<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><atom:link href="https://krymtkts.github.io/feed.xml" rel="self" type="application/rss+xml"></atom:link><title>krymtkts</title><description>krymtkts's personal blog</description><link>https://krymtkts.github.io</link><lastBuildDate>Fri, 17 Apr 2026 22:16:18 +0900</lastBuildDate><generator>blog-fable</generator><item><guid>https://krymtkts.github.io/posts/2026-04-12-powrshell-project-local-resource-management-part-6.html</guid><link>https://krymtkts.github.io/posts/2026-04-12-powrshell-project-local-resource-management-part-6.html</link><title>PowerShell Local Resource Manager Part 6 - pslrm-bump-action</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pslrm&quot; title=&quot;krymtkts/pslrm&quot;&gt;krymtkts/pslrm&lt;/a&gt; を使って lockfile を更新・ PR を作成する third-party action &lt;a href=&quot;https://github.com/krymtkts/pslrm-bump-action&quot; title=&quot;krymtkts/pslrm-bump-action&quot;&gt;krymtkts/pslrm-bump-action&lt;/a&gt; を作ってる。&lt;/p&gt;
&lt;p&gt;Marketplace 公開目的で GitHub Actions を作るのが始めてなので、知らないことが多く中々難航してる。
でもとりあえず repository を公開できる程度には出来上がってきた。 push したら早速 self smoke test がコケたが。
このあと tag を打って release 作って Marketplace に公開し、 tag base で使えるようにするのが 1 つの目標地点。&lt;/p&gt;
&lt;p&gt;初めて third-party action を作ったけど、自分の repository 用に書くのと随分違った。
JavaScript で書くやる気ないなと思い、 YAML ベースで &lt;a href=&quot;https://docs.github.com/en/actions/tutorials/create-actions/create-a-composite-action&quot; title=&quot;composite action&quot;&gt;composite action&lt;/a&gt; 的にしつつ、ややこしい場所を PowerShell script に逃している。
具体的には PowerShell と Windows PowerShell の差分吸収とかを PowerShell script に逃がした。
Windows PowerShell の &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/?view=powershellget-3.x&amp;viewFallbackFrom=powershellget-2.x&quot; title=&quot;PowerShellGet&quot;&gt;PowerShellGet&lt;/a&gt; しかないところに確実に &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/?view=powershellget-3.x&quot; title=&quot;PSResourceGet&quot;&gt;PSResourceGet&lt;/a&gt; を用意するとかが厄介なためだ。
&lt;a href=&quot;https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idstepsshell&quot; title=&quot;&lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps[*].shell&lt;/code&gt;&quot;&gt;&lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps[*].shell&lt;/code&gt;&lt;/a&gt; の値は、起動時点で決定されている必要がある様子。
そのため YAML 上でその 2 パターンを取り扱おうとすると冗長になる。
だから PowerShell script 内で handling した方が simple だった。&lt;/p&gt;
&lt;p&gt;ちなみに composite action の引数で受けた値を &lt;code&gt;shell&lt;/code&gt; に渡すなら問題ない。
だが third party action の場合は相対パスで composite action の YAML を探すところが信用できないみたい。
例えば current directory を third-party action を呼ぶまでに変えられてたりとかで、相対パスでは参照できない場合があるみたい？
まだこういったケースをわたし自身理解してないが、不確定要素をここで抱える意味もないなと思った。
なので気は進まなかったが PowerShell script で色々やることにした。&lt;/p&gt;
&lt;p&gt;利用者がどういう使い方をして、 action 側は決定論的に module 解決するためにどうすべきか。
PAT を使わないと commit と pull request で後続の GitHub Actions を起動できないからどう documentation するとか。
知らない事が多いだけに学びも多いが、中々難しいな。
GitHub Copilot に色々聞きながらやってるから進められるが、これは単独趣味プロでやってたらもっと時間がかかるだろうな。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pester.dev/&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; による unit testing と &lt;a href=&quot;https://github.com/nektos/act&quot; title=&quot;nektos/act&quot;&gt;nektos/act&lt;/a&gt; で integration testing してる。
けど最終的な疎通確認は、生の GitHub repository でやらないといけないのがハードル高いな。
生の repository 相手だと CI に組み込むのも flaky だし、手動テストという形なる。
まだそのためのテスト用 repository は作れてない。 action 公開勢はみんなテスト用 repo 作ってやってるのかな？謎。
テストの度に PR が作成されたり面倒そうだが、これしか方法はないのかな。
sandbox できなものがあればいいのだけど見つけられなかったので、実 repository でやる想定。&lt;/p&gt;
&lt;p&gt;それらが終わったら Marketplace に公開したいのだけど、公式文書には workflow が含まれたらだめとか書いてある。
&lt;a href=&quot;https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax&quot; title=&quot;Workflow syntax for GitHub Actions - GitHub Docs&quot;&gt;Workflow syntax for GitHub Actions - GitHub Docs&lt;/a&gt;
何故。&lt;/p&gt;
&lt;p&gt;でも &lt;a href=&quot;https://github.com/actions/checkout&quot; title=&quot;actions/checkout&quot;&gt;actions/checkout&lt;/a&gt; とか代表的な action 見る限り &lt;code&gt;.github/workflow&lt;/code&gt; が含まれてるし、はて？となっている。
他にも、なんか文脈的に tag 打ちで GitHub CLI で作成する release には Marketplace への publish ができなそうに見えるとか諸々心配点がある。
よくわからんがまずは SHA base で自前テストしてみてから考えるかー。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;随分気づくのが遅くなったが、 &lt;a href=&quot;https://github.com/krymtkts/pslrm-bump-action&quot; title=&quot;krymtkts/pslrm-bump-action&quot;&gt;krymtkts/pslrm-bump-action&lt;/a&gt; がおもくそ private のママだったので public にした。
まだ CI コケてるし、はよ直して test repo で試してみたいところ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Tue, 14 Apr 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-04-05-powrshell-project-local-resource-management-part-5.html</guid><link>https://krymtkts.github.io/posts/2026-04-05-powrshell-project-local-resource-management-part-5.html</link><title>PowerShell Local Resource Manager Part 5</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pslrm&quot; title=&quot;krymtkts/pslrm&quot;&gt;krymtkts/pslrm&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2026-03-29-powrshell-project-local-resource-management-part-4.html&quot; title=&quot;前回話していた&quot;&gt;前回話していた&lt;/a&gt; &lt;code&gt;Update-PSLResource&lt;/code&gt; を使った &lt;code&gt;psreq.lock.psd1&lt;/code&gt; の Bump workflow を直した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pslrm/blob/d9a96677d1690fb5b7465a992bbbd3f55772103a/.github/workflows/bump.yml&quot; title=&quot;pslrm/.github/workflows/bump.yml at d9a96677d1690fb5b7465a992bbbd3f55772103a · krymtkts/pslrm&quot;&gt;pslrm/.github/workflows/bump.yml at d9a96677d1690fb5b7465a992bbbd3f55772103a · krymtkts/pslrm&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Bump&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dependencies&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;on:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;schedule:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;cron:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;0 20 * * 5&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# Every Friday at 06:00 JST&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;workflow_dispatch:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;concurrency:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;group:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;bump-dependencies&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;cancel-in-progress:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; no permissions are needed.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;permissions:&lt;/span&gt; {}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;jobs:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;bump:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;runs-on:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;steps:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Checkout&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/checkout@v6&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;with:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;ref:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;main&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-comment&quot;&gt;# &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; to trigger the workflow on a push to the bump branch.&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;token:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${{&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secrets.PSLRM_BUMP_TOKEN&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;}}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Bump&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dependencies&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pwsh&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|&lt;br /&gt;          Set-PSResourceRepository PSGallery -Trusted&lt;br /&gt;          Import-Module ./pslrm.psd1 -Force&lt;br /&gt;          Update-PSLResource&lt;br /&gt;&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Detect&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;lockfile&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;changes&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;id:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;lockfile&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pwsh&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|&lt;br /&gt;          $diff = git status --porcelain -- psreq.lock.psd1&lt;br /&gt;          if ($diff) {&lt;br /&gt;            &amp;quot;changed=true&amp;quot; &amp;gt;&amp;gt; $env:GITHUB_OUTPUT&lt;br /&gt;            Write-Host &amp;quot;Lockfile changes detected.&amp;quot;&lt;br /&gt;          } else {&lt;br /&gt;            &amp;quot;changed=false&amp;quot; &amp;gt;&amp;gt; $env:GITHUB_OUTPUT&lt;br /&gt;            Write-Host &amp;quot;No lockfile changes detected.&amp;quot;&lt;br /&gt;          }&lt;br /&gt;&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Create&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pull&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;request&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;if:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;steps.lockfile.outputs.changed&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;true&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;env:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;GH_TOKEN:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${{&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secrets.PSLRM_BUMP_TOKEN&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;}}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pwsh&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|&lt;br /&gt;          git config user.name &amp;#x27;github-actions[bot]&amp;#x27;&lt;br /&gt;          git config user.email &amp;#x27;41898282+github-actions[bot]@users.noreply.github.com&amp;#x27;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;$branch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;chore/bump-pslrm-dependencies&amp;#x27;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--force-create&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$branch&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;psreq.lock.psd1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;$stagedLockfile&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--cached&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--name-only&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;psreq.lock.psd1&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;(-not&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$stagedLockfile)&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;No staged lockfile changes to commit.&amp;#x27;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;$title&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Bump pslrm dependencies.&amp;#x27;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;commit&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--message&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$title&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--force&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--set-upstream&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;origin&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$branch&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;$baseBranch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;main&amp;#x27;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;$prNumber&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gh&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pr&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--base&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$baseBranch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--head&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$branch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--state&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--json&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--jq&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;.[0].number&amp;#x27;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;($prNumber)&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Pull request #$prNumber already exists.&amp;quot;&lt;/span&gt;&lt;br /&gt;          } &lt;span class=&quot;hljs-string&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;$body&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Automated dependency bump generated by Update-PSLResource.&amp;#x27;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;gh&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pr&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--base&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$baseBranch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--head&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$branch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--title&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$title&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--body&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$body&lt;/span&gt;&lt;br /&gt;          }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#using-a-personal-access-token-on-the-command-line&quot; title=&quot;Managing your personal access tokens - GitHub Docs&quot;&gt;Managing your personal access tokens - GitHub Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;直に URL に PAT を指定する方法を始め使おうと思ったが、やめた。
どうも &lt;a href=&quot;https://github.com/actions/checkout&quot; title=&quot;&lt;code&gt;actions/checkout&lt;/code&gt;&quot;&gt;&lt;code&gt;actions/checkout&lt;/code&gt;&lt;/a&gt; で &lt;code&gt;token&lt;/code&gt; に PAT を渡せば PAT で認証された HTTPS remote を使うようだったのでそれを採用した。
その方が、見た目がスッキリしてよろしい。&lt;/p&gt;
&lt;p&gt;PAT には Content read/write と Pull Request read/write を設定するので、 workflow 自体の認証が要らなくなる。
指定の仕方がわからなかったが、これは公式文書上に書いてあった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#defining-access-for-the-github_token-scopes&quot; title=&quot;Defining access for the GITHUB_TOKEN scopes | Workflow syntax for GitHub Actions - GitHub Docs&quot;&gt;Defining access for the GITHUB_TOKEN scopes | Workflow syntax for GitHub Actions - GitHub Docs&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;permissions:&lt;/span&gt; {}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ちょっと見慣れない書き方だが、今回のケースはコレがハマるはず。&lt;/p&gt;
&lt;p&gt;コレをベースに pslrm の third-party actions を作り始めてみたが、この週末体調が優れずあんま進んでない。
休日を有効活用できず残念だが、一歩くらいは進んでるのでよしとする。
今回使った &lt;code&gt;actions/checkout&lt;/code&gt; の &lt;code&gt;token&lt;/code&gt; に PAT を渡す方法は、 third-party action の場合だと checkout を内包すべきでないだろうし、使わない想定。
少しずつ仕様を詰めていってはよ v0 の bump-pslrm-action として公開したいな(そして自分の repos で使うのだ)。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 05 Apr 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-03-29-powrshell-project-local-resource-management-part-4.html</guid><link>https://krymtkts.github.io/posts/2026-03-29-powrshell-project-local-resource-management-part-4.html</link><title>PowerShell Local Resource Manager Part 4</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pslrm&quot; title=&quot;krymtkts/pslrm&quot;&gt;krymtkts/pslrm&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Update-PSLResource&lt;/code&gt; を使えば、実行後に &lt;code&gt;psreq.lock.psd1&lt;/code&gt; の差分から依存関係の更新を検知できる。
それを使って Dependabot のような自動的な更新したくてそういう GitHub Actions workflow をこしらえた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pslrm/blob/d42f35ea69c63159ff5043106bbdfc4a1b5113d1/.github/workflows/bump.yml&quot; title=&quot;pslrm/.github/workflows/bump.yml at d42f35ea69c63159ff5043106bbdfc4a1b5113d1 · krymtkts/pslrm&quot;&gt;pslrm/.github/workflows/bump.yml at d42f35ea69c63159ff5043106bbdfc4a1b5113d1 · krymtkts/pslrm&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Bump&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dependencies&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;on:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;schedule:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;cron:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;0 20 * * 5&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# Every Friday at 06:00 JST&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;workflow_dispatch:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;concurrency:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;group:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;bump-dependencies&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;cancel-in-progress:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;permissions:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;contents:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;write&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;pull-requests:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;write&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;jobs:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;bump:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;runs-on:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;steps:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Checkout&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/checkout@v6&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;with:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;ref:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;main&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Restore&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;modules&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PSGallery&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pwsh&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|&lt;br /&gt;          Set-PSResourceRepository PSGallery -Trusted&lt;br /&gt;          Import-Module ./pslrm.psd1 -Force&lt;br /&gt;          Restore-PSLResource&lt;br /&gt;&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Bump&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dependencies&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pwsh&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|&lt;br /&gt;          Import-Module ./pslrm.psd1 -Force&lt;br /&gt;          Update-PSLResource&lt;br /&gt;&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Detect&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;lockfile&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;changes&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;id:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;lockfile&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pwsh&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|&lt;br /&gt;          $diff = git status --porcelain -- psreq.lock.psd1&lt;br /&gt;          if ($diff) {&lt;br /&gt;            &amp;quot;changed=true&amp;quot; &amp;gt;&amp;gt; $env:GITHUB_OUTPUT&lt;br /&gt;            Write-Host &amp;quot;Lockfile changes detected.&amp;quot;&lt;br /&gt;          } else {&lt;br /&gt;            &amp;quot;changed=false&amp;quot; &amp;gt;&amp;gt; $env:GITHUB_OUTPUT&lt;br /&gt;            Write-Host &amp;quot;No lockfile changes detected.&amp;quot;&lt;br /&gt;          }&lt;br /&gt;&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Create&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pull&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;request&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;if:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;steps.lockfile.outputs.changed&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;true&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;env:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;GH_TOKEN:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${{&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;github.token&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;}}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pwsh&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|&lt;br /&gt;          git config user.name &amp;#x27;github-actions[bot]&amp;#x27;&lt;br /&gt;          git config user.email &amp;#x27;41898282+github-actions[bot]@users.noreply.github.com&amp;#x27;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;$branch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;chore/bump-pslrm-dependencies&amp;#x27;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--force-create&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$branch&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;psreq.lock.psd1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;$stagedLockfile&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--cached&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--name-only&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;psreq.lock.psd1&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;(-not&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$stagedLockfile)&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;No staged lockfile changes to commit.&amp;#x27;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;$title&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Bump pslrm dependencies.&amp;#x27;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;commit&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--message&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$title&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--force&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--set-upstream&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;origin&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$branch&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;$baseBranch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;main&amp;#x27;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;$prNumber&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gh&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pr&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--base&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$baseBranch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--head&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$branch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--state&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--json&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--jq&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;.[0].number&amp;#x27;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-string&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;($prNumber)&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Pull request #$prNumber already exists.&amp;quot;&lt;/span&gt;&lt;br /&gt;          } &lt;span class=&quot;hljs-string&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;$body&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Automated dependency bump generated by Update-PSLResource.&amp;#x27;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;gh&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pr&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--base&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$baseBranch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--head&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$branch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--title&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$title&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;--body&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$body&lt;/span&gt;&lt;br /&gt;          }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;つい昨日いい感じに動き PR &lt;a href=&quot;https://github.com/krymtkts/pslrm/pull/1&quot; title=&quot;#1&quot;&gt;#1&lt;/a&gt; は作成されたのだが、運用してみてちょっとした問題があるとわかった。
単純な話だが GitHub Actions の仕様で bot が作った PR に対して CI の GitHub Actions workflow が起動しないというものだ。
&lt;a href=&quot;https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request&quot; title=&quot;&lt;code&gt;pull_request&lt;/code&gt;&quot;&gt;&lt;code&gt;pull_request&lt;/code&gt;&lt;/a&gt; の節には書いてないようだが &lt;a href=&quot;https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#check_run&quot; title=&quot;&lt;code&gt;check_run&lt;/code&gt;&quot;&gt;&lt;code&gt;check_run&lt;/code&gt;&lt;/a&gt; &lt;a href=&quot;https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#check_suite&quot; title=&quot;&lt;code&gt;check_suite&lt;/code&gt;&quot;&gt;&lt;code&gt;check_suite&lt;/code&gt;&lt;/a&gt; には書いてある様子。&lt;/p&gt;
&lt;p&gt;CI が &lt;code&gt;pull_request&lt;/code&gt; じゃなく &lt;a href=&quot;https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target&quot; title=&quot;&lt;code&gt;pull_request_target&lt;/code&gt;&quot;&gt;&lt;code&gt;pull_request_target&lt;/code&gt;&lt;/a&gt; を使っていれば起動できるが、そこは本質じゃない。
あるべき像としては pslrm の GitHub Actions workflow 側で GitHub CLI の &lt;code&gt;GH_TOKEN&lt;/code&gt; に権限を持った &lt;a href=&quot;https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens&quot; title=&quot;PAT&quot;&gt;PAT&lt;/a&gt; を使うのがいいっぽい。
GitHub App を使う手もあるが、その方式が一番一般的ぽい。
次のステップとしては &lt;a href=&quot;https://www.powershellgallery.com/&quot; title=&quot;PowerShell Gallery&quot;&gt;PowerShell Gallery&lt;/a&gt; に公開している pslrm を使う third-party Action を作りたく、その場合も PAT がいいみたい。
なのでその方向でも調整していこうと思っているが、リアルで旅の途中なので着手はできてない。&lt;/p&gt;
&lt;p&gt;他にも PR のために作成する branch name が固定だったり、 description が簡素過ぎたりもある。
Dependabot ぽくするなら label もつけたいしな。
その辺りも含めて機能を揃えられたら、 third-party Action として良さげかなと考えている。
如何せん third-party Action を作ったことがないから、手探りで進めていく予定。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 29 Mar 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-03-22-powrshell-project-local-resource-management-part-3.html</guid><link>https://krymtkts.github.io/posts/2026-03-22-powrshell-project-local-resource-management-part-3.html</link><title>PowerShell Local Resource Manager Part 3 - pslrm 0.0.1-alpha</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pslrm&quot; title=&quot;krymtkts/pslrm&quot;&gt;krymtkts/pslrm&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/pslrm/0.0.1-alpha&quot; title=&quot;0.0.1-alpha&quot;&gt;0.0.1-alpha&lt;/a&gt; として PowerShell Gallery に公開した。
まだ使い勝手はかなり悪いが、最低限の版として一度公開しておきたかった。
コレまでの機能実装からは特に機能的な拡充をしてなくて、専らに CI/CD を中心に整備した。
release したかったのは、この CI/CD 周りの最後の動作確認をしたかったからでもある(そして build script の不具合が見つかり目論見通り動作確認の意味があった)。&lt;/p&gt;
&lt;p&gt;pull request 時や push 時の CI は元々作ってあった。
これに加えて release note 更新、 &lt;a href=&quot;https://www.powershellgallery.com/&quot; title=&quot;PowerShell Gallery&quot;&gt;PowerShell Gallery&lt;/a&gt; への公開と &lt;a href=&quot;https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository&quot; title=&quot;GitHub の Release&quot;&gt;GitHub の Release&lt;/a&gt; 作成の流れを GitHub Actions に起こした感じ。
特に release note に関しては、 PowerShell Gallery の事例を見つつなるべくマシな形になるよううまく整理したんじゃないかなと。&lt;/p&gt;
&lt;p&gt;これまで自分で作ってきた PowerShell module は管理がてきとーだったので release note を作ってこなかった。
今回からは真面目にやろうと考えて、 PowerShell の &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/developer/module/how-to-write-a-powershell-module-manifest?view=powershell-7.6&quot; title=&quot;module manifest&quot;&gt;module manifest&lt;/a&gt; に含まれる &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/developer/module/how-to-write-a-powershell-module-manifest?view=powershell-7.6#module-manifest-elements&quot; title=&quot;&lt;code&gt;ReleaseNotes&lt;/code&gt;&quot;&gt;&lt;code&gt;ReleaseNotes&lt;/code&gt;&lt;/a&gt; の更新なんかも真面目に検討した。
ここでいう release note は changelog の一部であると考えてもらいたい。
PowerShell module には release note の属性が用意されているが、そこに何を書くかは明確に定義されていない。&lt;/p&gt;
&lt;p&gt;わたしの知る限り、 PowerShell Gallery に公開されてる module では大体以下のパターンが存在する。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;release note への外部リンク(URL 文字列)&lt;/li&gt;&lt;li&gt;累積の release note&lt;/li&gt;&lt;li&gt;何もなし&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;1 は、大体 GitHub の release とか changelog のファイルへの外部リンクが多い。
中には全然関係ない URL もあったりするようだ。
この場合 PowerShell Gallery に表示されたら、リンクになっている。
&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/get-module?view=powershell-7.6&quot; title=&quot;&lt;code&gt;Get-Module&lt;/code&gt;&quot;&gt;&lt;code&gt;Get-Module&lt;/code&gt;&lt;/a&gt; や &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/get-installedpsresource?view=powershellget-3.x&quot; title=&quot;&lt;code&gt;Get-InstalledPSResource&lt;/code&gt;&quot;&gt;&lt;code&gt;Get-InstalledPSResource&lt;/code&gt;&lt;/a&gt; で得た &lt;code&gt;ReleaseNotes&lt;/code&gt; はただの URL 文字列だ。
代表例は &lt;a href=&quot;https://www.powershellgallery.com/packages/Pester/5.1.0&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; なんかがそう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt; Get-InstalledPSResource -Name pester -Scope AllUsers | % ReleaseNotes&lt;br /&gt;https://github.com/pester/Pester/releases/tag/6.0.0-alpha5
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;module manifest の &lt;code&gt;ReleaseNotes&lt;/code&gt; の更新も URL 文字列をブチ込むだけなので簡単。
だからこれは運用最適化のパターンで、利用者としてはその場で確認できないという意味でちょっと味気ないなと感じている。&lt;/p&gt;
&lt;p&gt;2 はちょっとややこしい。
始まった頃からの累積 release note と、 major や minor 毎の累積 release note がありそう。
開発者は &lt;code&gt;ReleaseNotes&lt;/code&gt; を自動生成・更新するなり手で更新する必要がある。
また module manifest が肥大化する恐れがある(サイズ制限の有無は不明)。
運用の負荷が一番高いが、利用者は URL をたどる必要がないので情報を得やすい。
パッと見、 &lt;a href=&quot;https://www.powershellgallery.com/packages/PowerShellGet/2.2.5&quot; title=&quot;PSResourceGet&quot;&gt;PSResourceGet&lt;/a&gt; はこの minor version 毎の累積 release note っぽい。
pull request を見るに module manifest は手で更新してるのかな～と思ってる。
そのためか、ファイルが肥大化しないように &lt;a href=&quot;https://github.com/PowerShell/PSResourceGet/tree/9c8bd26a63dad0f79448c8620870c730ccd8169e/CHANGELOG&quot; title=&quot;changelog を version で分割してる&quot;&gt;changelog を version で分割してる&lt;/a&gt;みたい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt; Get-InstalledPSResource -Name *PSResourceGet -Scope AllUsers -Version 1.2.0-rc3 | % ReleaseNotes&lt;br /&gt;## 1.2.0-rc3&lt;br /&gt;&lt;br /&gt;## Bug fix&lt;br /&gt;- Packages that depend on a specific version should search for the dependency with NormalizedVersion (#1941)&lt;br /&gt;&lt;br /&gt;## 1.2.0-rc2&lt;br /&gt;&lt;br /&gt;## Bug fix&lt;br /&gt;- For packages with dependency on a specific version use specific version instead of version range (#1937)&lt;br /&gt;&lt;br /&gt;... 略
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;3 は simple だ。何もなし。
開発者は &lt;code&gt;ReleaseNotes&lt;/code&gt; には何もしなくて良い。
利用者は &lt;code&gt;ProjectUri&lt;/code&gt; から自力でたどり着く必要がある。
開発者は楽だが利用者に対して親切ではないかなと考えている運用。
代表例は &lt;a href=&quot;https://www.powershellgallery.com/packages/PSScriptAnalyzer/1.24.0&quot; title=&quot;PSScriptAnalyzer&quot;&gt;PSScriptAnalyzer&lt;/a&gt;
また、利用者が &lt;code&gt;ProjectUri&lt;/code&gt; を辿ってもそこに release note が存在する保証はない。
わたしのこれまでの module はこれにあたる。&lt;/p&gt;
&lt;p&gt;PowerShell module の release note 事情はこのように現時点での正解はないと思っている。
であれば自分で考える正解を突き進むのが良かろうと思った。
個人的には release note はあった方が良い。また運用負荷は下げたくて手作業はやりたくない。
module manifest の肥大化も避けたい。
というわけで以下のルールとした。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CHANGELOG.md&lt;/code&gt; を source of truth にする&lt;/li&gt;&lt;li&gt;直近 3 release 分の release note を module manifest の &lt;code&gt;ReleaseNotes&lt;/code&gt; に含める&lt;/li&gt;&lt;li&gt;以降は省略し &lt;code&gt;ReleaseNotes&lt;/code&gt; 最下部に full release note である &lt;code&gt;CHANGELOG.md&lt;/code&gt; への URL を記載する&lt;/li&gt;&lt;li&gt;GitHub Release には release 対象 version の release note を記載する(当たり前)&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;情報を示しつつ完全版への道筋も示す 1 と 2 の複合版が多分いま一番マシなんじゃないかなと考えた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CHANGELOG.md&lt;/code&gt; は &lt;a href=&quot;https://keepachangelog.com/en/1.1.0/&quot; title=&quot;Keep a Changelog&quot;&gt;Keep a Changelog&lt;/a&gt; を参考にしつつ、情報の付加や自動化に有利な独自のルールを付加している。
具体的に言うと &lt;code&gt;Notes&lt;/code&gt; で release ごとの付加情報を添えたのと、自動化を簡単にするため footer の区切りとして &lt;code&gt;---&lt;/code&gt; を入れたところ。
ほかは Keep a Changelog に倣っている。&lt;/p&gt;
&lt;p&gt;今どきは conventional commit が多いが、個人的に好きではないので使ってないのもあり、利用者向けの情報となる release note は人間がまとめる方針とした。
&lt;code&gt;CHANGELOG.md&lt;/code&gt; を source of truth にして &lt;code&gt;ReleaseNotes&lt;/code&gt; と GitHub Release への反映を自動化した task を用意している。&lt;/p&gt;
&lt;p&gt;0.0.1-alpha の場合以下のようになった。多分そんなに変なことにはなってないはず。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt; Get-InstalledPSResource -Name pslrm -Scope AllUsers | % ReleaseNotes&lt;br /&gt;## [0.0.1-alpha]&lt;br /&gt;&lt;br /&gt;### Added&lt;br /&gt;&lt;br /&gt;- Add project-local PowerShell resource management based on PSResourceGet.&lt;br /&gt;- Add requirements and lockfile workflows with `Install-PSLResource` and `Update-PSLResource`.&lt;br /&gt;- Add lockfile restore and removal workflows with `Restore-PSLResource` and `Uninstall-PSLResource`.&lt;br /&gt;- Add `Get-InstalledPSLResource` for reading installed project resources from the lockfile.&lt;br /&gt;- Add `Invoke-PSLResource` for running commands from project-local resources in an isolated runspace.&lt;br /&gt;- Add build, lint, unit test, and integration test tasks through `Invoke-Build`.&lt;br /&gt;&lt;br /&gt;### Notes&lt;br /&gt;&lt;br /&gt;- This is the initial alpha release track for `pslrm`.&lt;br /&gt;- Supported PowerShell versions are Windows PowerShell 5.1 through PowerShell 7.x.&lt;br /&gt;- Supported repository is PowerShell Gallery.&lt;br /&gt;- `Invoke-PSLResource` uses `IsolatedRunspace` execution. `InProcess` execution is not implemented.&lt;br /&gt;&lt;br /&gt;Full CHANGELOG: https://github.com/krymtkts/pslrm/blob/main/CHANGELOG.md
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;準備には手間がかかったが、コレによって PowerShell Gallery や module 自体に理解しやすい release note を提供できる。
また &lt;code&gt;CHANGELOG.md&lt;/code&gt; 自体への導線も保ちつつ、自動化で付加も低減できた。
個人開発で release note をするのは今回が初めてなので、真面目に検討した価値があったんじゃないかな。
当面この感じで使ってみて問題点現れないかやってみるつもり。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 22 Mar 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-03-15-powrshell-project-local-resource-management-part-2.html</guid><link>https://krymtkts.github.io/posts/2026-03-15-powrshell-project-local-resource-management-part-2.html</link><title>PowerShell Local Resource Manager Part 2</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pslrm&quot; title=&quot;krymtkts/pslrm&quot;&gt;krymtkts/pslrm&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;これまでは、 &lt;a href=&quot;https://pester.dev/&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; のように設定が独自 object だと型の解決に問題があるので、 pslrm では実行できなかった。
&lt;a href=&quot;https://github.com/nightroman/Invoke-Build&quot; title=&quot;Invoke-Build&quot;&gt;Invoke-Build&lt;/a&gt; のような task runner 経由であればそういうことができるようにした。
この対応、個人的にかなり難しく GitHub Copilot の導く方向もちょいちょい間違ってたので、要所要所手作りの温もりで調整したつもり。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pslrm/compare/3a999c942ee37eb8ade8516d16978f60a9e66b82...3f63fe6b742c88e5eba7d013cb89a318850e211d&quot; title=&quot;このへんのコミット&quot;&gt;このへんのコミット&lt;/a&gt;がそうなんだが、入れ子で呼び出される場合に Host の取り扱いが良くなかったみたい。
&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-host&quot; title=&quot;&lt;code&gt;Write-Host&lt;/code&gt;&quot;&gt;&lt;code&gt;Write-Host&lt;/code&gt;&lt;/a&gt; が実行されたら null reference で落ちてしまってた。
GitHub Copilot は独自 Host 実装を作ればいいと言ってたが、んなあほな...ということで階層が深い場合は一番上の Host が使われるように調整して、いけるようになった。&lt;/p&gt;
&lt;p&gt;GitHub Actions 上に CI も整備して cross platform のテストを回してみた。
Windows &amp;amp; PowerShell は問題なし。
Windows PowerShell の方は互換性を維持して置き換えたら動くようになった。
Ubuntu &amp;amp; PowerShell の方は成功するけどたまに Host 周りが失敗してるから、 flaky ぽい。
local で &lt;a href=&quot;https://github.com/nektos/act&quot; title=&quot;nektos/act&quot;&gt;nektos/act&lt;/a&gt; で動かした限りは Ubuntu でも問題なく動いてそうなんやが。
macOS はまだ成功してるところを見たことないが、どうだろう。
このテストは GitHub Copilot サンに書いてもらってるので理解浅いから、後追いで理解していかんと。
特に、今回は背視したような入れ子の Host 問題みたいなケースで本質を追うのは GitHub Copilot サンには難しいから、自力でしか解決できんしな。&lt;/p&gt;
&lt;p&gt;まだ結構イマイチな箇所が多いけど、 pslrm の開発で使うレベルでは徐々に &lt;a href=&quot;https://pester.dev/&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt;, &lt;a href=&quot;https://github.com/PowerShell/PSScriptAnalyzer&quot; title=&quot;PSScriptAnalyzer&quot;&gt;PSScriptAnalyzer&lt;/a&gt;, Invoke-Build の実行はできるようになった。&lt;/p&gt;
&lt;p&gt;例えば &lt;a href=&quot;https://pester.dev/docs/v6/quick-start&quot; title=&quot;Pester v6&quot;&gt;Pester v6&lt;/a&gt; のように独自提供の型を使って設定を組み上げるようなケースは、煩雑だが以下のようにできる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-PSLResource&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-Pester&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Arguments&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;-Configuration&amp;#x27;&lt;/span&gt;, (&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-PSLResource&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;New-PesterConfiguration&lt;/span&gt;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSResourceGet&quot; title=&quot;PSResourceGet&quot;&gt;PSResourceGet&lt;/a&gt; しか入ってない Windows PowerShell でも動いてるので多分うまくいってるんじゃないかな。
さらにいいところは以下。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pslrm/blob/0eb5c4d62508c80f6704feb404e69c61d56cc508/.github/actions/restore-and-test/action.yml#L22-L27&quot; title=&quot;pslrm/.github/actions/restore-and-test/action.yml at 0eb5c4d62508c80f6704feb404e69c61d56cc508 · krymtkts/pslrm&quot;&gt;pslrm/.github/actions/restore-and-test/action.yml at 0eb5c4d62508c80f6704feb404e69c61d56cc508 · krymtkts/pslrm&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Restore&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;modules&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PSGallery&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${{&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;inputs.shell&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;}}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|&lt;br /&gt;    Set-PSResourceRepository PSGallery -Trusted&lt;br /&gt;    Import-Module ./pslrm.psd1 -Force&lt;br /&gt;    Restore-PSLResource&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こんな風に依存関係の restore が &lt;code&gt;Restore-PSLResource&lt;/code&gt; 一発で済んで simple になってるのでとてもいいなと思ってる。
もうちょっといい感じになったら &lt;a href=&quot;https://www.powershellgallery.com/&quot; title=&quot;PowerShell Gallery&quot;&gt;PowerShell Gallery&lt;/a&gt; へ publish しよう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 15 Mar 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-03-08-powrshell-project-local-resource-management-part-1.html</guid><link>https://krymtkts.github.io/posts/2026-03-08-powrshell-project-local-resource-management-part-1.html</link><title>PowerShell Local Resource Manager Part 1</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2026-03-01-fsharp-powrshell-module-template-part-4.html&quot; title=&quot;前回触れた&quot;&gt;前回触れた&lt;/a&gt; PowerShell の project-local な依存管理を提供する薄い wrapper module を作り始めた。
仮に名前は PowerShell Local Resource Manager ということで pslrm としている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pslrm&quot; title=&quot;krymtkts/pslrm&quot;&gt;krymtkts/pslrm&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;まだ未完成だが、 project- local で動かせるんだなといのがわかったので、ひとまず repository 公開した。
でもまだ &lt;a href=&quot;https://www.powershellgallery.com/&quot; title=&quot;PowerShell Gallery&quot;&gt;PowerShell Gallery&lt;/a&gt; に公開するには使えなさ過ぎるので、やってない。&lt;/p&gt;
&lt;p&gt;読みは acronym なので &amp;quot;P-S-L-R-M&amp;quot; でもいいし、親しみを込めて &amp;quot;ps-lurm&amp;quot;(&amp;quot;Pee Slurm&amp;quot;) と疑似的に読んでもいい。
AI 曰く、擬似的に読むなら &amp;quot;ps-lrm&amp;quot; -&amp;gt; &amp;quot;Pee Slurm&amp;quot; が自然な読み方で、日本語的に「ピーエスラーム」とはならんそうだ。&lt;/p&gt;
&lt;p&gt;pslrm では &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/?view=powershellget-3.x&quot; title=&quot;PSResourceGet&quot;&gt;PSResourceGet&lt;/a&gt; に PowerShell からの取得や依存関係の解決を任せている。
だから pslrm がやる仕事は少ない。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;project-local を指定して &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/save-psresource?view=powershellget-3.x&quot; title=&quot;&lt;code&gt;Save-PSResource&lt;/code&gt;&quot;&gt;&lt;code&gt;Save-PSResource&lt;/code&gt;&lt;/a&gt; すること。&lt;/li&gt;&lt;li&gt;project-local な module を global 汚染せず別 session で動かすこと。&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;しかしこれだけでもまだできない機能があるくらいなので、随分と面倒だ。
特に「project-local な module を別 session」のは process か runspace を分けることになる。
今のところ pslrm 0.0.1 では runspace を分けるだけにしている。 process を分けると起動が流石に遅いかと考えた。
現状でもかなり遅いのだが、 runspace を分けて最低限 project-local な resource を動かせるところまでは確認できた。&lt;/p&gt;
&lt;p&gt;以下は &lt;a href=&quot;https://github.com/PowerShell/PSScriptAnalyzer&quot; title=&quot;PSScriptAnalyzer&quot;&gt;PSScriptAnalyzer&lt;/a&gt; を動かしてみた例だ。呼び出しが極めて面倒だが、動くのは動く。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt; Import-Module .\pslrm.psd1 -Force&lt;br /&gt;&amp;gt; get-command -Module pslrm&lt;br /&gt;&lt;br /&gt;CommandType     Name                                               Version    Source&lt;br /&gt;-----------     ----                                               -------    ------&lt;br /&gt;Function        Get-InstalledPSLResource                           0.0.1      pslrm&lt;br /&gt;Function        Install-PSLResource                                0.0.1      pslrm&lt;br /&gt;Function        Invoke-PSLResource                                 0.0.1      pslrm&lt;br /&gt;Function        Restore-PSLResource                                0.0.1      pslrm&lt;br /&gt;Function        Uninstall-PSLResource                              0.0.1      pslrm&lt;br /&gt;Function        Update-PSLResource                                 0.0.1      pslrm&lt;br /&gt;&lt;br /&gt;&amp;gt; cat .\psreq.psd1&lt;br /&gt;@{&lt;br /&gt;    Pester = @{&lt;br /&gt;        Repository = &amp;#x27;PSGallery&amp;#x27;&lt;br /&gt;        Prerelease = $true&lt;br /&gt;    }&lt;br /&gt;    PSScriptAnalyzer = @{&lt;br /&gt;        Repository = &amp;#x27;PSGallery&amp;#x27;&lt;br /&gt;        Prerelease = $true&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&amp;gt; Install-PSLResource -Path . -Confirm:$false&lt;br /&gt;&lt;br /&gt;Name        : PSScriptAnalyzer&lt;br /&gt;Version     : 1.24.0&lt;br /&gt;Repository  : PSGallery&lt;br /&gt;IsDirect    : True&lt;br /&gt;ProjectRoot : C:\Users\takatoshi\dev\krymtkts.github.com\krymtkts\pslrm&lt;br /&gt;&lt;br /&gt;Name        : Pester&lt;br /&gt;Version     : 6.0.0-alpha5&lt;br /&gt;Repository  : PSGallery&lt;br /&gt;IsDirect    : True&lt;br /&gt;ProjectRoot : C:\Users\takatoshi\dev\krymtkts.github.com\krymtkts\pslrm&lt;br /&gt;&lt;br /&gt;&amp;gt; Get-InstalledPSLResource -Path . -IncludeDependencies&lt;br /&gt;&lt;br /&gt;Name        : PSScriptAnalyzer&lt;br /&gt;Version     : 1.24.0&lt;br /&gt;Repository  : PSGallery&lt;br /&gt;IsDirect    : True&lt;br /&gt;ProjectRoot : C:\Users\takatoshi\dev\krymtkts.github.com\krymtkts\pslrm&lt;br /&gt;&lt;br /&gt;Name        : Pester&lt;br /&gt;Version     : 6.0.0-alpha5&lt;br /&gt;Repository  : PSGallery&lt;br /&gt;IsDirect    : True&lt;br /&gt;ProjectRoot : C:\Users\takatoshi\dev\krymtkts.github.com\krymtkts\pslrm&lt;br /&gt;&lt;br /&gt;&amp;gt; Invoke-PSLResource -Path . -CommandName Invoke-ScriptAnalyzer -Arguments @(&amp;#x27;-Path&amp;#x27;, &amp;#x27;.\src&amp;#x27;, &amp;#x27;-Recurse&amp;#x27;)&lt;br /&gt;&lt;br /&gt;RuleName : PSUseShouldProcessForStateChangingFunctions&lt;br /&gt;Severity : Warning&lt;br /&gt;Line     :&lt;br /&gt;Column   :&lt;br /&gt;Message  : Function &amp;#x27;New-PSLRMResourceObject&amp;#x27; has verb that could change system state. Therefore, the&lt;br /&gt;           function has to support &amp;#x27;ShouldProcess&amp;#x27;.&lt;br /&gt;&lt;br /&gt;RuleName : PSUseShouldProcessForStateChangingFunctions&lt;br /&gt;Severity : Warning&lt;br /&gt;Line     :&lt;br /&gt;Column   :&lt;br /&gt;Message  : Function &amp;#x27;New-Resource&amp;#x27; has verb that could change system state. Therefore, the function has&lt;br /&gt;           to support &amp;#x27;ShouldProcess&amp;#x27;.&lt;br /&gt;&lt;br /&gt;RuleName : PSUseSingularNouns&lt;br /&gt;Severity : Warning&lt;br /&gt;Line     :&lt;br /&gt;Column   :&lt;br /&gt;Message  : The cmdlet &amp;#x27;Get-LockfileResourceNames&amp;#x27; uses a plural noun. A singular noun should be used&lt;br /&gt;           instead.&lt;br /&gt;&lt;br /&gt;RuleName : PSUseSingularNouns&lt;br /&gt;Severity : Warning&lt;br /&gt;Line     :&lt;br /&gt;Column   :&lt;br /&gt;Message  : The cmdlet &amp;#x27;ConvertTo-PSLResourceInvocationArguments&amp;#x27; uses a plural noun. A singular noun&lt;br /&gt;           should be used instead.&lt;br /&gt;&lt;br /&gt;RuleName : PSUseOutputTypeCorrectly&lt;br /&gt;Severity : Information&lt;br /&gt;Line     :&lt;br /&gt;Column   :&lt;br /&gt;Message  : The cmdlet &amp;#x27;Uninstall-PSLResource&amp;#x27; returns an object of type &amp;#x27;System.Object[]&amp;#x27; but this type&lt;br /&gt;           is not declared in the OutputType attribute.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コードも不格好でかなり遅いが、今はとりあえず project-local な依存関係の管理ができるというのがわかった。
この後本当に使いやすさであるとか例外的に支えない PowerShell module があるかとかを検証していく必要がある。
でも GitHub Actions 等での CI で個別に module を install することなく local と同じ version を使えるというのは、いいんじゃないかな。
PowerShell でも deterministic な module 管理をしたかったので気に入っている。&lt;/p&gt;
&lt;p&gt;F# の PowerShell module template 作成からは寄り道しているが、当面 pslrm の機能を拡充していくつもり。
&lt;a href=&quot;https://pester.dev/&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; のように設定が独自 object だと型の解決に問題があるので、それは cmdlet 直の実行でなく script を実行できるようにしたい。
template で依存する PowerShell module 管理を簡単にするため pslrm のアイデアが生まれたので、どん詰まりまではやってみてもよかろう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 08 Mar 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-03-01-fsharp-powrshell-module-template-part-4.html</guid><link>https://krymtkts.github.io/posts/2026-03-01-fsharp-powrshell-module-template-part-4.html</link><title>F# の PowerShell Module の Template を作りたい Part 4 - PowerShell の project-base なモジュール管理</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/FsPowerShellTemplate&quot; title=&quot;krymtkts/FsPowerShellTemplate&quot;&gt;krymtkts/FsPowerShellTemplate&lt;/a&gt; の開発をした。
task runner の task を拡充をした。 unit/end-to-end testing, documentation, PowerShell Gallery への publish 等。
あと coverage も足しておきたいなと考えてるが、まだ着手できていない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/testing/microsoft-testing-platform-intro?tabs=dotnetcli&quot; title=&quot;Microsoft.Testing.Platform&quot;&gt;Microsoft.Testing.Platform&lt;/a&gt; に対応した &lt;a href=&quot;https://github.com/coverlet-coverage/coverlet&quot; title=&quot;Coverlet&quot;&gt;Coverlet&lt;/a&gt; ができたのでそれを使おうと考えてる。
けど、他の v8 系は出ているけど MTP 版だけ NuGet に公開する権限の問題でまだ出てないらしい。以下の issue にそれが書かれている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/coverlet-coverage/coverlet/issues/1816#issuecomment-3903692885&quot; title=&quot;NuGet &amp;quot;coverlet.MTP&amp;quot; package does not exist? · Issue #1816 · coverlet-coverage/coverlet&quot;&gt;NuGet &amp;quot;coverlet.MTP&amp;quot; package does not exist? · Issue #1816 · coverlet-coverage/coverlet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上記以外は概ね揃えたつもりなのだけど、最後に PowerShell Module のモジュール管理を project-local でできないことが気になっている。
&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/?view=powershellget-3.x&quot; title=&quot;PSResourceGet&quot;&gt;PSResourceGet&lt;/a&gt; だと project local に依存関係を管理する仕組みがないはず。
module の install は、 machine local か current user local が対象になる。
これは開発環境では project 毎に複数の module version があると支障がある。
&lt;code&gt;$PSModulePath&lt;/code&gt; を指定していても machine や user の module を拾ってしう。
(container で分けろという世界観なのかも知れないが)&lt;/p&gt;
&lt;p&gt;今できる方法としては、わたしが作ってる他の PowerShell Module 同様に、 version を指定せずに使う。
あるいは、愚直に script を書いて利用 version の固定をやればいいの。
だが汎用性に欠けるし、そもそも開発環境でも CI でも同じ方法で管理できるのが一番うれしい。
要は lockfile base で PowerShell Module を restore できるようなのが欲しい。&lt;/p&gt;
&lt;p&gt;PowerShell のモジュール依存関係の管理として、昔から &lt;a href=&quot;https://github.com/RamblingCookieMonster/PSDepend&quot; title=&quot;PSDepend&quot;&gt;PSDepend&lt;/a&gt; がある。
長らく開発停止してるみたい。
わたしは使ったことがないが、見た感じでは lockfile がなくようなので求める機能がなさそう。
仮に動いても、見たところ PowerShell Gallery 以外の source にも対応しているから結構多機能なのでこんなに重厚なやつが欲しいのではないかなという感じ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/install-psresource?view=powershellget-3.x&quot; title=&quot;&lt;code&gt;Install-PSResource&lt;/code&gt;&quot;&gt;&lt;code&gt;Install-PSResource&lt;/code&gt;&lt;/a&gt; には &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/install-psresource?view=powershellget-3.x#-requiredresourcefile&quot; title=&quot;&lt;code&gt;-RequiredResourceFile&lt;/code&gt;&quot;&gt;&lt;code&gt;-RequiredResourceFile&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/install-psresource?view=powershellget-3.x#-requiredresource&quot; title=&quot;&lt;code&gt;-RequiredResource&lt;/code&gt;&quot;&gt;&lt;code&gt;-RequiredResource&lt;/code&gt;&lt;/a&gt; という option がある。
この option を使えば、 &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_data_files?view=powershell-7.5&quot; title=&quot;&lt;code&gt;psd1&lt;/code&gt;&quot;&gt;&lt;code&gt;psd1&lt;/code&gt;&lt;/a&gt; ファイルに exact version を記入することで擬似的に lockfile として使えそう。
でも install で自動生成されないし、先に上げた user と machine の汚染は防げないから、隔離環境でしか使えない。
なら &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/save-psresource?view=powershellget-3.x&quot; title=&quot;&lt;code&gt;Save-PSResource&lt;/code&gt;&quot;&gt;&lt;code&gt;Save-PSResource&lt;/code&gt;&lt;/a&gt; が requirements-base で動かせたらいいのだけど、残念ながらできない。&lt;/p&gt;
&lt;p&gt;ないのであればということで、いま PSResourceGet をベースとして、上記の project-local な依存管理を提供する薄い wrapper module を試作している。
仮に名前は PowerShell Local Resource Manager ということで pslrm としている。
今の時代は略語が多すぎて何を考えても重複するリスクがあって、これも名前が衝突してるが、仕方ない。
今はまだ実感として使える感じがなくて、わたしには珍しく private repository にして開発してる。歴史直したりするしな。
pslrm が多少愚直でも求める機能を提供できるようになったら、 template に組み込んで使うつもり。&lt;/p&gt;
&lt;p&gt;将来的に PSResourceGet がその機能を持つこともあるかも知れないが、今はないので多分価値があるねんよな。
PSResourceGet で machine や user から分離した module management ができるようになったら、薄い wrapper module は要らなくなるはず。
付け焼き刃の出番をなくすためにも、本体の進化を期待するばかり。&lt;/p&gt;
&lt;p&gt;当面は pslrm 試作に時間を割くので、 template の方は手を付けないつもり。
その間に MTP 版の Coverlet が NuGet に登録されたらいいなという淡い期待。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 01 Mar 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-02-23-enable-windows-dev-drive.html</guid><link>https://krymtkts.github.io/posts/2026-02-23-enable-windows-dev-drive.html</link><title>Windows の Dev Drive を有効にする</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;storage 貧者だったので使ってなかったが、 laptop 変えて増えたので Dev Drive を設定してみた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/dev-drive/&quot; title=&quot;Set up a Dev Drive on Windows 11 | Microsoft Learn&quot;&gt;Set up a Dev Drive on Windows 11 | Microsoft Learn&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;よくわかってないが Dev Drive は ReFS を採用している。 &lt;a href=&quot;https://learn.microsoft.com/en-us/windows-server/storage/refs/refs-overview&quot; title=&quot;Resilient File System (ReFS) overview | Microsoft Learn&quot;&gt;Resilient File System (ReFS) overview | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;Dev Drive のところにも載ってるが、 NuGet の cache などの directory について&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/nuget/consume-packages/managing-the-global-packages-and-cache-folders&quot; title=&quot;How to manage the global packages, HTTP cache, temp folders in NuGet | Microsoft Learn&quot;&gt;How to manage the global packages, HTTP cache, temp folders in NuGet | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Windows の UI から設定する。サイズは 256 GB にした。&lt;/p&gt;
&lt;p&gt;Dev Drive の文書の NuGet の箇所をもとに cache などを Dev Drive に設定する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt; dotnet nuget locals all --list&lt;br /&gt;http-cache: C:\Users\takatoshi\AppData\Local\NuGet\v3-cache&lt;br /&gt;global-packages: C:\Users\takatoshi\.nuget\packages\&lt;br /&gt;temp: C:\Users\takatoshi\AppData\Local\Temp\NuGetScratch&lt;br /&gt;plugins-cache: C:\Users\takatoshi\AppData\Local\NuGet\plugins-cache
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;環境変数で設定できる様子。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;setx NUGET_PACKAGES D:\nuget\packages&lt;br /&gt;setx NUGET_HTTP_CACHE_PATH D:\nuget\http&lt;span class=&quot;hljs-literal&quot;&gt;-cache&lt;/span&gt;\v3&lt;span class=&quot;hljs-literal&quot;&gt;-cache&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;npm 等も Dev Drive の文書をもとに設定する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt; npm config get cache&lt;br /&gt;C:\Users\takatoshi\AppData\Local\npm-cache&lt;br /&gt;&amp;gt; npm config set cache D:\npm-cache --global
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ついでに仕事用 laptop も Dev Drive 設定してみた。
私物では使ってないが仕事で使う &lt;a href=&quot;https://classic.yarnpkg.com/lang/en/docs/cli/cache/#toc-change-the-cache-path-for-yarn&quot; title=&quot;Yarn&quot;&gt;Yarn&lt;/a&gt; も Dev Drive を使わせてみた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt; setx YARN_CACHE_FOLDER D:\yarn-cache
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;仕事でよく利用する &lt;a href=&quot;https://github.com/nektos/act&quot; title=&quot;nektos/act&quot;&gt;nektos/act&lt;/a&gt;, &lt;a href=&quot;https://github.com/aws/aws-cdk&quot; title=&quot;AWS CDK&quot;&gt;AWS CDK&lt;/a&gt;, &lt;a href=&quot;https://openai.com/codex/&quot; title=&quot;OpenAI Codex&quot;&gt;OpenAI Codex&lt;/a&gt; とかも cache があるのだけど、今は設定してない。
今回は cache だけ Dev Drive を使わせたが、 &lt;code&gt;node_modules&lt;/code&gt; のような小さいファイルが大量にあるものは、本当は repo 丸ごと Dev Drive 配置がベストっぽい。
だけど今はなんとなくやらなかった。&lt;/p&gt;
&lt;p&gt;仕事で使う場合だと、 PHP と TypeScript を Docker で動かすため、 bind mount では ReFS の良くないところが目立つようなので中々手出しできなと思った。
一般的にこのようなユースケースでは WSL2 側で &lt;code&gt;git clone&lt;/code&gt; するのが良いようだが、 &lt;code&gt;ghq&lt;/code&gt; で管理してるのもありやってない。&lt;/p&gt;
&lt;p&gt;ここまでの Dev Drive の設定自体は何も困らなかった。
ただ設定後に &lt;code&gt;dotnet tool restore&lt;/code&gt; しても tool が見つからない状態になって、非常に困った。
原因は以下のように &lt;code&gt;dotnet tool&lt;/code&gt; の問題みたい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dotnet/sdk/issues/11432#issuecomment-1020543559&quot; title=&quot;&amp;#39;Dotnet tool restore&amp;#39; does not work correctly when NUGET_PACKAGES (global-packages) is set to an alternative location · Issue #11432 · dotnet/sdk&quot;&gt;&amp;#39;Dotnet tool restore&amp;#39; does not work correctly when NUGET_PACKAGES (global-packages) is set to an alternative location · Issue #11432 · dotnet/sdk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$env:USERPROFILE\.dotnet\toolResolverCache&lt;/code&gt; にある dotnet tool の path が cache されてるらしい。
cache を消去しないと dotnet tool が Dev Drive の path を見ず、正しい restore が行われない。やば。&lt;/p&gt;
&lt;p&gt;確認してみたら中にはこういう cache があって path が古いままだった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Version&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;5.0.0-alpha.22&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;TargetFramework&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;net10.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;RuntimeIdentifier&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;any&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;fable&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Runner&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;PathToExecutable&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;C:\\Users\\takatoshi\\.nuget\\packages\\fable\\5.0.0-alpha.22\\tools/net10.0/any/fable.dll&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Version&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;5.0.0-alpha.23&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;TargetFramework&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;net10.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;RuntimeIdentifier&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;any&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;fable&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Runner&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;PathToExecutable&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;C:\\Users\\takatoshi\\.nuget\\packages\\fable\\5.0.0-alpha.23\\tools/net10.0/any/fable.dll&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;cache を消す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$env:USERPROFILE&lt;/span&gt;\.dotnet\toolResolverCache
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この後 &lt;code&gt;dotnet tool restore&lt;/code&gt; したらきれいに cache が再生成され、 Dev Drive を見るようになる。&lt;/p&gt;
&lt;p&gt;これを自力で解決するのは難しいな。 AI は素っ頓狂なことを言うし、自力でググってよかった。
&lt;a href=&quot;https://github.com/dotnet/sdk/issues/11432#issuecomment-3118705720&quot; title=&quot;&lt;code&gt;dnx&lt;/code&gt; ならこれが起こらんらしい&quot;&gt;&lt;code&gt;dnx&lt;/code&gt; ならこれが起こらんらしい&lt;/a&gt;が仕組みが違うっぽい。試してないのでわからん。&lt;/p&gt;
&lt;p&gt;Dev Drive に変えてみて特に性能面で優れた点をまだ感じてないが、今後のデフォみたいだし徐々に利用範囲を広めたい所存。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Mon, 23 Feb 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-02-22-disable-windows-smart-app-control.html</guid><link>https://krymtkts.github.io/posts/2026-02-22-disable-windows-smart-app-control.html</link><title>Windows の Smart App Control を無効にする</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;ある日 &lt;a href=&quot;https://github.com/x-motemen/ghq&quot; title=&quot;&lt;code&gt;ghq&lt;/code&gt;&quot;&gt;&lt;code&gt;ghq&lt;/code&gt;&lt;/a&gt; がブロックされた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt; ghq&lt;br /&gt;ResourceUnavailable: Program &amp;#x27;ghq.exe&amp;#x27; failed to run: An error occurred trying to start process &amp;#x27;C:\Users\takatoshi\go\bin\ghq.exe&amp;#x27; with working directory &amp;#x27;C:\Users\takatoshi&amp;#x27;. An Application Control policy has blocked this file.At line:1 char:1&lt;br /&gt;+ ghq&lt;br /&gt;+ ~~~.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;event log 全文。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt; Get-WinEvent -LogName &amp;quot;Microsoft-Windows-CodeIntegrity/Operational&amp;quot; | ? -Property Message -like &amp;#x27;*ghq.exe*&amp;#x27; | Select-Object -First 1 | % Message&lt;br /&gt;Code Integrity determined that a process (\Device\HarddiskVolume3\Program Files\PowerShell\7-preview\pwsh.exe) attempted to load \Device\HarddiskVolume3\Users\takatoshi\go\bin\ghq.exe that did not meet the Enterprise signing level requirements or violated code integrity policy (Policy ID:{0283ac0f-fff1-49ae-ada1-8a933130cad6}).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;さっぱりわからんかったが、 Windows 11 の &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/apps/develop/smart-app-control/overview&quot; title=&quot;Smart App Control&quot;&gt;Smart App Control&lt;/a&gt; という機能らしい。
署名されてないアプリを全殺しするみたい。わたしは Go 系の tool は GitHub 直で local build しているのでそのせい。
新しい laptop を使い始めて、最初の期間は評価モードで、その後 Windows Updates かなんかを機に強制モードとなり、ブロックされるようになったようだ。怖。&lt;/p&gt;
&lt;p&gt;Go のバイナリ以外にも local で build してるものは全て使えなくなってると想像され面倒極まりないので、開発者には向いてないと判断した。
決まった directory を除外するとかの細かいルールを定めるのも億劫なので、やることは定まってくる。
除外ルール設定せず Privacy &amp;amp; security &amp;gt; Windows Security &amp;gt; App &amp;amp; browser control で Smart App Control を無効化する。
これまでは一度 Off にすると clean install するまで再度 On にできなかったそうだが、 &lt;a href=&quot;https://windowsreport.com/windows-11-kb5074105-removes-major-limitation-from-smart-app-control/&quot; title=&quot;2026-02 の更新プログラムで再度有効できるよう修正された&quot;&gt;2026-02 の更新プログラムで再度有効できるよう修正された&lt;/a&gt;様子。
そうならば一旦 Off にするのに何の躊躇もなく行えるので、無効にした。&lt;/p&gt;
&lt;p&gt;久し振りに困った。非エンジニア向けの機能らしいが、めちゃくちゃ面倒な機能だな。
いまでは Windows にも開発者向け機能の設定画面があるのだし、そこで設定できれば楽なのに。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 22 Feb 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-02-15-fsharp-powrshell-module-template-part-3.html</guid><link>https://krymtkts.github.io/posts/2026-02-15-fsharp-powrshell-module-template-part-3.html</link><title>F# の PowerShell Module の Template を作りたい Part 3</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/FsPowerShellTemplate&quot; title=&quot;krymtkts/FsPowerShellTemplate&quot;&gt;krymtkts/FsPowerShellTemplate&lt;/a&gt; の開発をした。
Cmdlet, Command-line predictor, Feedback Provider の相互の連携を作り、 task runner の整備をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.subsystem.prediction.icommandpredictor?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;ICommandPredictor&lt;/code&gt;&quot;&gt;&lt;code&gt;ICommandPredictor&lt;/code&gt;&lt;/a&gt; と &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.subsystem.feedback.ifeedbackprovider?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;IFeedbackProvider&lt;/code&gt;&quot;&gt;&lt;code&gt;IFeedbackProvider&lt;/code&gt;&lt;/a&gt; を別 class で実装してるので、状態の共有を別の class を経由する必要がある。
この場合は、コードの中枢を module に抽出するのが良い。 &lt;a href=&quot;https://github.com/krymtkts/FsPowerShellTemplate/blob/d35ee403e1dd54f1aeaf03105f1536c0cb7b97ec/src/SampleModule/Core.fs&quot; title=&quot;&lt;code&gt;Core&lt;/code&gt;&quot;&gt;&lt;code&gt;Core&lt;/code&gt;&lt;/a&gt; とした。
Cmdlet, Command-line predictor, Feedback Provider はそれを参照する薄い実装のみに留めるのが良いだろう。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Core&lt;/code&gt; がこんな感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;namespace&lt;/span&gt; SampleModule&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System.Threading&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System.Collections&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Core &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;GreetingStore&lt;/span&gt;() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Literal&amp;gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; dirtyFlag &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Literal&amp;gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; cleanFlag &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; gate &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; obj ()&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; names &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Generic.List&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;()&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;mutable&lt;/span&gt; dirty &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; cleanFlag&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Add(name&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;lock&lt;/span&gt; gate (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; () &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                name &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; names.Add&lt;br /&gt;                dirty &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; dirtyFlag)&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Get() &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;lock&lt;/span&gt; gate (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; () &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Return a snapshot to avoid enumeration issues with concurrent updates.&lt;/span&gt;&lt;br /&gt;                names &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Seq.toArray &lt;span class=&quot;hljs-operator&quot;&gt;:&amp;gt;&lt;/span&gt; seq&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Count() &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;lock&lt;/span&gt; gate (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; () &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; names.Count)&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Remove(name&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;lock&lt;/span&gt; gate (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; () &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; name &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; names.Remove &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;                    dirty &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; dirtyFlag)&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.ConsumeUpdated() &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            Interlocked.Exchange(&lt;span class=&quot;hljs-operator&quot;&gt;&amp;amp;&lt;/span&gt;dirty, cleanFlag) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; dirtyFlag&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; greetingStore &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; GreetingStore()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Command-line predictor (長いので一部端折る)
なんか今見てみたら &lt;code&gt;GetSuggestion&lt;/code&gt; の実装がイマイチなのでより simple に直した方が良さそう。
&lt;code&gt;OnSuggestionAccepted&lt;/code&gt; を呼ばせるには &lt;code&gt;CanAcceptFeedback&lt;/code&gt; で &lt;code&gt;true&lt;/code&gt; を返す必要がある。
また suggestion に mini session ID も含ませていないと呼ばれなかった。
これらの情報は多分 sample には載ってないのよね。 interface の説明&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;&lt;a id=&quot;footnote-ref-2&quot; href=&quot;#footnote-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;等からこの挙動を拾ったのだけど、他の文書に書いてないのかな。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;GreetingPredictor&lt;/span&gt;(guid&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; guid &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Guid.Parse&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;mutable&lt;/span&gt; miniSessionId &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; ICommandPredictor &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.GetSuggestion&lt;br /&gt;            (client&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PredictionClient, context&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PredictionContext, cancellationToken&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; CancellationToken)&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; SuggestionPackage &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; suggestions &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                context.InputAst.Extent.Text&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; suggestionEntries requires non-empty by Requires.NotNullOrEmpty.&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-comment&quot;&gt;// https://github.com/PowerShell/PowerShell/blob/eef334de1b0f648512859bd032356f9c8df7cb91/src/System.Management.Automation/engine/Subsystem/PredictionSubsystem/ICommandPredictor.cs#L278&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; input &lt;span class=&quot;hljs-keyword&quot;&gt;when&lt;/span&gt; input &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; String.IsNullOrWhiteSpace &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; Seq.empty&lt;br /&gt;                    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; input &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                        greetingStore.Get()&lt;br /&gt;                        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Seq.choose (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; name &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; name.Contains(input, StringComparison.OrdinalIgnoreCase) &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;                                PredictiveSuggestion(&lt;br /&gt;                                    &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;&lt;span class=&quot;hljs-subst&quot;&gt;{suggestionPart1}&lt;/span&gt;&lt;span class=&quot;hljs-subst&quot;&gt;{name}&lt;/span&gt;&lt;span class=&quot;hljs-subst&quot;&gt;{suggestionPart2}&lt;/span&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;                                    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;A friendly greeting from F#!&amp;quot;&lt;/span&gt;&lt;br /&gt;                                )&lt;br /&gt;                                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;&lt;br /&gt;                            &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;                                &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;)&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Linq.Enumerable.ToList&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; empty suggestionEntries is rejected by PowerShell&amp;#x27;s internal validation.&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; suggestions.Count &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;                Unchecked.defaultof&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;SuggestionPackage&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; SuggestionPackage must include a mini-session id; PowerShell uses it when calling OnSuggestionDisplayed/OnSuggestionAccepted.&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; session &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Threading.Interlocked.Increment(&lt;span class=&quot;hljs-operator&quot;&gt;&amp;amp;&lt;/span&gt;miniSessionId) &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; uint32&lt;br /&gt;                SuggestionPackage(session, suggestions)&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.CanAcceptFeedback(client&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PredictionClient, feedback&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PredictorFeedbackKind) &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            DebugLogger.WriteLine &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;CanAcceptFeedback: Feedback kind: &lt;span class=&quot;hljs-subst&quot;&gt;{feedback}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; to capture events, must be return true for expected feedback kinds.&lt;/span&gt;&lt;br /&gt;            feedback &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; PredictorFeedbackKind.SuggestionAccepted&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.OnSuggestionAccepted(client&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PredictionClient, session&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;uint32&lt;/span&gt;, acceptedSuggestion&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            DebugLogger.WriteLine &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;OnSuggestionAccepted: Accepted suggestion: &lt;span class=&quot;hljs-subst&quot;&gt;{acceptedSuggestion}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; matches &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; acceptedSuggestion &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; greetingPattern.Match&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; matches.Captures.Count &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; removal &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; matches.Groups.[&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;removal&amp;quot;&lt;/span&gt;].Value&lt;br /&gt;                removal &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; greetingStore.Remove&lt;br /&gt;                DebugLogger.WriteLine &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;OnSuggestionAccepted: Removed greeting for: &lt;span class=&quot;hljs-subst&quot;&gt;{removal}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Feedback Provider は、多分既定では &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.subsystem.feedback.ifeedbackprovider.getfeedback?view=powershellsdk-7.4.0#system-management-automation-subsystem-feedback-ifeedbackprovider-getfeedback(system-management-automation-subsystem-feedback-feedbackcontext-system-threading-cancellationtoken)&quot; title=&quot;&lt;code&gt;GetFeedback&lt;/code&gt;&quot;&gt;&lt;code&gt;GetFeedback&lt;/code&gt;&lt;/a&gt; の引数 &lt;code&gt;context&lt;/code&gt;&lt;sup&gt;&lt;a id=&quot;footnote-ref-3&quot; href=&quot;#footnote-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; をこねくり回して前の実行の文脈から処理対象を選び出すとかを想定されてる。
ただ Cmdlet, Command-line predictor, Feedback Provider の連携が必要な場合はそれだと役に立たない。
なので状態の共有が結果的に一番 simple になる。
template 用の sample 実装では global な状態を持たせてるから、同じ PowerShell session の中でだけ状態が共有される。
session をまたいで共有させたい場合は &lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;&lt;code&gt;krymtkts/SnippetPredictor&lt;/code&gt;&quot;&gt;&lt;code&gt;krymtkts/SnippetPredictor&lt;/code&gt;&lt;/a&gt; のように PowerShell の外の世界に永続化しないといけない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;GreetingFeedbackProvider&lt;/span&gt;(guid&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; IFeedbackProvider &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Trigger&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; FeedbackTrigger &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; FeedbackTrigger.Success&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.GetFeedback(context&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; FeedbackContext, token&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Threading.CancellationToken) &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; FeedbackItem &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            DebugLogger.WriteLine &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;GetFeedback: Checking for feedback provision.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Provide feedback only when there is an update.&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Using the greeting store directly here for simplicity and context does not provide suggestion acceptance status.&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; greetingStore.ConsumeUpdated() &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; header &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Greeting Feedback&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                FeedbackItem(&lt;br /&gt;                    header,&lt;br /&gt;                    [ &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;You have &lt;span class=&quot;hljs-subst&quot;&gt;{greetingStore.Count()}&lt;/span&gt; greetings stored.&amp;quot;&lt;/span&gt;&lt;br /&gt;                      &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Thank you for using the Greeting Predictor!&amp;quot;&lt;/span&gt; ]&lt;br /&gt;                    &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Generic.List&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;,&lt;br /&gt;                    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Feedback for the Greeting Predictor&amp;quot;&lt;/span&gt;,&lt;br /&gt;                    FeedbackDisplayLayout.Portrait&lt;br /&gt;                )&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;改めて &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-cmdline-predictor&quot; title=&quot;Command-line predictor&quot;&gt;Command-line predictor&lt;/a&gt; が中枢だと思った。
&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-feedback-provider&quot; title=&quot;Feedback Provider&quot;&gt;Feedback Provider&lt;/a&gt; は、言葉は悪いが Command-line predictor に添えるアクセントのようなものというのが現状だろう。
Feedback Provider が登場したのは 2023 年の PowerShell 7.4 だが、いまのところ今後も残り続けるのかがよくわからん機能でもある。
コミュニティもなんとなく使い所がよくわからない機能として扱ってる気もする(それは Command-line predictor も同じ話だが)。
Feedback Provider の GitHub Project はあるようだが 2026-02-15 時点で大きな動きはなさそう。 community が feedback しても先に進まん的な雰囲気があるのかも知れない。
&lt;a href=&quot;https://github.com/orgs/PowerShell/projects/11/views/1&quot; title=&quot;Main · Feedback Provider Roadmap&quot;&gt;Main · Feedback Provider Roadmap&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;もしかしたら &lt;a href=&quot;https://github.com/PowerShell/PowerShell-RFC/blob/master/CommunityCall/README.md&quot; title=&quot;community call&quot;&gt;community call&lt;/a&gt; に参加してたらなんかわかるのかな？
そんな感じには思えないのだけど。&lt;/p&gt;
&lt;p&gt;Command-line predictor, Feedback Provider は binary module なので、試した感じでは PowerShell だけで完結してサクッと書けない。
C# なり F# なりで書く必要があるから、それもあって feedback が集まりにくい状況になっているのかもな。
実際、実装自体は &lt;code&gt;ICommandPredictor&lt;/code&gt; と &lt;code&gt;IFeedbackProvider&lt;/code&gt; を 1 つの class に実装すれば状態共有も単純だ。
なので PowerFighter(PowerShell 使いの自作の造語) の言語をまたぐ心理的なハードルだけが普及の課題なんやろう。&lt;/p&gt;
&lt;p&gt;ハードルを超えて Command-line predictor を書けば、結構いい感じに PowerShell 統合された追加機能を作れる。
でも Feedback Provider はコマンド実行後の表示を賑やかすだけなので、あえて付ける必要があるかというのがこれまた難しい。&lt;/p&gt;
&lt;p&gt;何にせよ実際に書いてみないと使い所や問題点もイメージできなかったし、今回書いてよかった。
まだ廃止にもなってないし、自作 PowerShell module にも使ってみようと思っている。
採用した後で廃止となれば、撤退作業のような普段経験しにくい作業も体験できるかも知れないし、やっておく経験が損になることはないかな。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと task runner 。今回から psake じゃなく &lt;a href=&quot;https://github.com/nightroman/Invoke-Build&quot; title=&quot;nightroman/Invoke-Build&quot;&gt;nightroman/Invoke-Build&lt;/a&gt; を使うようにした。
&lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;psake/psake&quot;&gt;psake/psake&lt;/a&gt; は名前が最高だが parameter を渡すのはちょっと面倒だし、 Invoke-Build でならそのへん simple に改善できそうだったためだ。&lt;/p&gt;
&lt;p&gt;build script の名は Invoke-Build の流儀に合わせ &lt;a href=&quot;https://github.com/krymtkts/FsPowerShellTemplate/blob/d35ee403e1dd54f1aeaf03105f1536c0cb7b97ec/build.ps1&quot; title=&quot;&lt;code&gt;build.ps1&lt;/code&gt;&quot;&gt;&lt;code&gt;build.ps1&lt;/code&gt;&lt;/a&gt; とした。
build script 直で呼んだ場合に Invoke-Build で起動し直す。
build script で呼べるので parameter 補完を PowerShell の仕組みに寄せた感じ。
parameter の一部を &lt;code&gt;$Task&lt;/code&gt; としてたら予約されておりエラーになったので、そこだけ別名にしたため詰め直しが必要だった。
使用感はなかなか良い。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;#&lt;br /&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;.Synopsis&lt;/span&gt;&lt;br /&gt;    Invoke-Build tasks&lt;br /&gt;#&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Build script parameters&lt;/span&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;Diagnostics.CodeAnalysis.SuppressMessageAttribute&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSUseDeclaredVarsMoreThanAssignments&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;Justification&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Variables are used in script blocks and argument completers&amp;#x27;&lt;/span&gt;)]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;(&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Position&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)]&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;ValidateSet&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Init&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Clean&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Lint&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Build&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Import&amp;#x27;&lt;/span&gt;)]&lt;br /&gt;    [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;[]] &lt;span class=&quot;hljs-variable&quot;&gt;$Tasks&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Build&amp;#x27;&lt;/span&gt;),&lt;br /&gt;&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;ValidateSet&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Debug&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Release&amp;#x27;&lt;/span&gt;)]&lt;br /&gt;    [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;] &lt;span class=&quot;hljs-variable&quot;&gt;$Configuration&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Debug&amp;#x27;&lt;/span&gt;&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# If invoked directly (not dot-sourced by Invoke-Build), hand off execution to Invoke-Build.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$MyInvocation&lt;/span&gt;.InvocationName &lt;span class=&quot;hljs-operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;.&amp;#x27;&lt;/span&gt;) {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$forward&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$PSBoundParameters&lt;/span&gt;.GetEnumerator() | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Begin&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$acc&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{} } &lt;span class=&quot;hljs-literal&quot;&gt;-Process&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Processing parameter: &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{_}&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ForegroundColor&lt;/span&gt; Yellow&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Key &lt;span class=&quot;hljs-operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Tasks&amp;#x27;&lt;/span&gt;) {&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$acc&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;.Key&lt;/span&gt;] = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Value&lt;br /&gt;        }&lt;br /&gt;    } &lt;span class=&quot;hljs-literal&quot;&gt;-End&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$acc&lt;/span&gt; }&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-Build&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$PSCommandPath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Task&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Tasks&lt;/span&gt; @forward&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$LASTEXITCODE&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 略&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;まだ Invoke-Build 準拠の help とか書いてない。けどなくてもいいかもしれんな。&lt;/p&gt;
&lt;p&gt;あとは sample module の unit test や end-to-end test 、 documentation あたりを整備すれば一通りそろうかな。
そしたらまず GitHub の template repository 化しよう。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.subsystem.prediction.icommandpredictor.onsuggestiondisplayed?view=powershellsdk-7.4.0&quot; title=&quot;ICommandPredictor.OnSuggestionDisplayed Method (System.Management.Automation.Subsystem.Prediction) | Microsoft Learn&quot;&gt;ICommandPredictor.OnSuggestionDisplayed Method (System.Management.Automation.Subsystem.Prediction) | Microsoft Learn&lt;/a&gt; &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;footnote-2&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.subsystem.prediction.suggestionpackage.-ctor?view=powershellsdk-7.4.0#system-management-automation-subsystem-prediction-suggestionpackage-ctor(system-uint32-system-collections-generic-list((system-management-automation-subsystem-prediction-predictivesuggestion)))&quot; title=&quot;SuggestionPackage Constructor (System.Management.Automation.Subsystem.Prediction) | Microsoft Learn&quot;&gt;SuggestionPackage Constructor (System.Management.Automation.Subsystem.Prediction) | Microsoft Learn&lt;/a&gt; &lt;a href=&quot;#footnote-ref-2&quot; data-footnote-backref aria-label=&quot;Back to reference 2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;footnote-3&quot;&gt;
&lt;p&gt;型は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.subsystem.feedback.feedbackcontext?view=powershellsdk-7.4.0&quot; title=&quot;FeedbackContext Class (System.Management.Automation.Subsystem.Feedback)&quot;&gt;FeedbackContext Class (System.Management.Automation.Subsystem.Feedback)&lt;/a&gt; &lt;a href=&quot;#footnote-ref-3&quot; data-footnote-backref aria-label=&quot;Back to reference 3&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 15 Feb 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-02-08-fsharp-powrshell-module-template-part-2.html</guid><link>https://krymtkts.github.io/posts/2026-02-08-fsharp-powrshell-module-template-part-2.html</link><title>F# の PowerShell Module の Template を作りたい Part 2</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;ようやく重い腰を上げて PowerShell Module を F# で書くときの template を作り始めた。
repository name は &lt;a href=&quot;https://github.com/krymtkts/FsPowerShellTemplate&quot; title=&quot;krymtkts/FsPowerShellTemplate&quot;&gt;krymtkts/FsPowerShellTemplate&lt;/a&gt; にした。
まだ完成してないから template repository にはしてない。&lt;/p&gt;
&lt;p&gt;命名はちょっと気を使った。
先頭に &lt;code&gt;FSharp&lt;/code&gt; とか &lt;code&gt;PowerSHell&lt;/code&gt; は持ってくるべきではないだろうし、個人の識別子が入るのも微妙だ。
それでいて将来的に PowerShell Module 以外が含まれる可能性も考慮したうえで、いつか NuGet で template 配布するというのも考えて、今の形に。
略称の &lt;code&gt;Fs&lt;/code&gt; なら多少カジュアル感出るし、多分いい落とし所なはず。
&lt;code&gt;Scaffold&lt;/code&gt; も考えたが、 NuGet では &lt;code&gt;Template&lt;/code&gt; が一般的なのを考えたらそっちの方が見つけやすくなる。
NuGet の慣習的な dot 区切りだけはやめたが、それは repository name と合わせたくての妥協点だ。でも気が変わったら変える可能性ある。&lt;/p&gt;
&lt;p&gt;ひとまず template の設計としては、 Cmdlet, Command-line predictor, Feedback provider を 1 つの project に同梱する。
そしてこれらの連携が真骨頂なので、それの sample として十分な例を示しておけたらなと考えている。まだ作ってないけど。
これらを無効にする術としては、ひとまずはコードを消すことで実現したらいいかなと考えている。
そのため Cmdlet, Command-line predictor, Feedback provider が別ファイルで実装される。
今はやってないけど連携のコアの部分も別ファイルで作る。
そうすれば Feedback provider や Command-line predictor が不要ならファイルごと消せる感じということになる。
これで自分が新しく作るときもそのテンプレに従って書くだけなのでかなり楽なのでは？と期待している。&lt;/p&gt;
&lt;p&gt;と作り始めたもののなんだか花粉症かなと思ってたのが風邪っぽい？不調に変わってきたそんなに進んでない。
でも Cmdlet, Command-line predictor, Feedback provider の作成まではやった。
例にしてるのは何度も読んでる以下の文書。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-cmdline-predictor&quot; title=&quot;How to create a command-line predictor - PowerShell | Microsoft Learn&quot;&gt;How to create a command-line predictor - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-feedback-provider&quot; title=&quot;How to create a feedback provider - PowerShell | Microsoft Learn&quot;&gt;How to create a feedback provider - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Feedback provider は初めて作ったのだが、作ってみてこいつ単体の interface は simple なもんだというのに気づいた。
上記文書の sample だと 1 つの class で Command-line predictor と Feedback provider の両方を実装してるのでゴチャついて見えるだけ。
まだ Feedback provider の真髄である Command-line predictor や Cmdlet との連携を全くやってないので simple になっていると言うのもけど。
いま template に実装したのは何とも連携してない Feedback provider で、それを参考として貼ると以下の通り。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/FsPowerShellTemplate/blob/39cb16631a6cbc63812ba66ebff1a5b55290ed8e/src/SampleModule/FeedbackProvider.fs&quot; title=&quot;FsPowerShellTemplate/src/SampleModule/FeedbackProvider.fs at 39cb16631a6cbc63812ba66ebff1a5b55290ed8e · krymtkts/FsPowerShellTemplate&quot;&gt;FsPowerShellTemplate/src/SampleModule/FeedbackProvider.fs at 39cb16631a6cbc63812ba66ebff1a5b55290ed8e · krymtkts/FsPowerShellTemplate&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;namespace&lt;/span&gt; SampleModule&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System.Collections&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System.Management.Automation.Subsystem.Feedback&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;GreetingFeedbackProvider&lt;/span&gt;(guid&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Guid.Parse(guid)&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Literal&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; name &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Greeting&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Literal&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; description &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;A feedback provider that handles feedback for the greeting predictor.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; IFeedbackProvider &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Id &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;id&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Name &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; name&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Description &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; description&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.FunctionsToDefine &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Trigger&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; FeedbackTrigger &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; FeedbackTrigger.Success&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.GetFeedback(context&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; FeedbackContext, token&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Threading.CancellationToken) &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; FeedbackItem &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; header &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Greeting Feedback&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            FeedbackItem(&lt;br /&gt;                header,&lt;br /&gt;                [ &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Was the greeting helpful?&amp;quot;&lt;/span&gt;; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Did you like the style of the greeting?&amp;quot;&lt;/span&gt; ]&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Generic.List&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;,&lt;br /&gt;                &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Feedback for the Greeting Predictor&amp;quot;&lt;/span&gt;,&lt;br /&gt;                FeedbackDisplayLayout.Portrait&lt;br /&gt;            )
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;文書に載ってる sample でもわかるように、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.subsystem.feedback.ifeedbackprovider.getfeedback&quot; title=&quot;&lt;code&gt;GetFeedback&lt;/code&gt;&quot;&gt;&lt;code&gt;GetFeedback&lt;/code&gt;&lt;/a&gt; が Feedback provider のコア。
この中で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.subsystem.feedback.feedbackcontext&quot; title=&quot;&lt;code&gt;FeedbackContext&lt;/code&gt;&quot;&gt;&lt;code&gt;FeedbackContext&lt;/code&gt;&lt;/a&gt; の結果に応じて処理を分ける等するのが期待されるので、とっ散らからないよう別の型に処理をまとめるなどが必要だろうな。&lt;/p&gt;
&lt;p&gt;とりままだ連携機能を作ったワケではないので完全ではないけど、 Feedback provider を作った。
これで作ったことがなかったものは 1 つクリアしたわけだ。
作ってみていて、こういう Feedback provider の使い方はアリかもしれんな、とかアイデアの片鱗も掴めてた気がする。
実際に実装してみるというのはやっぱり重要やな。&lt;/p&gt;
&lt;p&gt;とりま連携部分とかの残りのタスクを進めるつもり。
そんで今の一番の悩みは task runner を何にするか。
長らく &lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;psake/psake&quot;&gt;psake/psake&lt;/a&gt; を使ってるが &lt;a href=&quot;https://github.com/nightroman/Invoke-Build&quot; title=&quot;nightroman/Invoke-Build&quot;&gt;nightroman/Invoke-Build&lt;/a&gt; も使ってみたい。
psake は名前が最高だが parameter を渡すのはちょっと面倒なのがなあ。
あと &lt;a href=&quot;https://github.com/fsprojects/FAKE&quot; title=&quot;fsprojects/FAKE&quot;&gt;fsprojects/FAKE&lt;/a&gt; を使うという手もある。
でも fsx から PowerShell 呼ぶってのもどうなんかなあという気がするよな。
楽しい悩みや。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 08 Feb 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-02-01-hp-omen-transcend-14.html</guid><link>https://krymtkts.github.io/posts/2026-02-01-hp-omen-transcend-14.html</link><title>HP OMEN Transcend 14 買った</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;従来機 Raze Blade Stealth 2017 も随分古く遅くなったし、昨今のメモリ高騰もあるしで、久し振りに laptop を新調した。
購入したのは &lt;a href=&quot;https://jp.ext.hp.com/gaming/personal/omen_transcend_14/?msockid=08b31ccb0c12649719b60a250d1c6572&quot; title=&quot;HP OMEN Transcend 14 の OMEN by HP Transcend 14-fb1011TX スプリームモデル G2&quot;&gt;HP OMEN Transcend 14 の OMEN by HP Transcend 14-fb1011TX スプリームモデル G2&lt;/a&gt; というやつ。
セールでも 38 万円ほどした。なかなかの出費だ。主要な Spec は以下の通り。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.intel.co.jp/content/www/jp/ja/products/sku/241747/intel-core-ultra-9-processor-285h-24m-cache-up-to-5-40-ghz/specifications.html&quot; title=&quot;Intel Core Ultra 9 285H (max 5.40GHz, cache 24MB)&quot;&gt;Intel Core Ultra 9 285H (max 5.40GHz, cache 24MB)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;14.0 inch 2.8K OLED&lt;/li&gt;&lt;li&gt;RAM 64GB (LPDDR5x-7467MT/s)&lt;/li&gt;&lt;li&gt;2TB PCIe Gen4 NVMe M.2 SSD TLC&lt;/li&gt;&lt;li&gt;NVIDIA GeForce RTX 5070 Laptop&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;この機種は GPU の消費電力が制限されておりフルパワーが出せなかったり、 13 inch が好きなので 14 inch はちょっと大きいとか色々気になる点はあった。
64GB の大容量メモリだと &lt;a href=&quot;https://www.amd.com/en/products/processors/laptop/ryzen/ai-300-series/amd-ryzen-ai-max-plus-395.html&quot; title=&quot;AMD Ryzen AI Max+ 395&quot;&gt;AMD Ryzen AI Max+ 395&lt;/a&gt; が載った &lt;a href=&quot;https://rog.asus.com/jp/laptops/rog-flow/rog-flow-z13-2025/&quot; title=&quot;ROG Flow Z13 (2025) GZ302&quot;&gt;ROG Flow Z13 (2025) GZ302&lt;/a&gt; もいいなと思っていた。
でもいくら驚異的に速い integrated GPU を搭載しているからと言って、 UWQHD のような高解像度だと現時点では discrete GPU には叶わないのが調べてわかった。
次買い替えるときには状況はわかってるかもだが、今久し振りにゲームもするならもうええかということで HP OMEN Transcend 14 にした。
理想としては laptop のヒンジが 180 °開く機種を選びたかったのだけど、これも妥協点の 1 つ。
ただ総じて Spec は高いので、従来機に比べて現時点極めて高速で満足している。&lt;/p&gt;
&lt;p&gt;しかし Microsoft アカウントの気に入らない仕様を回避するのには苦労した。
Windows 11 では初期設定時の Microsoft アカウントのログインは諸々の設定が同期されるので極めて楽だが、代償として username がアカウントメアド先頭 5 文字になってしまう。
&lt;code&gt;takatoshi~&lt;/code&gt; が &lt;code&gt;takat&lt;/code&gt; に。なんでなんだよ。
仕事では面倒でそのまま気にせず使ってるが、私用機ではこれは許容しがたい。
回避方法としてはネットワークを使わずに初期設定すれば local user を作って始めれるようなのだが、うっかり忘れて Wi-Fi に繋いでしまった。
一度 Wi-Fi に繋いだあとどうやって解除するかわからなかったので、ひとまず Microsoft アカウントで初期設定したのだが、これが良くなかった。&lt;/p&gt;
&lt;p&gt;初期設定後、 Microsoft アカウントの user を local user に変更、期待の名前の local user を作成し Microsoft アカウントに関連付けた。
ここで Windows Hello の設定が成功しなかったり設定や OneDrive の同期が機能しなくなった。
既存 user に設定していた Windows Hello と PIN の設定を外してもうまくいかなかったので一晩寝かしたところ、うまくいく様になった。クラウド側でキャッシュされてたのかな。&lt;/p&gt;
&lt;p&gt;OneDrive の同期だけは全く解消されなかったので、 AI とトラシューの上別の端末として管理されてしまったのかもなと考えて既存 user に連携済みファイルを移動してみた。
ここで急に同期が始まり Copy という suffix を持つ同じファイルが OneDrive にできてしまった... Copy 側を全部消して一旦同期済みになった。
Windows の設定が同期されないのはかなり痛いが、調べつつ個別に設定していった。&lt;/p&gt;
&lt;p&gt;アプリケーション類のインストールは &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/package-manager/winget/&quot; title=&quot;winget&quot;&gt;winget&lt;/a&gt; &lt;a href=&quot;https://chocolatey.org/&quot; title=&quot;Chocolatey&quot;&gt;Chocolatey&lt;/a&gt; を使った。
知らなかったのだが、昨今の Windows は winget がプリインストールされておりはじめから使える。
初回の script での package manager をインストールする手間が省ける。
今回は元々 winget で管理している package と Chocolatey を winget で、その他を Chocolatey でインストールした。
script 形式で配布されるアプリケーションはまだ winget ではインストールできないのもあるし、元々使ってるアプリケーションも Chocolatey で管理している。
が、 winget も package が拡充され使用感が良くなってるようなので、 binary 系は winget に寄せるのもいいのかもな。&lt;/p&gt;
&lt;p&gt;処理系と依存関係の設定、 Context menu 置き換え等の Registry 書換は自前の PowerShell Profile &lt;a href=&quot;https://github.com/krymtkts/pwsh-profile/&quot; title=&quot;krymtkts/pwsh-profile&quot;&gt;krymtkts/pwsh-profile&lt;/a&gt; で自動化している。
winget でも取れないアプリケーション、例えば &lt;a href=&quot;https://github.com/microsoft/terminal?tab=readme-ov-file#installing-windows-terminal-canary&quot; title=&quot;Windows Terminal Canary&quot;&gt;Windows Terminal Canary&lt;/a&gt; は profile で自動化している。&lt;/p&gt;
&lt;p&gt;あと今回から OneDrive で設定、 backup 、自作フォントを同期して使ってみた。
旧 laptop で雑に管理されたファイルが新 laptop にも引き継がれてしまう点は懸念だが、移行はかなり楽になった。
この方法なら &lt;a href=&quot;https://github.com/stylus/stylus&quot; title=&quot;Stylus&quot;&gt;Stylus&lt;/a&gt; の user CSS を OneDrive に出力しておけば Google Chrome でも Edge でも両方使えて便利だ。
dotfiles のうち sensitive な一部は OneDrive で同期してコピペした。
PowerToys も backup を OneDrive に出力し restore する方法を採用した。
ただ例えば &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/powertoys/command-palette/overview&quot; title=&quot;Command Palette&quot;&gt;Command Palette&lt;/a&gt; のような一部の設定は出力されなかったようで、そこは手で変更している。&lt;/p&gt;
&lt;p&gt;GnuPG の鍵束を移行するのにも手間取った。
鍵束の移行は始めたやったのでコピペでやったのだけど、所有権の違いでエラーになって使えなかった。
結局コピペは推奨されない方法ではあるものの、所有権を移せば利用できるようなので、今回はそれでしのいだ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 管理者権限で&lt;/span&gt;&lt;br /&gt;gpgconf &lt;span class=&quot;hljs-literal&quot;&gt;--kill&lt;/span&gt; all&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# backup の `gnupg` を `$env:APPDATA/gnupg` に配置&lt;/span&gt;&lt;br /&gt;takeown /F &lt;span class=&quot;hljs-variable&quot;&gt;$env:APPDATA&lt;/span&gt;\gnupg /&lt;span class=&quot;hljs-built_in&quot;&gt;R&lt;/span&gt; /D Y&lt;br /&gt;icacls &lt;span class=&quot;hljs-variable&quot;&gt;$env:APPDATA&lt;/span&gt;\gnupg /reset /T&lt;br /&gt;icacls &lt;span class=&quot;hljs-variable&quot;&gt;$env:APPDATA&lt;/span&gt;\gnupg /inheritance:&lt;span class=&quot;hljs-built_in&quot;&gt;r&lt;/span&gt;&lt;br /&gt;icacls &lt;span class=&quot;hljs-variable&quot;&gt;$env:APPDATA&lt;/span&gt;\gnupg /grant:&lt;span class=&quot;hljs-built_in&quot;&gt;r&lt;/span&gt; takatoshi:F /T
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで多分全て設定終わってるはず。
まだ微妙に痒いところが残ってるけど、それは追々調整していくものとする。&lt;/p&gt;
&lt;p&gt;結局 1 月は対して開発もせずに過ごしたので、 2 月はもうちょい開発したいな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 01 Feb 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-02-01-fsharp-powrshell-module-template.html</guid><link>https://krymtkts.github.io/posts/2026-02-01-fsharp-powrshell-module-template.html</link><title>F# の PowerShell Module の Template を作りたい</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今年やったことないものに取り組むのを、何にしようかなと考えていた。
結局 PowerShell の Feedback provider 辺りがいいかなと決定した。&lt;/p&gt;
&lt;p&gt;ただ Feedback provider の本当の魅力は Command-line predictor との連携なんやが、何を連携させるかのアイデアがない。
とはいえ F# で Feedback provider を書く変わり者もそういないし、それだけでも作る価値あるような気もしている。
なもんで何を実装するのかのアイデアを決めるまでの場繋ぎが必要になった。&lt;/p&gt;
&lt;p&gt;Feedback provider を作るだし、せっかくなので Template を作ってみよう思っている。
F# で作る PowerShell の Cmdlet, Command-line predictor, Feedback provider の Template だ。
これまでコピペで作ってたしちょうどいいわ。&lt;/p&gt;
&lt;p&gt;これを GitHub の Template にするのか NuGet の Template にするのかが悩ましかったので、 AI に聞いた。
ChatGPT に相談した感じだと、はじめは GitHub Template repository で型を作る。
その後に NuGet の Template で簡単に展開できる版にできるぞということなので、それで行く。
対応言語は F# のみ。自分が使うからな。
参照するのは以下の文書かな。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-standard-library-binary-module?view=powershell-7.5&quot; title=&quot;How to create a Standard Library Binary Module - PowerShell | Microsoft Learn&quot;&gt;How to create a Standard Library Binary Module - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-cmdline-predictor?view=powershell-7.5&quot; title=&quot;How to create a command-line predictor - PowerShell | Microsoft Learn&quot;&gt;How to create a command-line predictor - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-feedback-provider?view=powershell-7.5&quot; title=&quot;How to create a feedback provider - PowerShell | Microsoft Learn&quot;&gt;How to create a feedback provider - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/tools/custom-templates&quot; title=&quot;Custom templates for dotnet new - .NET CLI | Microsoft Learn&quot;&gt;Custom templates for dotnet new - .NET CLI | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Feedback provider と NuGet の Template は作ったことないが、他は作ったことある。
始めやすく Cmdlet -&amp;gt; Command-line predictor -&amp;gt; Feedback provider -&amp;gt; NuGet Template の流れで作ったらいいかな。
その内に Feedback provider が必要な機能のヒントを得られているかも知れない。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 01 Feb 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-01-25-try-to-use-powertoys-cli.html</guid><link>https://krymtkts.github.io/posts/2026-01-25-try-to-use-powertoys-cli.html</link><title>PowerToys CLI を使ってみる</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://devblogs.microsoft.com/commandline/powertoys-0-97-is-here-a-big-command-palette-update-and-a-new-mouse-utility/&quot; title=&quot;PowerToys 0.97 is here: a big Command Palette update and a new mouse utility - Windows Command Line&quot;&gt;PowerToys 0.97 is here: a big Command Palette update and a new mouse utility - Windows Command Line&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the last release we added CLI support for Peek, and we’re expanding that even further. FancyZones, Image Resizer, and File Locksmith can now all be controlled from the command line. Whether you want to switch layouts, resize a batch of images, or unlock files, it’s all possible through the CLI. Be sure to check the docs for the full list of supported commands.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;どうも Fancy Zones とかを CLI 経由で呼べるようになったぽいのよね。想像通りであれば起動 script として有用なのか判断するため調査したい。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/powertoys/fancyzones#command-line-reference&quot; title=&quot;FancyZones Window Manager for Windows - PowerToys | Microsoft Learn&quot;&gt;FancyZones Window Manager for Windows - PowerToys | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/powertoys/file-locksmith#command-line-reference&quot; title=&quot;File Locksmith Utility for Windows - PowerToys | Microsoft Learn&quot;&gt;File Locksmith Utility for Windows - PowerToys | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/powertoys/image-resizer#command-line-reference&quot; title=&quot;Image Resizer utility for Windows - PowerToys | Microsoft Learn&quot;&gt;Image Resizer utility for Windows - PowerToys | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/powertoys/peek#use-peek-from-the-command-line&quot; title=&quot;PowerToys Peek Utility - Preview Files Without Opening Apps | Microsoft Learn&quot;&gt;PowerToys Peek Utility - Preview Files Without Opening Apps | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;調べてみたら 0.97.0 から CLI 専用の実行ファイル &lt;code&gt;FancyZoneCli.exe&lt;/code&gt; &lt;code&gt;FileLocksmithCLI.exe&lt;/code&gt; が生えて、それを経由して使えるってことみたい。
&lt;code&gt;PowerToys.ImageResizerCLI.exe&lt;/code&gt; と &lt;code&gt;PowerToys.Peek.UI.exe&lt;/code&gt; は見当たらなかった。使ってないからなのか、謎。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; ll &lt;span class=&quot;hljs-variable&quot;&gt;$env:ProgramFiles&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-filter&lt;/span&gt; *powertoys* | ll &lt;span class=&quot;hljs-literal&quot;&gt;-Filter&lt;/span&gt; *CLI.exe&lt;br /&gt;&lt;br /&gt;        Directory: C:\Program Files\PowerToys&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Mode                LastWriteTime         Length Name&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                &lt;span class=&quot;hljs-literal&quot;&gt;-------------&lt;/span&gt;         &lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-a---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2026&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-19&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;12&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;07&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;166984&lt;/span&gt; 󿬔  FancyZonesCLI.exe&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-a---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2026&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-19&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;12&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;07&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;726560&lt;/span&gt; 󿬔  FileLocksmithCLI.exe
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;因みに上記 &lt;code&gt;ll&lt;/code&gt; を &lt;code&gt;Get-ChildItem&lt;/code&gt; の alias にしてる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Alias&lt;/span&gt; ll&lt;br /&gt;&lt;br /&gt;CommandType     Name                                               Version    Source&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-----------&lt;/span&gt;     &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                                               &lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;    &lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt;&lt;br /&gt;Alias           ll -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;場所はわかったが、ここには大量のファイルがあるので &lt;code&gt;Path&lt;/code&gt; を通したくない感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; ll &lt;span class=&quot;hljs-variable&quot;&gt;$env:ProgramFiles&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-filter&lt;/span&gt; *powertoys* | ll | &lt;span class=&quot;hljs-built_in&quot;&gt;measure&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Count             : &lt;span class=&quot;hljs-number&quot;&gt;703&lt;/span&gt;&lt;br /&gt;Average           :&lt;br /&gt;Sum               :&lt;br /&gt;Maximum           :&lt;br /&gt;Minimum           :&lt;br /&gt;StandardDeviation :&lt;br /&gt;Property          :
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ひとまず &lt;code&gt;cd&lt;/code&gt; して使ってみることにする。
早速 Fancy Zones を試す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; ./FancyZonesCLI &lt;span class=&quot;hljs-literal&quot;&gt;--help&lt;/span&gt;&lt;br /&gt;FancyZones &lt;span class=&quot;hljs-built_in&quot;&gt;CLI&lt;/span&gt; - Command line interface &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; FancyZones&lt;br /&gt;&lt;br /&gt;Usage: FancyZonesCLI [&lt;span class=&quot;hljs-type&quot;&gt;command&lt;/span&gt;] [&lt;span class=&quot;hljs-type&quot;&gt;options&lt;/span&gt;]&lt;br /&gt;&lt;br /&gt;Options:&lt;br /&gt;&lt;br /&gt;Commands:&lt;br /&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;open-editor&lt;/span&gt;, e                 Launch FancyZones layout editor&lt;br /&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;get-monitors&lt;/span&gt;, m                List monitors and FancyZones metadata&lt;br /&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;get-layouts&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt;                List available layouts&lt;br /&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;get-active&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-layout&lt;/span&gt;, active      Show currently active layout&lt;br /&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;set-layout&lt;/span&gt; &amp;lt;layout&amp;gt;, s         &lt;span class=&quot;hljs-built_in&quot;&gt;Set&lt;/span&gt; layout by UUID or template name&lt;br /&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;open-settings&lt;/span&gt;, settings        Open FancyZones settings page&lt;br /&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;get-hotkeys&lt;/span&gt;, hk                List all layout hotkeys&lt;br /&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;set-hotkey&lt;/span&gt; &amp;lt;key&amp;gt; &amp;lt;layout&amp;gt;, shk Assign hotkey (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-9&lt;/span&gt;) to a custom layout&lt;br /&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;remove-hotkey&lt;/span&gt; &amp;lt;key&amp;gt;, rhk       Remove hotkey assignment&lt;br /&gt;&lt;br /&gt;Examples:&lt;br /&gt;  FancyZonesCLI &lt;span class=&quot;hljs-literal&quot;&gt;--help&lt;/span&gt;&lt;br /&gt;  FancyZonesCLI &lt;span class=&quot;hljs-literal&quot;&gt;--version&lt;/span&gt;&lt;br /&gt;  FancyZonesCLI &lt;span class=&quot;hljs-built_in&quot;&gt;get-monitors&lt;/span&gt;&lt;br /&gt;  FancyZonesCLI &lt;span class=&quot;hljs-built_in&quot;&gt;set-layout&lt;/span&gt; focus&lt;br /&gt;  FancyZonesCLI &lt;span class=&quot;hljs-built_in&quot;&gt;set-layout&lt;/span&gt; &amp;lt;uuid&amp;gt; &lt;span class=&quot;hljs-literal&quot;&gt;--monitor&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;  FancyZonesCLI &lt;span class=&quot;hljs-built_in&quot;&gt;get-hotkeys&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;参照系だけ使ってみるか。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; ./FancyZonesCLI &lt;span class=&quot;hljs-built_in&quot;&gt;get-layouts&lt;/span&gt;&lt;br /&gt;=== Built&lt;span class=&quot;hljs-operator&quot;&gt;-in&lt;/span&gt; Template Layouts (&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt; total) ===&lt;br /&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;T1&lt;/span&gt;] blank&lt;br /&gt;    Zones: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    Visual Preview:&lt;br /&gt;    (No zones)&lt;br /&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;T2&lt;/span&gt;] focus&lt;br /&gt;    Zones: &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    Visual Preview:&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;+&lt;br /&gt;    |       |&lt;br /&gt;    | +&lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;+&lt;br /&gt;    +-|       |&lt;br /&gt;      | +&lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;+&lt;br /&gt;      +-|       |&lt;br /&gt;        ...&lt;br /&gt;        (total: &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt; zones)&lt;br /&gt;        ...&lt;br /&gt;        | +&lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;+&lt;br /&gt;        +-|       |&lt;br /&gt;          |       |&lt;br /&gt;          +&lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;+&lt;br /&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;T3&lt;/span&gt;] columns&lt;br /&gt;    Zones: &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;, Spacing: &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;px&lt;br /&gt;&lt;br /&gt;    Visual Preview:&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;br /&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;T4&lt;/span&gt;] rows&lt;br /&gt;    Zones: &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;, Spacing: &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;px&lt;br /&gt;&lt;br /&gt;    Visual Preview:&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;-----------------------------&lt;/span&gt;+&lt;br /&gt;    |                             |&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;-----------------------------&lt;/span&gt;+&lt;br /&gt;    |                             |&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;-----------------------------&lt;/span&gt;+&lt;br /&gt;    |                             |&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;-----------------------------&lt;/span&gt;+&lt;br /&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;T5&lt;/span&gt;] grid&lt;br /&gt;    Zones: &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    Visual Preview:&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;--------------&lt;/span&gt;+&lt;span class=&quot;hljs-literal&quot;&gt;--------------&lt;/span&gt;+&lt;br /&gt;    |              |              |&lt;br /&gt;    |              |              |&lt;br /&gt;    |              |              |&lt;br /&gt;    |              |              |&lt;br /&gt;    |              |              |&lt;br /&gt;    |              |              |&lt;br /&gt;    |              |              |&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;--------------&lt;/span&gt;+&lt;span class=&quot;hljs-literal&quot;&gt;--------------&lt;/span&gt;+&lt;br /&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;T6&lt;/span&gt;] priority&lt;span class=&quot;hljs-literal&quot;&gt;-grid&lt;/span&gt;&lt;br /&gt;    Zones: &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;, Spacing: &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;px&lt;br /&gt;&lt;br /&gt;    Visual Preview:&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    |         |         |         |&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;+&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;=== Custom Layouts (&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; total) ===&lt;br /&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] Cockpit&lt;br /&gt;    UUID: {&lt;span class=&quot;hljs-number&quot;&gt;04599&lt;/span&gt;F6F&lt;span class=&quot;hljs-literal&quot;&gt;-0BB0-46DF-9809-2E631E026DBC&lt;/span&gt;}&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Type&lt;/span&gt;: grid (&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;x2 grid)&lt;br /&gt;&lt;br /&gt;    Visual Preview:&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;---------------------------------------&lt;/span&gt;+&lt;br /&gt;    |                   |                  |&lt;br /&gt;    |                   |                  |&lt;br /&gt;    |                   |                  |&lt;br /&gt;    |                   |                  |&lt;br /&gt;    |                   |                  |&lt;br /&gt;    |                   |                  |&lt;br /&gt;    |                   |                  |&lt;br /&gt;    |                   |                  |&lt;br /&gt;    |                   |                  |&lt;br /&gt;    |                   |                  |&lt;br /&gt;    |                   |                  |&lt;br /&gt;    |                   |                  |&lt;br /&gt;    +&lt;span class=&quot;hljs-literal&quot;&gt;---------------------------------------&lt;/span&gt;+&lt;br /&gt;&lt;br /&gt;Use &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;FancyZonesCLI.exe set-layout &amp;lt;UUID&amp;gt;&amp;#x27;&lt;/span&gt; to apply a layout.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ほー。なんか人間が目で見て判断する系の出力してる。自動化には向かなそう。
(Monitor Instance と Serial Number 等、一部の情報は伏せる)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; ./FancyZonesCLI &lt;span class=&quot;hljs-built_in&quot;&gt;get-monitors&lt;/span&gt;&lt;br /&gt;=== Monitors (&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; total) ===&lt;br /&gt;&lt;br /&gt;Monitor &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:&lt;br /&gt;  Monitor: SHP1493&lt;br /&gt;  Monitor Instance: XXXXXXXXXXXXXXXXXXXXXX&lt;br /&gt;  Monitor Number: &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;  Serial Number: XXXXXXXXXXXX&lt;br /&gt;  Virtual Desktop: {XXXXXXXX&lt;span class=&quot;hljs-literal&quot;&gt;-XXXX-XXXX-XXXX-XXXXXXXXXXXX&lt;/span&gt;}&lt;br /&gt;  DPI: &lt;span class=&quot;hljs-number&quot;&gt;192&lt;/span&gt;&lt;br /&gt;  Resolution: &lt;span class=&quot;hljs-number&quot;&gt;1600&lt;/span&gt;x900&lt;br /&gt;  Work Area: &lt;span class=&quot;hljs-number&quot;&gt;1600&lt;/span&gt;x900&lt;br /&gt;  Position: (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;br /&gt;  Selected: False&lt;br /&gt;&lt;br /&gt;  Active Layout: blank&lt;br /&gt;  Zone Count: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;  Sensitivity Radius: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;px&lt;br /&gt;  Layout UUID: {&lt;span class=&quot;hljs-number&quot;&gt;2205&lt;/span&gt;FD22&lt;span class=&quot;hljs-literal&quot;&gt;-B38D-4BA9-9550-2E59F6298B91&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;Monitor &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;:&lt;br /&gt;  Monitor: DELA0F4&lt;br /&gt;  Monitor Instance: XXXXXXXXXXXXXXXXXXXXXX&lt;br /&gt;  Monitor Number: &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;  Serial Number: XXXXXXXXXXXX&lt;br /&gt;  Virtual Desktop: {XXXXXXXX&lt;span class=&quot;hljs-literal&quot;&gt;-XXXX-XXXX-XXXX-XXXXXXXXXXXX&lt;/span&gt;}&lt;br /&gt;  DPI: &lt;span class=&quot;hljs-number&quot;&gt;96&lt;/span&gt;&lt;br /&gt;  Resolution: &lt;span class=&quot;hljs-number&quot;&gt;3840&lt;/span&gt;x1600&lt;br /&gt;  Work Area: &lt;span class=&quot;hljs-number&quot;&gt;3840&lt;/span&gt;x1600&lt;br /&gt;  Position: (&lt;span class=&quot;hljs-literal&quot;&gt;-332&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot;&gt;-1600&lt;/span&gt;)&lt;br /&gt;  Selected: True&lt;br /&gt;&lt;br /&gt;  Active Layout: custom&lt;br /&gt;  Zone Count: &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;br /&gt;  Sensitivity Radius: &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;px&lt;br /&gt;  Layout UUID: {&lt;span class=&quot;hljs-number&quot;&gt;04599&lt;/span&gt;F6F&lt;span class=&quot;hljs-literal&quot;&gt;-0BB0-46DF-9809-2E631E026DBC&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; ./FancyZonesCLI &lt;span class=&quot;hljs-built_in&quot;&gt;get-active&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-layout&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;=== Active FancyZones Layout(s) ===&lt;br /&gt;&lt;br /&gt;Monitor &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;: SHP1493&lt;br /&gt;  Layout UUID: {&lt;span class=&quot;hljs-number&quot;&gt;2205&lt;/span&gt;FD22&lt;span class=&quot;hljs-literal&quot;&gt;-B38D-4BA9-9550-2E59F6298B91&lt;/span&gt;}&lt;br /&gt;  Layout &lt;span class=&quot;hljs-built_in&quot;&gt;Type&lt;/span&gt;: blank&lt;br /&gt;  Zone Count: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;  Sensitivity Radius: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;px&lt;br /&gt;&lt;br /&gt;Monitor &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;: DELA0F4&lt;br /&gt;  Layout UUID: {&lt;span class=&quot;hljs-number&quot;&gt;04599&lt;/span&gt;F6F&lt;span class=&quot;hljs-literal&quot;&gt;-0BB0-46DF-9809-2E631E026DBC&lt;/span&gt;}&lt;br /&gt;  Layout &lt;span class=&quot;hljs-built_in&quot;&gt;Type&lt;/span&gt;: custom&lt;br /&gt;  Zone Count: &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;br /&gt;  Spacing: &lt;span class=&quot;hljs-literal&quot;&gt;-1px&lt;/span&gt;&lt;br /&gt;  Sensitivity Radius: &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;px
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; ./FancyZonesCLI &lt;span class=&quot;hljs-built_in&quot;&gt;get-hotkeys&lt;/span&gt;&lt;br /&gt;=== Layout Hotkeys ===&lt;br /&gt;&lt;br /&gt;Press Win + Ctrl + Alt + &amp;lt;number&amp;gt; to &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; layouts:&lt;br /&gt;&lt;br /&gt;  [&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] =&amp;gt; {&lt;span class=&quot;hljs-number&quot;&gt;04599&lt;/span&gt;F6F&lt;span class=&quot;hljs-literal&quot;&gt;-0BB0-46DF-9809-2E631E026DBC&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;わたしの想像力が欠如してるのかも知れんが、これいまだとできることあんまないなという感じがした。
指定の window を layout 内の何番の位置に飛ばすとかができたらいいかなと思ってたのだけど、そういうのは今ないみたい。
個人的には UWQHD 使ってるのもあり Fancy Zones の使い方として起動後に layout を切り替えることもないから、今提供されている CLI 機能はほぼ使わんな。
そういう細かな位置の調整は起動時に Workspaces でやってくれよってことなんかな。なんかいまいち同一アプリ複数 window を使いこなせなくて使ってないねんよな Workspaces 。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;File Locksmith も見てみる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; ./FileLocksmithCLI &lt;span class=&quot;hljs-literal&quot;&gt;--help&lt;/span&gt;&lt;br /&gt;Usage: FileLocksmithCLI.exe [&lt;span class=&quot;hljs-type&quot;&gt;options&lt;/span&gt;] &amp;lt;path1&amp;gt; [&lt;span class=&quot;hljs-type&quot;&gt;path2&lt;/span&gt;] ...&lt;br /&gt;Options:&lt;br /&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;--kill&lt;/span&gt;      &lt;span class=&quot;hljs-built_in&quot;&gt;Kill&lt;/span&gt; processes locking the files&lt;br /&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;--json&lt;/span&gt;      Output results &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; JSON format&lt;br /&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;--wait&lt;/span&gt;      Wait &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; files to be unlocked&lt;br /&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;--timeout&lt;/span&gt;   Timeout &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; milliseconds &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--wait&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;--help&lt;/span&gt;      Show this help message
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コッチは subcommand 形式じゃないんかい。
でも &lt;code&gt;--json&lt;/code&gt; があるお陰で使いやすくはあるか。
試しに、 Desktop に転がってた PDF を開いて lock の状況を出してみる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; ./FileLocksmithCLI ~/OneDrive/Desktop/sample.pdf &lt;span class=&quot;hljs-literal&quot;&gt;--json&lt;/span&gt;&lt;br /&gt;{&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;processes&amp;quot;&lt;/span&gt;:[{&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;pid&amp;quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;3100&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Acrobat.exe&amp;quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;user&amp;quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;takatoshi&amp;quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;files&amp;quot;&lt;/span&gt;:[&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;C:\\Users\\takatoshi\\OneDrive\\Desktop\\sample.pdf&amp;quot;&lt;/span&gt;]}]}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; ./FileLocksmithCLI C:\Users\takatoshi\OneDrive\Desktop\sample.pdf &lt;span class=&quot;hljs-literal&quot;&gt;--json&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-Json&lt;/span&gt; | % processes&lt;br /&gt;&lt;br /&gt; pid name        user      files&lt;br /&gt; &lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;        &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;      &lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;3100&lt;/span&gt; Acrobat.exe takatoshi {C:\Users\takatoshi\OneDrive\Desktop\sample.pdf}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;File Locksmith は Fancy Zones に比べて楽に PowerShell と連携できそう。
ただ普段 File Locksmith のお世話にあんまならんからそんなに使わないだろうな。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;取り敢えずざっと見てみてすぐ使いそうなものはないかな～という感覚は得た。
autocomplete を出力する option なんかもないから、使うなら自前で補助してやる必要がある。
ひとまずは適当な wrapper function を PowerShell の profile に仕込んでおくとかはやってもいいかもな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 25 Jan 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-01-18-connect-gnupg-and-gpg4wing.html</guid><link>https://krymtkts.github.io/posts/2026-01-18-connect-gnupg-and-gpg4wing.html</link><title>Windows の GnuPG と Gpg4Win の連携</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;つい先日 &lt;code&gt;git commit&lt;/code&gt; したとき &lt;a href=&quot;https://www.gnupg.org/&quot; title=&quot;GnuPG&quot;&gt;GnuPG&lt;/a&gt; での commit sign が通らなくなったので、その解消方法をログに残す。&lt;/p&gt;
&lt;p&gt;まず前提を整理する。
実際のところ commit sign するだけなら GnuPG だけでも良い。
けど、 passphrase を入力する window が味気なく masking 解除できないのも好かんので、 &lt;a href=&quot;https://www.gpg4win.org/&quot; title=&quot;Gpg4Win&quot;&gt;Gpg4Win&lt;/a&gt; の &lt;code&gt;pinentry.exe&lt;/code&gt; を使ってた。
理想は &lt;code&gt;pinentry-mode loopback&lt;/code&gt; で CLI 入力するのが好きだ。
ただ &lt;a href=&quot;https://code.visualstudio.com/&quot; title=&quot;Visual Studio Code&quot;&gt;Visual Studio Code&lt;/a&gt; と一緒に使うと支障があり、 Gpg4Win の &lt;code&gt;pinentry.exe&lt;/code&gt; に落ち着いてた。&lt;/p&gt;
&lt;p&gt;GnuPG と Gpg4Win はそれぞれ &lt;a href=&quot;https://chocolatey.org/&quot; title=&quot;Chocolatey&quot;&gt;Chocolatey&lt;/a&gt; で入れてる。
初回 install は以下のような感じだ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;choco install gnupg gpg4win
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この構成で使っていて、まず年末年始頃に &lt;code&gt;choco upgrade all -y&lt;/code&gt; したあと commit sign できなくなった。
細かく調べてないが、どうも GnuPG 2.5 系になったため GPG の path が変わったからっぽい。&lt;/p&gt;
&lt;p&gt;そのため &lt;code&gt;~/.gitconfig&lt;/code&gt; で指定する &lt;code&gt;gpg&lt;/code&gt; の path を変更する必要があった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;hljs-section&quot;&gt;[gpg]&lt;/span&gt;&lt;br /&gt;&amp;emsp;&lt;span class=&quot;hljs-comment&quot;&gt;# program = C:\\Program Files (x86)\\gnupg\\bin\\gpg.exe&lt;/span&gt;&lt;br /&gt;&amp;emsp;&lt;span class=&quot;hljs-attr&quot;&gt;program&lt;/span&gt; = C:/Program Files/GnuPG/bin/gpg.exe
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;それでも以下のように sign できなかった。 &lt;code&gt;FC536D8DE73F2424&lt;/code&gt; は GitHub で使ってるわたしの GPG Key ID だ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Add a new post&amp;#x27;&lt;/span&gt;&lt;br /&gt;error: gpg failed to sign the &lt;span class=&quot;hljs-keyword&quot;&gt;data&lt;/span&gt;:&lt;br /&gt;gpg: skipped &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;FC536D8DE73F2424&amp;quot;&lt;/span&gt;: No secret key&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;GNUPG&lt;/span&gt;:] INV_SGNR &lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt; FC536D8DE73F2424&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;GNUPG&lt;/span&gt;:] FAILURE sign &lt;span class=&quot;hljs-number&quot;&gt;17&lt;/span&gt;&lt;br /&gt;gpg: signing failed: No secret key&lt;br /&gt;fatal: failed to &lt;span class=&quot;hljs-built_in&quot;&gt;write&lt;/span&gt; commit object
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;今思えば Gpg4Win が GnuPG 2.5 系に追いついてなかったからなのだろうけど、 &lt;code&gt;pinentry.exe&lt;/code&gt; が見つからなくなってるってのまでは理解できた。
なので &lt;code&gt;gpg-agent.conf&lt;/code&gt; で &lt;code&gt;pinentry.exe&lt;/code&gt; が見つかるように指定してやれば解消できる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$env:APPDATA&lt;/span&gt;/gnupg/gpg&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;.conf
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;default-cache-ttl 86400&lt;br /&gt;max-cache-ttl 86400&lt;br /&gt;&lt;br /&gt;pinentry-program C:\Program Files (x86)\Gpg4win\bin\pinentry.exe
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで &lt;code&gt;pinentry.exe&lt;/code&gt; が見つかるようになり、 commit sign できるようになった。&lt;/p&gt;
&lt;p&gt;ついでに、今までのように commit 時に passphrase を入力するようにしてたら、 GnuPG と Gpg4Win が繋がらなくなってた時の検知が遅れる。
それは気になるので、 terminal 起動時に passphrase を cache するようにしてみた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Command&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;gpgconf&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; SilentlyContinue) {&lt;br /&gt;    gpgconf &lt;span class=&quot;hljs-literal&quot;&gt;--launch&lt;/span&gt; gpg&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# NOTE: open pinentry for caching passphrase.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;warmup&amp;#x27;&lt;/span&gt; | gpg &lt;span class=&quot;hljs-literal&quot;&gt;--clearsign&lt;/span&gt; *&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで一見落着したかに見えたが、後日 chocolatey で更新したらまた commit sign できなくなった。
今度は Gpg4Win が &lt;a href=&quot;https://gpg4win.org/version-5.0.0.html&quot; title=&quot;5 系&quot;&gt;5 系&lt;/a&gt;に更新されて &lt;code&gt;pinentry.exe&lt;/code&gt; の path が変わったからだ。
&lt;code&gt;Program Files(x86)&lt;/code&gt; から &lt;code&gt;Program Files&lt;/code&gt; に移ったようなので、一旦以下のように変えればいい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;default-cache-ttl 86400&lt;br /&gt;max-cache-ttl 86400&lt;br /&gt;&lt;br /&gt;pinentry-program C:\Program Files\Gpg4win\bin\pinentry.exe
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;gpg-agent&lt;/code&gt; を再起動して passphrase を cache し直せばいつも通りに戻る。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;gpgconf &lt;span class=&quot;hljs-literal&quot;&gt;--kill&lt;/span&gt; gpg&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;&lt;br /&gt;gpgconf &lt;span class=&quot;hljs-literal&quot;&gt;--launch&lt;/span&gt; gpg&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;warmup&amp;#x27;&lt;/span&gt; | gpg &lt;span class=&quot;hljs-literal&quot;&gt;--clearsign&lt;/span&gt; *&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ただこれだと &lt;code&gt;pinentry.exe&lt;/code&gt; がどこに存在するかいちいちチェックしないといけない。
なので PC 乗り換えのときに備えて &lt;code&gt;gpg-agent.conf&lt;/code&gt; を更新するときに使う自前関数を更新し、 x86 でも x64 でも見つかるように修正した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;global&lt;/span&gt;:&lt;span class=&quot;hljs-title&quot;&gt;Set-GPGConfig&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$pinentryPath&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{env:ProgramFiles}, &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{env:ProgramFiles(x86)} | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{_}\Gpg4win\bin\pinentry.exe&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt;) {&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;pinentry-program &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{path}&amp;quot;&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;    } | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt; } | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-First&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;@&amp;quot;&lt;br /&gt;default-cache-ttl 86400&lt;br /&gt;max-cache-ttl 86400&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$pinentryPath&lt;/span&gt;&lt;br /&gt;&amp;quot;@&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$env:APPDATA&lt;/span&gt;/gnupg/gpg-agent.conf&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# currently unused.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;@&amp;#x27;&lt;br /&gt;# loopback is not work with VS Code.&lt;br /&gt;# VS Code hang up if you commit with signing.&lt;br /&gt;# pinentry-mode loopback&lt;br /&gt;&amp;#x27;@&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$env:APPDATA&lt;/span&gt;/gnupg/gpg.conf&amp;quot;&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで一通り整った。&lt;/p&gt;
&lt;p&gt;そもそも GnuPG と Gpg4Win が別々に入ってる構成が変な気もするので、そこを見直した方がいいのかもな。
なんでこんな構成になってるのかも忘れてしまってるし。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 18 Jan 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-01-11-suave-3-logging-with-serilog.html</guid><link>https://krymtkts.github.io/posts/2026-01-11-suave-3-logging-with-serilog.html</link><title>Suave 3 のアクセスログ出力を Serilog でやる</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2025-12-14-suave-3.html&quot; title=&quot;以前&quot;&gt;以前&lt;/a&gt; &lt;a href=&quot;https://github.com/SuaveIO/suave&quot; title=&quot;Suave&quot;&gt;Suave&lt;/a&gt; 3 へ更新した際に &lt;code&gt;Suave.Logging&lt;/code&gt; module がなくなった件に触れた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;あと今のところは &lt;code&gt;Logging&lt;/code&gt; module がなくなって &lt;code&gt;logger&lt;/code&gt; が使えなくなってた。
&lt;code&gt;Logging&lt;/code&gt; がなくなったのは読み込まれたファイルのログが出なくなって dev server 的には地味に痛いのだが、ひょっとしたら別の方法で実現できたり復活の可能性もあるので、経過観測する。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;それについて discussion に書かれてるのを見つけた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/SuaveIO/suave/discussions/793#discussioncomment-15252133&quot; title=&quot;v3.1.0 · SuaveIO/suave · Discussion #793&quot;&gt;v3.1.0 · SuaveIO/suave · Discussion #793&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Everything should work pretty much the same way, the API hasn&amp;#39;t changed significantly. For your logging needs you should use an alternative library like Serilog (&lt;a href=&quot;https://serilog.net/&quot; title=&quot;undefined&quot;&gt;https://serilog.net/&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;標準の logger を積まなくなったので &lt;a href=&quot;https://serilog.net/&quot; title=&quot;Serilog&quot;&gt;Serilog&lt;/a&gt; のような logging library を使えばいいらしい。
.NET の logging 事情は知らないので他に何があるか軽く調べた。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/extensions/logging?tabs=command-line&quot; title=&quot;Microsoft.Extensions.Logging&quot;&gt;Microsoft.Extensions.Logging&lt;/a&gt; は標準に寄せるなら強いかなと思ったが、結果的に今は簡単さ重視で Serilog にした。
Serilog でも構造夏ログを使わないのであれば overkill な気がするけど広く使われていて利用も楽なので。
といいつつ今後 Microsoft.Extensions.Logging に乗り換える可能性はある。&lt;/p&gt;
&lt;p&gt;また、 Suave 2 の時と同じような logging をどう実装するかよくわからなかったので GitHub Copilot サンに聞いた。
曰く、 simple にやるなら単に fish operator &lt;code&gt;&amp;gt;=&amp;gt;&lt;/code&gt; で扱える &lt;code&gt;WebPart&lt;/code&gt; を受けて返す関数を作ればいいらしい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Logging &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Serilog&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; logger &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        LoggerConfiguration()&lt;br /&gt;            .MinimumLevel.Debug()&lt;br /&gt;            .WriteTo.Console(&lt;br /&gt;                outputTemplate &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Level:u3}] {Message:lj}{NewLine}{Exception}&amp;quot;&lt;/span&gt;&lt;br /&gt;            )&lt;br /&gt;            .CreateLogger()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; log (logger&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; ILogger) &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; WebPart &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; ctx &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;async&lt;/span&gt; {&lt;br /&gt;                logger.Information(&lt;br /&gt;                    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;HTTP {Method} {Path} -&amp;gt; {Status} {Reason}&amp;quot;&lt;/span&gt;,&lt;br /&gt;                    ctx.request.&lt;span class=&quot;hljs-variable&quot;&gt;``method``&lt;/span&gt;.ToString(),&lt;br /&gt;                    ctx.request.rawPath,&lt;br /&gt;                    ctx.response.status.code,&lt;br /&gt;                    ctx.response.status.reason&lt;br /&gt;                )&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt; ctx&lt;br /&gt;            }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このような薄い module を拵えた。
依存関係には &lt;a href=&quot;https://www.nuget.org/packages/Serilog/&quot; title=&quot;Serilog&quot;&gt;Serilog&lt;/a&gt; と console 出力の実装である &lt;a href=&quot;https://www.nuget.org/packages/serilog.sinks.console&quot; title=&quot;Serilog.Sinks.Console&quot;&gt;Serilog.Sinks.Console&lt;/a&gt; が要る。
これで以下のように Suave 2 の頃と同じ様な使い方ができる。 Suave 2 利用時と比較するとこんな感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    let logger = Logging.Log.create &amp;quot;dev-server&amp;quot; // Suave 2 はこう&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     choose [&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        path &amp;quot;/websocket&amp;quot; &amp;gt;=&amp;gt; handShake socketHandler&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        path &amp;quot;/sse&amp;quot; &amp;gt;=&amp;gt; EventSource.handShake sseHandler &amp;gt;=&amp;gt; Logging.log Logging.logger&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;         GET&lt;br /&gt;         &amp;gt;=&amp;gt; Writers.setHeader &amp;quot;Cache-Control&amp;quot; &amp;quot;no-cache, no-store, must-revalidate&amp;quot;&lt;br /&gt;         &amp;gt;=&amp;gt; Writers.setHeader &amp;quot;Pragma&amp;quot; &amp;quot;no-cache&amp;quot;&lt;br /&gt;         &amp;gt;=&amp;gt; Writers.setHeader &amp;quot;Expires&amp;quot; &amp;quot;0&amp;quot;&lt;br /&gt;         &amp;gt;=&amp;gt; choose [&lt;br /&gt;&lt;br /&gt;             path $&amp;quot;/{root}/&amp;quot; &amp;gt;=&amp;gt; Files.browseFileHome $&amp;quot;{root}/index.html&amp;quot;&lt;br /&gt;             path $&amp;quot;/{root}&amp;quot; &amp;gt;=&amp;gt; Redirection.redirect $&amp;quot;/{root}/&amp;quot;&lt;br /&gt;&lt;br /&gt;             Files.browseHome&lt;br /&gt;&lt;br /&gt;         ]&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        &amp;gt;=&amp;gt; log logger logFormat // Suave 2 はこう&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        &amp;gt;=&amp;gt; Logging.log Logging.logger&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;         Writers.setStatus HTTP_404&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        &amp;gt;=&amp;gt; logWithLevel Logging.Error logger logFormat // Suave 2 はこう&lt;/span&gt;&lt;br /&gt;         &amp;gt;=&amp;gt; choose [&lt;br /&gt;             Files.browseFileHome $&amp;quot;{root}/404.html&amp;quot;&lt;br /&gt;             RequestErrors.NOT_FOUND &amp;quot;404 - Not Found&amp;quot; // NOTE: Fallback 404 page.&lt;br /&gt;         ]&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        &amp;gt;=&amp;gt; Logging.log Logging.logger // TODO: ログレベルを指定できるようにする&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この日記を書いてる最中にログレベル指定の対応忘れてるなと気付いたので後でやる。
こんな感じのログ出力になる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;[2026-01-11 12:30:30.091 INF] HTTP GET /index.html -&amp;gt; 200 OK&lt;br /&gt;[2026-01-11 12:30:30.189 INF] HTTP GET /pagefind/pagefind-ui.css -&amp;gt; 200 OK&lt;br /&gt;[2026-01-11 12:30:30.198 INF] HTTP GET /css/style.css -&amp;gt; 200 OK&lt;br /&gt;[2026-01-11 12:30:30.211 INF] HTTP GET /css/solarized-dark.min.css -&amp;gt; 200 OK&lt;br /&gt;[2026-01-11 12:30:30.231 INF] HTTP GET /pagefind/pagefind-ui.js -&amp;gt; 200 OK&lt;br /&gt;[2026-01-11 12:30:30.257 INF] HTTP GET /js/dev.js -&amp;gt; 200 OK&lt;br /&gt;[2026-01-11 12:30:30.274 INF] HTTP GET /js/handler.js -&amp;gt; 200 OK&lt;br /&gt;[2026-01-11 12:30:30.741 INF] HTTP GET /sse -&amp;gt; 200 OK
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これでひとまず dev server のアクセスログも復活できて Suave 2 の頃と同様な使用感になった。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 11 Jan 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-01-04-powershell-preview.html</guid><link>https://krymtkts.github.io/posts/2026-01-04-powershell-preview.html</link><title>PowerShell Preview を使い始めた - PowerShell 7.6.0-preview.6</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;刺激を求めて PowerShell の Preview(&lt;a href=&quot;https://github.com/PowerShell/PowerShell/releases/tag/v7.6.0-preview.6&quot; title=&quot;v7.6.0-preview.6&quot;&gt;v7.6.0-preview.6&lt;/a&gt;) を使うように変えた。
CLI での install には &lt;a href=&quot;https://community.chocolatey.org/packages/powershell-core/7.6.0-preview06&quot; title=&quot;Chocolatey&quot;&gt;Chocolatey&lt;/a&gt; か &lt;a href=&quot;https://learn.microsoft.com/ja-jp/powershell/scripting/install/install-powershell-on-windows?view=powershell-7.6#install-powershell-using-winget-recommended&quot; title=&quot;WinGet&quot;&gt;WinGet&lt;/a&gt; が使える。
ただ Chocolatey では prerelease で提供されてるので &lt;a href=&quot;https://docs.chocolatey.org/en-us/choco/commands/pin/&quot; title=&quot;&lt;code&gt;choco pin&lt;/code&gt;&quot;&gt;&lt;code&gt;choco pin&lt;/code&gt;&lt;/a&gt; してないと &lt;a href=&quot;https://docs.chocolatey.org/en-us/choco/commands/upgrade/&quot; title=&quot;&lt;code&gt;choco upgrade all&lt;/code&gt;&quot;&gt;&lt;code&gt;choco upgrade all&lt;/code&gt;&lt;/a&gt; すると stable に落ちてしまう。
これは面倒なので今回は winget を使うようにした。
install したときは PowerShell 7.6.0-preview.5 までしか winget の community repo に存在しなかった。
でもタイミングよくすぐ更新されて PowerShell 7.6.0-preview.6 が降ってきた。
以下のコマンドを実行すればよい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;winget install &lt;span class=&quot;hljs-literal&quot;&gt;--id&lt;/span&gt; Microsoft.PowerShell.Preview
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あと &lt;a href=&quot;https://github.com/microsoft/terminal&quot; title=&quot;Windows Terminal&quot;&gt;Windows Terminal&lt;/a&gt; でも &lt;a href=&quot;https://docs.github.com/en/copilot/how-tos/chat-with-copilot/chat-in-windows-terminal&quot; title=&quot;GitHub Copilot Chat&quot;&gt;GitHub Copilot Chat&lt;/a&gt; が使いたくて &lt;a href=&quot;https://github.com/microsoft/terminal?tab=readme-ov-file#installing-windows-terminal-canary&quot; title=&quot;Canary&quot;&gt;Canary&lt;/a&gt; に変えた。
これは仕事用の PC では既に切り替えてあるので、そちらと合わせる意味もある。
変えてからあんまり積極的に Windows Terminal で GitHub Copilot Chat を使ってるわけではないけど、いつも質問できる安心感的なのを得るためだ。&lt;/p&gt;
&lt;p&gt;Windows Terminal Canary は chocolatey や winget では入れられない。
なので自前で installer を download して起動するよう関数を profile に用意してる。
いま単に installer を起動するだけにしてるが、どうも &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/appx/add-appxpackage?view=windowsserver2025-ps&quot; title=&quot;&lt;code&gt;Add-AppxPackage&lt;/code&gt;&quot;&gt;&lt;code&gt;Add-AppxPackage&lt;/code&gt;&lt;/a&gt; が使えるみたい。
それができたら installer の削除まで一貫して行えるので、次回試してみたい。コメントアウトしてるところがそれだ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Install-WindowsTerminalCanary&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$installer&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Microsoft.WindowsTerminalCanary.appinstaller&amp;#x27;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://aka.ms/terminal-canary-installer&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-OutFile&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Microsoft.WindowsTerminalCanary.appinstaller&amp;#x27;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Start-Process&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$installer&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# try {&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;#     Add-AppxPackage -AppInstallerFile $installer&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# }&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# finally {&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;#     Remove-Item $installer -Force -ErrorAction SilentlyContinue&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# }&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;PowerShell Preview に入れ替えたら、 Windows Terminal の profile にちょっと工夫が必要だった。
PowerShell の stable を入れてたときは &lt;code&gt;&amp;quot;source&amp;quot;: &amp;quot;Windows.Terminal.PowershellCore&amp;quot;&lt;/code&gt; だけで Preview を使えてた。
けど stable を消したら認識しなくなってしまった。なので個別に指定する必要があるみたい。
以下は GUI から操作して生成させたものなので、ひょっとしたら公式かどっかに落ちてる情報なのかな。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;            &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;colorScheme&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Solarized Dark - Patched&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;guid&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{a3a2e83a-884a-5379-baa8-16f193a13b21}&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;hidden&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;PowerShell 7 Preview&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-comment&quot;&gt;// &amp;quot;source&amp;quot;: &amp;quot;Windows.Terminal.PowershellCore&amp;quot;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;commandline&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\&amp;quot;C:\\Program Files\\PowerShell\\7-preview\\pwsh.exe\&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;icon&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ms-appx:///ProfileIcons/pwsh-preview.png&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;startingDirectory&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;%USERPROFILE%&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;tabColor&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#001E27&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Preview に入れ替えたせいか知らんが &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/get-experimentalfeature?view=powershell-7.6&quot; title=&quot;&lt;code&gt;Get-ExperimentalFeature&lt;/code&gt;&quot;&gt;&lt;code&gt;Get-ExperimentalFeature&lt;/code&gt;&lt;/a&gt; の出力が変わったような。最近見てなかったから定かではない。
これまで更新してきた分の残骸かな？&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ExperimentalFeature&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Format-List&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Name        : PSLoadAssemblyFromNativeCode&lt;br /&gt;Enabled     : True&lt;br /&gt;Source      : PSEngine&lt;br /&gt;Description : Expose an API to allow assembly loading from native code&lt;br /&gt;&lt;br /&gt;Name        : PSProfileDSCResource&lt;br /&gt;Enabled     : False&lt;br /&gt;Source      : PSEngine&lt;br /&gt;Description : DSC v3 resources &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; managing PowerShell profile.&lt;br /&gt;&lt;br /&gt;Name        : PSSerializeJSONLongEnumAsNumber&lt;br /&gt;Enabled     : True&lt;br /&gt;Source      : PSEngine&lt;br /&gt;Description : Serialize enums based on long or ulong as an numeric value rather than the string&lt;br /&gt;              representation when &lt;span class=&quot;hljs-keyword&quot;&gt;using&lt;/span&gt; ConvertTo-Json.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;いま &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_config?view=powershell-7.6&quot; title=&quot;&lt;code&gt;powershell.config.json&lt;/code&gt;&quot;&gt;&lt;code&gt;powershell.config.json&lt;/code&gt;&lt;/a&gt; に入ってるものは以下(整形済み)だった。随分多いな。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;ExperimentalFeatures&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;PSFeedbackProvider&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;PSCommandNotFoundSuggestion&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;PSSubsystemPluginModel&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;PSLoadAssemblyFromNativeCode&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;PSNativeWindowsTildeExpansion&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;PSSerializeJSONLongEnumAsNumber&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以下を見るに 7.5, 7.6 で mainstream になった feature が残ってたみたい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/learn/experimental-features?view=powershell-7.6#available-features&quot; title=&quot;Using Experimental Features in PowerShell - PowerShell | Microsoft Learn&quot;&gt;Using Experimental Features in PowerShell - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;experimental からなくなった feature は取り除いておいた。&lt;/p&gt;
&lt;p&gt;最後に winget で管理してる application が増えたので更新のタイミングがわかりやすいよう profile に仕込んでみた。
以下がこれまでに winget で入れるようになったもの。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Microsoft.OpenSSH.Preview&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;Microsoft.PowerShell.Preview&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;Microsoft.VisualStudioCode.Insiders&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Command&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-WinGetPackage&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; SilentlyContinue) {&lt;br /&gt;    &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Microsoft.VisualStudioCode.Insiders&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Microsoft.OpenSSH.Preview&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Microsoft.PowerShell.Preview&amp;#x27;&lt;/span&gt;&lt;br /&gt;    ) | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$pkg&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-WinGetPackage&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Id&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; ((&lt;span class=&quot;hljs-variable&quot;&gt;$pkg&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-and&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$pkg&lt;/span&gt;.IsUpdateAvailable)) {&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Warning&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;💡 Newer &amp;#x27;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{_}&amp;#x27; is available. &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$pkg&lt;/span&gt;.AvailableVersions | Where-Object {&lt;br /&gt;                [version]&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; -gt [version]&lt;span class=&quot;hljs-variable&quot;&gt;$pkg&lt;/span&gt;.InstalledVersion&lt;br /&gt;            } | Sort-Object -Descending | Select-Object -First 1)&amp;quot;&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/Microsoft.WinGet.Client/1.11.460&quot; title=&quot;Microsoft.WinGet.Client&quot;&gt;Microsoft.WinGet.Client&lt;/a&gt; で簡単に操作できるのがありがたい。
パッと見 &lt;code&gt;AvailableVersions&lt;/code&gt; は降順に並ぶようだけど並び替えと絞り込みを入れておいた。
&lt;code&gt;Get-WinGetPackage&lt;/code&gt; が使えるかもチェックしている。&lt;/p&gt;
&lt;p&gt;これで更新があれば PowerShell 起動時にログが出て多分気付ける。
その後の更新は command prompt から手で実行することになる想定。未だに PowerShell 内から PowerShell を更新する良い手順を知らない。&lt;/p&gt;
&lt;p&gt;特に違いも感じずまだ刺激になってないけど、これからは preview を使っていこう。
VS Code も GitHub Copilot の機能をいち早く使うため Insider にしてるし、なんか unstable だれけになりつつある。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;2026-01-11 追記。&lt;/p&gt;
&lt;p&gt;VS Code で PowerShell Extension が利かなくなった。
どうも Preview だけだと &lt;code&gt;pwsh&lt;/code&gt; バイナリが見つからないみたい。
なので設定で直に &lt;code&gt;pwsh&lt;/code&gt; への path を指定してやる必要があった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;powershell.powerShellAdditionalExePaths&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;pwsh-preview&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;C:\\Program Files\\PowerShell\\7-preview\\pwsh.exe&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;powershell.powerShellDefaultVersion&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;pwsh-preview&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description><pubDate>Sun, 11 Jan 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2026-01-01-planning.html</guid><link>https://krymtkts.github.io/posts/2026-01-01-planning.html</link><title>2026</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;例年通り目標をたてる。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;テーマ: 不惑&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;2023 年から続くテーマ、不惑。
わたしの探求は継続の中にこそあるって感じがしてきた。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2026-&quot; href=&quot;#2026-&quot;&gt;2026 年の目標&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;継続目標の強度をすこし上げる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;積読消化 2 冊/月を超える&lt;ul&gt;
&lt;li&gt;2025 年は 1.9 冊/月まできたので、ちょっと負荷を高める。頁数が多い本や難解な本を読み始めたらそれだけで詰みそうだが、そこはバランスとりつつで臨機応変に何とかならんかな。達成できたらこれを標準にしよう&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;F# の開発&lt;ul&gt;
&lt;li&gt;新しいものを最低 1 つ作る&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt;, &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;blog-fable&quot;&gt;blog-fable&lt;/a&gt;, &lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;SnippetPredictor&quot;&gt;SnippetPredictor&lt;/a&gt;, &lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife&quot; title=&quot;PSGameOfLife&quot;&gt;PSGameOfLife&lt;/a&gt; もやる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;GitHub のストリークを継続する&lt;ul&gt;
&lt;li&gt;秋には 1500 に達するので油断せず着実に進める&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;毎週ブログを書く&lt;/li&gt;&lt;li&gt;ギター練習を 5 / week&lt;ul&gt;
&lt;li&gt;毎日コツコツ進めよう&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;深酒で怪我・二日酔いをしない&lt;ul&gt;
&lt;li&gt;怪我だけでなく二日酔いによるパフォーマンス劣化にも注意する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;自分メンテナンス&lt;ul&gt;
&lt;li&gt;仕事にのめり込んでいる日は筋トレメニューを軽くしがちなので、毎日同じように続けるのを目標にしたい&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;仕事は年初から「高難易度だし忙しいけど暇」を解消するためのテコ入れを始めないといけない。
幾つかすぐにやれる案はあるのでぼちぼちやってく。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Thu, 01 Jan 2026 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-12-31-retrospective2025.html</guid><link>https://krymtkts.github.io/posts/2025-12-31-retrospective2025.html</link><title>振り返り 2025 年</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;2025 年を振り返る。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2025-01-01-planning.html&quot; title=&quot;2025 年のテーマ&quot;&gt;2025 年のテーマ&lt;/a&gt;も「不惑」だった。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2025-&quot; href=&quot;#2025-&quot;&gt;2025 年の目標と成果&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;比較的穏やかで順調だった。
今年は妻が万博に熱を上げていたので春～秋にかけて家族一同頻繁に外出してたから、その間の活動は停滞しがちだった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭕️積読消化 1 冊/月を超える&lt;ul&gt;
&lt;li&gt;順調に進んで 2024 年から続いてた 3 冊と 20 冊で 23 冊読めた。内 5 冊は再読。今日で 500 日連続読書になった。やったね&lt;/li&gt;&lt;li&gt;ワインバーグ氏とデマルコ氏の著書はもはや古典だが読んでよかった。古典は良い&lt;/li&gt;&lt;li&gt;輪読会で読んだ&lt;a href=&quot;/booklogs/introduction-to-ethics.html&quot; title=&quot;入門・倫理学&quot;&gt;入門・倫理学&lt;/a&gt;は booklog をつけるのが難しくてやめてしまったがなんとか最後まで読んだ。効率と倫理のバランスはすごく重要な要素と感じている。そのうち一人で読む機会を設けてちゃんと booklog つけるようにしたい&lt;ul&gt;
&lt;li&gt;読了&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/booklogs/wei-wu-zhu-sun-tzu.html&quot; title=&quot;魏武注孫子&quot;&gt;魏武注孫子&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/peering-chronicle-in-japan.html&quot; title=&quot;ピアリング戦記 日本のインターネットを繋ぐ技術者たち&quot;&gt;ピアリング戦記 日本のインターネットを繋ぐ技術者たち&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/what-a-programmer-should-know-about-the-cpu.html&quot; title=&quot;プログラマーのための CPU 入門 CPU は如何にしてソフトウェアを高速に実行するか&quot;&gt;プログラマーのための CPU 入門 CPU は如何にしてソフトウェアを高速に実行するか&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/molecular-cooking-in-japanese-cuisine.html&quot; title=&quot;分子調理の日本食&quot;&gt;分子調理の日本食&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/sous-vide-at-home.html&quot; title=&quot;家庭の低温調理 完璧な食事のためのモダンなテクニックと肉、魚、野菜、デザートのレシ&quot;&gt;家庭の低温調理 完璧な食事のためのモダンなテクニックと肉、魚、野菜、デザートのレシ&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/pickled.html&quot; title=&quot;世界の作りおき野菜 みんなに愛される味付けの魔法&quot;&gt;世界の作りおき野菜 みんなに愛される味付けの魔法&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/pickles-a-global-history.html&quot; title=&quot;ピクルスと漬物の歴史&quot;&gt;ピクルスと漬物の歴史&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/hard-to-break.html&quot; title=&quot;習慣と脳の科学&quot;&gt;習慣と脳の科学&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/sandor-katzs-fermentation-journey.html&quot; title=&quot;サンダー・キャッツの発酵の旅 世界中を旅して見つけたレシピ、技術、そして伝統&quot;&gt;サンダー・キャッツの発酵の旅 世界中を旅して見つけたレシピ、技術、そして伝統&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/show-us-your-screens.html&quot; title=&quot;演奏するプログラミング、ライブコーディングの思想と実践&quot;&gt;演奏するプログラミング、ライブコーディングの思想と実践&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/type-systems-distilled-with-typescript.html&quot; title=&quot;型システムのしくみ TypeScript で実装しながら学ぶ型とプログラミング言語&quot;&gt;型システムのしくみ TypeScript で実装しながら学ぶ型とプログラミング言語&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/basic-fermentation.html&quot; title=&quot;サンダー・キャッツの発酵教室&quot;&gt;サンダー・キャッツの発酵教室&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/becoming-a-technical-leader.html&quot; title=&quot;スーパーエンジニアへの道 技術リーダーシップの人間学&quot;&gt;スーパーエンジニアへの道 技術リーダーシップの人間学&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/the-psychology-of-computer-programming.html&quot; title=&quot;プログラミングの心理学 25 周年記念版&quot;&gt;プログラミングの心理学 25 周年記念版&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/peopleware.html&quot; title=&quot;ピープルウエア ヤル気こそプロジェクト成功の鍵 第 3 版&quot;&gt;ピープルウエア ヤル気こそプロジェクト成功の鍵 第 3 版&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/deadline.html&quot; title=&quot;デッドライン ソフト開発を成功に導く 101 の法則&quot;&gt;デッドライン ソフト開発を成功に導く 101 の法則&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/slack.html&quot; title=&quot;Slack ゆとりの法則&quot;&gt;Slack ゆとりの法則&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/waltzing-with-bears.html&quot; title=&quot;熊とワルツを リスクを楽しむプロジェクト管理&quot;&gt;熊とワルツを リスクを楽しむプロジェクト管理&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/adrenaline-junkies.html&quot; title=&quot;アドレナリンジャンキー プロジェクトの現在と未来を映す 86 パターン&quot;&gt;アドレナリンジャンキー プロジェクトの現在と未来を映す 86 パターン&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/exploring-the-world-of-fermented-soybeans-natto.html&quot; title=&quot;世界の納豆をめぐる探検&quot;&gt;世界の納豆をめぐる探検&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/essentialism.html&quot; title=&quot;エッセンシャル思考 最少の時間で成果を最大にする&quot;&gt;エッセンシャル思考 最少の時間で成果を最大にする&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/effortless.html&quot; title=&quot;エフォートレス思考 努力を最小化して成果を最大化する&quot;&gt;エフォートレス思考 努力を最小化して成果を最大化する&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/no-hard-work.html&quot; title=&quot;NO HARD WORK! 無駄ゼロで結果を出す僕らの働き方&quot;&gt;NO HARD WORK! 無駄ゼロで結果を出す僕らの働き方&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;まさに今日読み終わったところ&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️ F# の開発&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-cmdline-predictor?view=powershell-7.5&quot; title=&quot;Command-line predictor plugin&quot;&gt;Command-line predictor plugin&lt;/a&gt; の &lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; を作った。地味に良い。普段から愛用してる&lt;/li&gt;&lt;li&gt;久しぶりに GUI やりたくて &lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife&quot; title=&quot;krymtkts/PSGameOfLife&quot;&gt;krymtkts/PSGameOfLife&lt;/a&gt; を作った。結果的に GUI より .NET の低レベルの理解が捗った。 Game of Life という題材は探求する余地が無限にあるので徐々にやっていきたい&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; と &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;blog-fable&quot;&gt;blog-fable&lt;/a&gt; もぼちぼち開発できてる。悩みはどれか 1 つをやってると他を放置してしまうこと。改善したい&lt;/li&gt;&lt;li&gt;次のネタも探して実装したい&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️GitHub のストリークを継続する&lt;ul&gt;
&lt;li&gt;今 1200 を超えたくらい。来年は 1500 に達する。この先終わりはないができるところまで継続あるのみ&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️毎週ブログを書く&lt;/li&gt;&lt;li&gt;⭕️ギター練習を 4 / week&lt;ul&gt;
&lt;li&gt;IaC deploy 待ち、 Coding Agent 待ちと色々待ち時間があるのでちまちま練習。昔コピって弾けてない曲ばかりなのでちまちま補正してる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️深酒で怪我をしない&lt;ul&gt;
&lt;li&gt;単に機会がなかっただけ。酒に弱くなってきてるのもあってちょっと飲むと二日酔いしかけるので来年もっと注意が必要そう&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️自分メンテナンス&lt;ul&gt;
&lt;li&gt;メモに記録する非システマティックな方法で筋トレ習慣をちょっと改善できた。待ち時間増加の効果もあるか。そのおかげか &lt;a href=&quot;https://fatgripz.com/&quot; title=&quot;Fat Gripz&quot;&gt;Fat Gripz&lt;/a&gt; を使ってプルアップできるようになった。 Extreme ならサムレスだが Pro ならサムアラウンド。そこから先が進まなくてワンアームの手前にすら至れないのだけど。ワンレッグスクワットも練習しだして壁とかのアシストありなら数回できるようになった。ただ如何せん筋肉の柔軟性が壊滅的で足を伸ばせないのがわかったので、能動的ストレッチでそれを改善しようとしてる&lt;/li&gt;&lt;li&gt;あと万博に同行するだけで 5 Kg くらい痩せて今もそれを維持してる。ちょっと軽すぎるし筋肉量増やすためにも摂取カロリーを増やした方が良いかもな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;2025 年は仕事内容も充実してたし、概ねそれらを適切にこなせた。
ただ 2025 年中頃から「高難易度だし忙しいけど暇」だと頻繁に感じていた。
2 周目以降じゃなく初めてやるようなものでも、初めは新鮮な刺激があるが少ししたら他の知識との関連やパターンが見つかって同じような感覚に陥る。
時間をかけたらどうせできるしなという感覚、つまり学習負荷が低い状況になってるというところまでは認識してる。
来年はそこをテコ入れして改善する。改善できないとおもしろくなさ過ぎて、つらい。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;まとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;結構習慣も落ち着いてきたし、来年はもうちょっと新たな刺激を注入したいなと考えてる。
ただ油断してバランスを崩したら習慣が壊れてしまうこともあるし、いい感じに習慣をリアーキするのが必要なんやろなあ。さじ加減が難しい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Wed, 31 Dec 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-12-28-year-end-cleaning.html</guid><link>https://krymtkts.github.io/posts/2025-12-28-year-end-cleaning.html</link><title>年末の大掃除</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;先日 &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; の dev server をいじってから、年末の大掃除的に他のも継続して修正してる。&lt;/p&gt;
&lt;p&gt;細々した修正が主たるものだが、わかりやすいものだと blog-fable では振り返り日記をつけるにあたり、本を読んだ期間を本の link に添えたり &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/433&quot; title=&quot;#433&quot;&gt;#433&lt;/a&gt; してみた。
わかりやすく視認性が上がったので満足している。&lt;/p&gt;
&lt;p&gt;他にも触ってるのは &lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; で、雑に扱ってた resource management を小綺麗にできないか &lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor/pull/72&quot; title=&quot;#72&quot;&gt;#72&lt;/a&gt; 試しているところ。
Command-line predictor の plugin なので plugin が remove されたら全部 resource 掃除されるしいいかと思ってたが是正してみてる。
PowerShell だし思わぬ形で長生きされても困るしな。
手法としては &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; で得た &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.volatile?view=net-10.0&quot; title=&quot;&lt;code&gt;Volatile&lt;/code&gt;&quot;&gt;&lt;code&gt;Volatile&lt;/code&gt;&lt;/a&gt; などの知識を流用して、実装は AI に書かせてみてる。
毎日コツコツとリアル大掃除の方を進めているので、掃除中に実装してもらってレビューしている。&lt;/p&gt;
&lt;p&gt;これらは大掃除が終わったら年を越す前に release してみたい気持ち。
使用感が変わるわけでもないが、全くリリースなく年を越すよりはなんとなくいいかなと。
あと数日大晦日まで時間があるので、その中でぼちぼち更新していきたい。&lt;/p&gt;
&lt;p&gt;あと使い続けてる &lt;a href=&quot;https://keeb.io/collections/iris-split-ergonomic-keyboard&quot; title=&quot;Iris Keyboard&quot;&gt;Iris Keyboard&lt;/a&gt; の key の chattering が大変なことになっていて、特に Enter key が重大な問題になってる。
正しく打鍵どおりに入力できないから、しょうもないパスワード入力間違いや、実行したつもりの command が実行できてなかったり。
これを解消したいのだけど今のところホコリをとっても直らないしあとは接点復活剤か key 自体の取り換えしか選択肢がない。
年内に何らかの術でどうにか解消したいところだ。&lt;/p&gt;
&lt;p&gt;これは機械接点に由来する問題だから mechanical switch の避けられない問題だ。
なので今の時代だと磁気スイッチとかが狙い目かも知れんが、中々自作ハードルが高いな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 28 Dec 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-12-21-switch-live-reloading-from-web-socket-to-sse.html</guid><link>https://krymtkts.github.io/posts/2025-12-21-switch-live-reloading-from-web-socket-to-sse.html</link><title>blog の Live reloading を WebSocket から SSE に切り替えた</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;先日 &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; の dev server を &lt;a href=&quot;https://github.com/SuaveIO/suave&quot; title=&quot;Suave&quot;&gt;Suave&lt;/a&gt; &lt;a href=&quot;https://www.nuget.org/packages/Suave/3.2.0&quot; title=&quot;3.2.0&quot;&gt;3.2.0&lt;/a&gt; に更新した。
その流れで dev server を refactor した。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/424&quot; title=&quot;#424&quot;&gt;#424&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;blog-fable では元々ファイル変更時に client へ event 通知する、要は live reloading するのに WebSocket で通知してた。
でも相互通信が必要な訳ではなく、単に server -&amp;gt; client の単方向通知だけが目的だと過剰なので、 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events&quot; title=&quot;Server-Sent Events&quot;&gt;Server-Sent Events&lt;/a&gt; にしようと考えた。
幸い Suave には &lt;a href=&quot;https://github.com/SuaveIO/suave/blob/a856edacfa9209d0ffb2078932169a7b8e084f18/src/Suave/Combinators.fs#L770-L866&quot; title=&quot;&lt;code&gt;EventSource&lt;/code&gt; module&quot;&gt;&lt;code&gt;EventSource&lt;/code&gt; module&lt;/a&gt; があって、それを使うことで簡単に実装できる。
&lt;code&gt;EventSource&lt;/code&gt; module について何処かにあるのかも知れないが document は見当たらなかった。
Sample code には多少出現してそうなのだけど、そこからはあまり使い方がわからなかった。&lt;/p&gt;
&lt;p&gt;GitHub Copilot(GPT-5.2) に方針を示したらサクッと実装してくれた。
余談だが &lt;a href=&quot;https://fable.io/docs/javascript/features.html#utilities&quot; title=&quot;Fable の binding&quot;&gt;Fable の binding&lt;/a&gt; をサラッと書いてくれた辺りは中々やるなと思った。
当然多少の手直しが必要なのは変わらないけど。&lt;/p&gt;
&lt;p&gt;再帰を使ってた部分も単純な while loop に直した。
コードが圧縮されて良いかなと。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken?view=net-10.0&quot; title=&quot;&lt;code&gt;CancellationToken&lt;/code&gt;&quot;&gt;&lt;code&gt;CancellationToken&lt;/code&gt;&lt;/a&gt; は Suave の config の方に移ったのでここでの出番はなくなってる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    let socketHandler (ws: WebSocket) _ =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        let rec refreshLoop (ct: CancellationToken) =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            task {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                ct.ThrowIfCancellationRequested()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                do! refreshEvent.Publish |&amp;gt; Async.AwaitEvent&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                printfn &amp;quot;refresh client.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                let seg = ASCII.bytes &amp;quot;refreshed&amp;quot; |&amp;gt; ByteSegment&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                let! _ = ws.send Text seg true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                return! refreshLoop ct&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        let rec mainLoop (cts: CancellationTokenSource) =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            socket {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                let! msg = ws.read ()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                match msg with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                | Close, _, _ -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    // use _ = cts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    cts.Cancel()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    let emptyResponse = [||] |&amp;gt; ByteSegment&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    do! ws.send Close emptyResponse true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    printfn &amp;quot;WebSocket connection closed gracefully.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                | _ -&amp;gt; return! mainLoop cts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        let cts = new CancellationTokenSource()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        refreshLoop cts.Token |&amp;gt; ignore&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        mainLoop cts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    handleWatcherEvents, socketHandler&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    let sseHandler (conn: Connection) : Task&amp;lt;unit&amp;gt; =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        task {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            try&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                // NOTE: Tell the browser how long to wait before retrying the connection.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                do! EventSource.retry conn 1000u&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                // NOTE: Initial event so the client can confirm it is connected.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                do! EventSource.eventType conn &amp;quot;connected&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                do! EventSource.data conn &amp;quot;ok&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                do! EventSource.dispatch conn&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                while true do&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    do!&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                        Async.StartAsTask(&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                            refreshEvent.Publish |&amp;gt; Async.AwaitEvent,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                            cancellationToken = CancellationToken.None&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                        )&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    do! EventSource.eventType conn &amp;quot;refresh&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    do! EventSource.data conn &amp;quot;refreshed&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    do! EventSource.dispatch conn&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            | :? OperationCanceledException -&amp;gt; ()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            | :? SocketException -&amp;gt; ()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    handleWatcherEvents, sseHandler&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この関数を &lt;code&gt;EventSource.handShake&lt;/code&gt; に渡すだけ。便利だ。
Suave 3 系になって &lt;code&gt;handShake&lt;/code&gt; 系の関数は &lt;code&gt;Task&lt;/code&gt; を要求する signature に変わってる。昔は &lt;code&gt;Async&lt;/code&gt; だったなとしみじみと感じる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;     choose [&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        path &amp;quot;/websocket&amp;quot; &amp;gt;=&amp;gt; handShake socketHandler&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        path &amp;quot;/sse&amp;quot; &amp;gt;=&amp;gt; EventSource.handShake sseHandler&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;         GET&lt;br /&gt;         &amp;gt;=&amp;gt; Writers.setHeader &amp;quot;Cache-Control&amp;quot; &amp;quot;no-cache, no-store, must-revalidate&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;client 側は &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/EventSource&quot; title=&quot;&lt;code&gt;EventSource&lt;/code&gt;&quot;&gt;&lt;code&gt;EventSource&lt;/code&gt;&lt;/a&gt; を使う。
ここで Fable の binding が活きる。
元々使っていた &lt;a href=&quot;https://www.nuget.org/packages/Fable.Browser.WebSocket&quot; title=&quot;&lt;code&gt;Fable.Browser.WebSocket&lt;/code&gt;&quot;&gt;&lt;code&gt;Fable.Browser.WebSocket&lt;/code&gt;&lt;/a&gt; の代わりに &lt;a href=&quot;https://www.nuget.org/packages/Fable.Browser.EventSource/&quot; title=&quot;&lt;code&gt;Fable.Browser.EventSource&lt;/code&gt;&quot;&gt;&lt;code&gt;Fable.Browser.EventSource&lt;/code&gt;&lt;/a&gt; を使うというの手もあったが、使わなかった。
&lt;code&gt;Fable.Browser.EventSource&lt;/code&gt; も小さい module だし利用箇所はもっと小さいので、自前の方が依存関係を減らせて何かと管理が楽だ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt; module Dev&lt;br /&gt;&lt;br /&gt; open Browser.Dom&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-open Browser.WebSocket&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+open Fable.Core&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-let private initLiveReloading _ =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    // NOTE: don&amp;#x27;t use string interpolation here, it will break the code because of importing String module.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    let ws = WebSocket.Create &amp;lt;| &amp;quot;ws://&amp;quot; + window.location.host + &amp;quot;/websocket&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+[&amp;lt;Emit(&amp;quot;typeof EventSource !== &amp;#x27;undefined&amp;#x27;&amp;quot;)&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+let private hasEventSource: bool = jsNative&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+[&amp;lt;AllowNullLiteral&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+type private IEventSource =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    abstract addEventListener: string * (obj -&amp;gt; unit) -&amp;gt; unit&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    abstract close: unit -&amp;gt; unit&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    abstract onmessage: (obj -&amp;gt; unit) with get, set&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+[&amp;lt;Emit(&amp;quot;new EventSource($0)&amp;quot;)&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+let private createEventSource (_url: string) : IEventSource = jsNative&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+let private initLiveReloadingViaSse () =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    let es = createEventSource &amp;quot;/sse&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    ws.onmessage &amp;lt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        fun _ -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            ws.close (1000, &amp;quot;reload&amp;quot;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            window.location.reload ()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    let reload (_: obj) =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        es.close ()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        window.location.reload ()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    window.addEventListener (&amp;quot;beforeunload&amp;quot;, (fun _ -&amp;gt; ws.close ()))&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    es.addEventListener (&amp;quot;refresh&amp;quot;, reload)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    es.onmessage &amp;lt;- reload&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    window.addEventListener (&amp;quot;beforeunload&amp;quot;, (fun _ -&amp;gt; es.close ()))&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+let private initLiveReloading _ =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    // SSE only.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    // If the browser doesn&amp;#x27;t support EventSource, do nothing.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    if hasEventSource then&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        initLiveReloadingViaSse ()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; window.addEventListener (&amp;quot;load&amp;quot;, initLiveReloading)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以上備忘のメモ。&lt;/p&gt;
&lt;p&gt;今回のような普段書き直さないような部分の書き直しは新たな再発見があっていいな。
あと log はまだ来てないようだし、 Suave 3 の更新がある限りはちまちまと触る機会になりそうで、良い。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 21 Dec 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-12-14-suave-3.html</guid><link>https://krymtkts.github.io/posts/2025-12-14-suave-3.html</link><title>Suave 3</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; は開発時の preview や snapshot testing の web server に &lt;a href=&quot;https://github.com/SuaveIO/suave&quot; title=&quot;Suave&quot;&gt;Suave&lt;/a&gt; を使っている。
Suave は F# で書かれた軽量な Web server で、 2023 年に出た &lt;a href=&quot;https://www.nuget.org/packages/Suave/2.7.0-beta1&quot; title=&quot;2.7.0-beta1&quot;&gt;2.7.0-beta1&lt;/a&gt; 以降リリースは止まっていた。開発はポツポツ進んでいたみたいなのだけど。
でもつい先日 dev server での preview ができなくなったので調べてみたら、なんと &lt;a href=&quot;https://www.nuget.org/packages/Suave/3.1.0-beta&quot; title=&quot;2025-11 頃から 3 系 preview が NuGet で公開&quot;&gt;2025-11 頃から 3 系 preview が NuGet で公開&lt;/a&gt;され出してた。
2025-12-11 の時点で preview でない &lt;a href=&quot;https://www.nuget.org/packages/Suave/3.2.0&quot; title=&quot;3.2.0&quot;&gt;3.2.0&lt;/a&gt; まで来てる。&lt;/p&gt;
&lt;p&gt;活動再開を目にできるなんて実に喜ばしいことだ。
&lt;a href=&quot;https://github.com/jgthms/bulma&quot; title=&quot;Bulma&quot;&gt;Bulma&lt;/a&gt; の時もそうだったが、そもそも活動再開でもなくてそういう開発スタイルとスパンなのかも知れんな。
何にせよ利用者としては嬉しい限り。&lt;/p&gt;
&lt;p&gt;Suave の 2 -&amp;gt; 3 ではごっそり書き換えが必要なレベルの設計変更はなかった。
パフォーマンス最適化がメインで、内部で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/task-expressions&quot; title=&quot;&lt;code&gt;Task&lt;/code&gt;&quot;&gt;&lt;code&gt;Task&lt;/code&gt;&lt;/a&gt; がより多く使われるようになってる。
他は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.buffers.arraypool-1?view=net-10.0&quot; title=&quot;&lt;code&gt;ArrayPool&lt;/code&gt;&quot;&gt;&lt;code&gt;ArrayPool&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.memory-1?view=net-10.0&quot; title=&quot;&lt;code&gt;Memory&lt;/code&gt;&quot;&gt;&lt;code&gt;Memory&lt;/code&gt;&lt;/a&gt; とかね。&lt;/p&gt;
&lt;p&gt;あと今のところは &lt;code&gt;Logging&lt;/code&gt; module がなくなって &lt;code&gt;logger&lt;/code&gt; が使えなくなってた。
&lt;code&gt;Logging&lt;/code&gt; がなくなったのは読み込まれたファイルのログが出なくなって dev server 的には地味に痛いのだが、ひょっとしたら別の方法で実現できたり復活の可能性もあるので、経過観測する。&lt;/p&gt;
&lt;p&gt;blog-fable で一番影響があったのは一部 signature の変更かな。でも build error を直すだけ。
&lt;code&gt;socket&lt;/code&gt; CE の中で使ってた &lt;code&gt;use&lt;/code&gt; が使えなくなったのと &lt;code&gt;defaultMimeTypesMap&lt;/code&gt; の signature 変更あたりが細かな修正点。
これら blog-fable で影響のあった点を &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/422&quot; title=&quot;#422&quot;&gt;#422&lt;/a&gt; でいい感じに対応した。
実測した訳では無いのと target framework が &lt;code&gt;net10.0&lt;/code&gt; になってるのもあるだろうが、体感かなり速くなった気がする。&lt;/p&gt;
&lt;p&gt;久しぶりに dev server 周りいじったので、この機会に他にも細かな改善などしていっていいかも知れんな。
その間 &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の方が放置されてしまうが、
 blog-fable の修正は大した事ない物が多いからそんなに時間もかからないだろう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 14 Dec 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-12-07-dont-understand-nuget-dependabot-well.html</guid><link>https://krymtkts.github.io/posts/2025-12-07-dont-understand-nuget-dependabot-well.html</link><title>NuGet の Dependabot がよくわからない</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;予定があって &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発はできなかった。
なのでちまちました改善をするに留めてたのだが、 あらためて NuGet の &lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates&quot; title=&quot;Dependabot version updates&quot;&gt;Dependabot version updates&lt;/a&gt; の挙動がよくわからないなと思っている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2025-04-06-fix-dependabot-nuget-project-not-found.html&quot; title=&quot;以前&quot;&gt;以前&lt;/a&gt; project が見つからなくなった話をしたが、あれとはまた違う。
今回のは特定の依存関係だけ更新されずに残っているという挙動に出会った。&lt;/p&gt;
&lt;p&gt;blog-fable の repo root で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-package-list&quot; title=&quot;&lt;code&gt;dotnet list package --outdated&lt;/code&gt;&quot;&gt;&lt;code&gt;dotnet list package --outdated&lt;/code&gt;&lt;/a&gt; したら以下が表示された。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; dotnet list package &lt;span class=&quot;hljs-literal&quot;&gt;--outdated&lt;/span&gt;&lt;br /&gt;Restore complete (&lt;span class=&quot;hljs-number&quot;&gt;1.2&lt;/span&gt;s)&lt;br /&gt;&lt;br /&gt;Build succeeded &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1.3&lt;/span&gt;s&lt;br /&gt;&lt;br /&gt;The following sources were used:&lt;br /&gt;   https://api.nuget.org/v3/index.json&lt;br /&gt;&lt;br /&gt;Project `App` has the following updates to its packages&lt;br /&gt;   [&lt;span class=&quot;hljs-type&quot;&gt;net10.0&lt;/span&gt;]:&lt;br /&gt;   Top&lt;span class=&quot;hljs-literal&quot;&gt;-level&lt;/span&gt; Package        Requested   Resolved   Latest&lt;br /&gt;   &amp;gt; Fable.Browser.Dom      &lt;span class=&quot;hljs-number&quot;&gt;2.19&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      &lt;span class=&quot;hljs-number&quot;&gt;2.19&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;2.20&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Project `test` has the following updates to its packages&lt;br /&gt;   [&lt;span class=&quot;hljs-type&quot;&gt;net10.0&lt;/span&gt;]:&lt;br /&gt;   Top&lt;span class=&quot;hljs-literal&quot;&gt;-level&lt;/span&gt; Package           Requested   Resolved   Latest&lt;br /&gt;   &amp;gt; Microsoft.Playwright      &lt;span class=&quot;hljs-number&quot;&gt;1.56&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      &lt;span class=&quot;hljs-number&quot;&gt;1.56&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;1.57&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;いつも JST 金曜 06:00 に更新してるから、 &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Playwright&quot; title=&quot;&lt;code&gt;Microsoft.Playwright&lt;/code&gt;&quot;&gt;&lt;code&gt;Microsoft.Playwright&lt;/code&gt;&lt;/a&gt; の方は 2025-12-04 21:29:03Z でチェックの後に更新されたからわかる。
ただ &lt;a href=&quot;https://www.nuget.org/packages/Fable.Browser.Dom#versions-body-tab&quot; title=&quot;&lt;code&gt;Fable.Browser.Dom&lt;/code&gt;&quot;&gt;&lt;code&gt;Fable.Browser.Dom&lt;/code&gt;&lt;/a&gt; の方は 5 ヶ月も前に更新されてるから拾えないのはおかしい。
仕方ないのでどちらも手動で更新した。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/416&quot; title=&quot;#416&quot;&gt;#416&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;この過程で blog の code snippet が正しく改行されなくなっているのも発見した。これは困る。
Microsoft (Chromium )Edge だと正しく改行されて Google Chrome で改行されないみたい。&lt;/p&gt;
&lt;p&gt;1Password の Google Chrome 拡張機能が有効だと改行コードが破壊さて Syntax highlighting もされなくなるところまで突き止めた。
いまの version は 8.11.22.25 だった。&lt;/p&gt;
&lt;p&gt;HTML 生成時点で code snippet は highlight.js の class が付与された状態に出力されているのだけど、 1Password 拡張機能付きで読み込むと動的に書き換えられてしまうみたい。
なんじゃこりゃーー。
似たような問題が報告されているのも確認できた。これは関連がありそうだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.1password.community/discussions/1password/bug-beta-and-nightly-extension-degrade-pages-original-functionallity/165329&quot; title=&quot;[BUG] Beta and Nightly extension degrade page&amp;#39;s original functionallity | 1Password Community&quot;&gt;[BUG] Beta and Nightly extension degrade page&amp;#39;s original functionallity | 1Password Community&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;通常はこう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;lt;code class=&amp;quot;language-powershell&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hljs-comment&amp;quot;&amp;gt;# .NET 9 まで(.NET 10 でも動く)&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;dotnet add ./src/pocof package FSharp.Core &amp;lt;span class=&amp;quot;hljs-literal&amp;quot;&amp;gt;--version&amp;lt;/span&amp;gt; &amp;lt;span class=&amp;quot;hljs-number&amp;quot;&amp;gt;10.0&amp;lt;/span&amp;gt;.&amp;lt;span class=&amp;quot;hljs-number&amp;quot;&amp;gt;100&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;span class=&amp;quot;hljs-comment&amp;quot;&amp;gt;# .NET 10 から&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;dotnet package add FSharp.Core &amp;lt;span class=&amp;quot;hljs-literal&amp;quot;&amp;gt;--version&amp;lt;/span&amp;gt; &amp;lt;span class=&amp;quot;hljs-number&amp;quot;&amp;gt;10.0&amp;lt;/span&amp;gt;.&amp;lt;span class=&amp;quot;hljs-number&amp;quot;&amp;gt;100&amp;lt;/span&amp;gt; &amp;lt;span class=&amp;quot;hljs-literal&amp;quot;&amp;gt;--project&amp;lt;/span&amp;gt; ./src/pocof&lt;br /&gt;&amp;lt;/code&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;でも 1Password が悪さするとこうなる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;lt;code class=&amp;quot;language-powershell&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;token comment&amp;quot;&amp;gt;# .NET 9 まで(.NET 10 でも動く)dotnet add ./src/pocof package FSharp.Core --version 10.0.100# .NET 10 からdotnet package add FSharp.Core --version 10.0.100 --project ./src/pocof&amp;lt;/span&amp;gt;&lt;br /&gt;&amp;lt;/code&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ちょっと対応方法がわからないのでこれは様子見するかー。残念や。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 07 Dec 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-11-30-writing-cmdlet-in-fsharp-pt83.html</guid><link>https://krymtkts.github.io/posts/2025-11-30-writing-cmdlet-in-fsharp-pt83.html</link><title>F# で Cmdlet を書いてる pt.82 - pocof 0.22.0</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。
&lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.22.0&quot; title=&quot;0.22.0&quot;&gt;0.22.0&lt;/a&gt; をリリースをした。&lt;/p&gt;
&lt;p&gt;最適化サポートを LTS の PowerShell 、今だと 7.4 なので .NET 8.0 を基準&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;にして、その旨を &lt;code&gt;README.md&lt;/code&gt; に明記した。&lt;/p&gt;
&lt;p&gt;あと、クエリに変更がなければキャッシュした結果を使い回す機能をうっかり実装してしまった &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/403&quot; title=&quot;#403&quot;&gt;#403&lt;/a&gt; ので、それもリリースに含めた。
クエリに変更がないというのは、クエリ文字列・一致条件・組み合わせ・反転などが一致している状態を指す。
これは当然 whitespace を打ち込んだ場合も cache を使えないということでもある。
なので現時点ではカーソル移動の時だけ有効な感じ。
とりあえずの出発点としてはこれでよいかと。&lt;/p&gt;
&lt;p&gt;クエリ構築は結構重いので、生成しなくてよく無くなるだけで ms level ではあるが節約になる。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;QueryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Median&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen1&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;prepare&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,389.987 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;23.8900 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;42.4645 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,382.051 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.001&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.7038&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2944 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareCached&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.167 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2167 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.3963 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.133 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.005&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepare&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,739.519 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;54.3090 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;113.3631 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,697.941 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.002&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.3695&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0038&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5728 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareCached&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.104 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2165 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.3497 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.149 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.003&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepare&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4,242.972 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;83.1371 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;224.7660 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4,166.865 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.003&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.0294&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0076&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8512 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareCached&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.288 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2180 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.5054 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.249 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.002&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepare&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6,242.056 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;280.0643 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;825.7758 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5,906.579 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.017&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.19&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.7084&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0076&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11328 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareCached&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.755 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2117 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.3357 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.662 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.001&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;このクエリ構築が重いのは、キャッシュを履歴化するだとか、差分コンパイルするだとかで改善できると考えられるが、どこまでやるかやな。
どのみちクエリの実行自体が最も重いので、こういうのは細かな調整レベルの話なのだが、色々考えることがあって楽しい。&lt;/p&gt;
&lt;p&gt;prerelease は久しぶりに使ったのだけど、 prerelease 版と正規版がどちらもバージョン文字列の directory を利用することをすっかり忘れていた。
お陰で PowerShell Gallery から最新版(正規版)を更新するとき、 PowerShell が &lt;code&gt;FSharp.Core.dll&lt;/code&gt; を掴んだままで消せなくて手間取った。
これは .NET がプロセスを死なせるまで握り続けてしまうからで、開いている PowerShell をすべて殺してから更新するしか術がない。
この事象に出くわしたのも久しぶりで何？となったのだけど、これは .NET の未来永劫変わらないのかな。面倒なのでいつか改善してくれればいいのだけど。
うっかり忘れがちなので pocof で prerelease を使う時は次の version まで飛ばしてしまう方が安定していて良いか。&lt;/p&gt;
&lt;p&gt;あと 1 ヶ月程で 2025 年も終わるが、あと 1 回位は改善リリースができたら良さそうかな。
まだ Multi targeting にした利点を全く活かせてないので、そこ攻めたいよな。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/install/powershell-support-lifecycle?view=powershell-7.5#powershell-end-of-support-dates&quot; title=&quot;PowerShell Support Lifecycle - PowerShell | Microsoft Learn&quot;&gt;PowerShell Support Lifecycle - PowerShell | Microsoft Learn&lt;/a&gt; &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 30 Nov 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-11-23-writing-cmdlet-in-fsharp-pt82.html</guid><link>https://krymtkts.github.io/posts/2025-11-23-writing-cmdlet-in-fsharp-pt82.html</link><title>F# で Cmdlet を書いてる pt.82 - pocof 0.22.0-alpha</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。
Multi targeting と bugfix を含めたものを &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.22.0-alpha&quot; title=&quot;0.22.0-alpha&quot;&gt;0.22.0-alpha&lt;/a&gt; としてリリースをした。
初めて Multi targeting するのもありほんとにちゃんと publish されるのかなと不安があったので、久々の &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/gallery/concepts/module-prerelease-support?view=powershellget-3.x&quot; title=&quot;prerelease&quot;&gt;prerelease&lt;/a&gt; にした。&lt;/p&gt;
&lt;p&gt;リリースに際してこれまで import した module ベースでの publish してたのをやめた。
代わりにより再現性高い path ベースので publish に切り替えた。
また今回は prerelease として出したのだけど、リリース用の psakefile を調整して prerelease version まで検査できるように直した。
これはなかなか気に入っている。
元は pocof を始めるとき参考にした blog の情報に基づき &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/import-localizeddata?view=powershell-7.5&quot; title=&quot;&lt;code&gt;Import-LocalizedData&lt;/code&gt;&quot;&gt;&lt;code&gt;Import-LocalizedData&lt;/code&gt;&lt;/a&gt; を使ってた。
でも pocof では多言語化意味ないので単純な &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/import-powershelldatafile?view=powershell-7.5&quot; title=&quot;&lt;code&gt;Import-PowerShellDataFile&lt;/code&gt;&quot;&gt;&lt;code&gt;Import-PowerShellDataFile&lt;/code&gt;&lt;/a&gt; に切り替えた。
これによって &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-version&quot; title=&quot;&lt;code&gt;System.Version&lt;/code&gt;&quot;&gt;&lt;code&gt;System.Version&lt;/code&gt;&lt;/a&gt; で取り扱えない prerelease suffix もいい感じに扱える。&lt;/p&gt;
&lt;p&gt;今回のリリース後に Linux でのみ crash する bug &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/397&quot; title=&quot;#397&quot;&gt;#397&lt;/a&gt; を発見した。
いつから壊れてるのかわからないが多分 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.text.stringbuilder?view=net-8.0&quot; title=&quot;&lt;code&gt;StringBuilder&lt;/code&gt;&quot;&gt;&lt;code&gt;StringBuilder&lt;/code&gt;&lt;/a&gt; を使いだしたころからかな。
これは早めに対処したいが、 platform 依存の bug は対処難しいのでどうなることやら。&lt;/p&gt;
&lt;p&gt;因みに今回の prerelease で .NET 6.0 と .NET Standard 2.0 の binary が配信されるようになったのだけど、両者にパフォーマンス上の違いはほぼなさそうだった。
以下に未来の自分に対して target framework の変更程度で高速化するなんて儚い希望は持つなよという意味で結果を残しておく。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;以下は benchmark の project を &lt;code&gt;net 9.0&lt;/code&gt; で回した場合。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/frameworks&quot; title=&quot;TFM&quot;&gt;TFM&lt;/a&gt; が &lt;code&gt;netstandard2.0&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;BenchmarkDotNet v0.15.7, Windows 11 (10.0.26200.7171/25H2/2025Update/HudsonValley2)
Intel Core i7-8550U CPU 1.80GHz (Max: 2.00GHz) (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
.NET SDK 10.0.100
[Host] : .NET 9.0.11 (9.0.11, 9.0.1125.51716), X64 RyuJIT x86-64-v3 DEBUG
DefaultJob : .NET 9.0.11 (9.0.11, 9.0.1125.51716), X64 RyuJIT x86-64-v3&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;invokeAction_Noop&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;138.4 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.68 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.38 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.02&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_AddQuery&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;862.1 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17.14 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;25.12 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.23&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.21&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.3920&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1640 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;476.1 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.45 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.89 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.44&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.08&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;639.9 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.34 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;14.21 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.63&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.13&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0477&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;200 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.92&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_DeleteBackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;235.5 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.51 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.01 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.70&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_DeleteBackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,380.1 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;46.32 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;70.74 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17.21&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.58&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.8392&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3512 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;33.77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_SelectBackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;516.8 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.39 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.64 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.74&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.09&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0401&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;168 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_SelectBackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;566.6 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.23 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;14.99 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.13&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0629&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;264 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_RotateMatcher&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;160.2 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.02 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.96 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.16&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0496&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;208 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_NoSearch&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;139.3 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.32 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.94 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.01&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.02&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_Search&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;529.8 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.45 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;13.59 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.83&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.12&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1564&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;656 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_Rotate&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;420.9 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.44 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.05 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.09&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1392&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;584 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.62&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;TFM が &lt;code&gt;net6.0&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;BenchmarkDotNet v0.15.7, Windows 11 (10.0.26200.7171/25H2/2025Update/HudsonValley2)
Intel Core i7-8550U CPU 1.80GHz (Max: 2.00GHz) (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
.NET SDK 10.0.100
[Host] : .NET 9.0.11 (9.0.11, 9.0.1125.51716), X64 RyuJIT x86-64-v3 DEBUG
DefaultJob : .NET 9.0.11 (9.0.11, 9.0.1125.51716), X64 RyuJIT x86-64-v3&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;invokeAction_Noop&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;136.4 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.73 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.83 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_AddQuery&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;829.1 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.56 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17.72 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.08&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.21&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.3920&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1640 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;463.7 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.26 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.09 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.40&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;627.2 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.09 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.83 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.60&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.14&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0477&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;200 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.92&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_DeleteBackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;230.9 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.47 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.93 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.69&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_DeleteBackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,293.5 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;40.80 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;57.19 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.83&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.62&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.8392&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3512 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;33.77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_SelectBackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;498.0 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.16 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.15 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.65&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0401&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;168 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_SelectBackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;569.3 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.32 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.58 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.18&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.14&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0629&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;264 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_RotateMatcher&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;161.7 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.15 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.79 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.19&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0496&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;208 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_NoSearch&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;141.1 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.92 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.58 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_Search&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;525.6 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.31 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;14.11 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.86&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.15&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1564&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;656 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_Rotate&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;460.4 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.93 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.91 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.38&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1392&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;584 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.62&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;悪あがきで試しに TFM が &lt;code&gt;net8.0&lt;/code&gt; の場合も取った。&lt;/p&gt;
&lt;p&gt;BenchmarkDotNet v0.15.7, Windows 11 (10.0.26200.7171/25H2/2025Update/HudsonValley2)
Intel Core i7-8550U CPU 1.80GHz (Max: 2.00GHz) (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
.NET SDK 10.0.100
[Host] : .NET 9.0.11 (9.0.11, 9.0.1125.51716), X64 RyuJIT x86-64-v3 DEBUG
DefaultJob : .NET 9.0.11 (9.0.11, 9.0.1125.51716), X64 RyuJIT x86-64-v3&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;invokeAction_Noop&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;139.6 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.80 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.99 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_AddQuery&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;854.5 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.77 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;22.38 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.12&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.20&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.3920&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1640 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;473.8 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.30 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.70 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.39&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.09&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;624.0 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.34 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;13.21 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.47&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.13&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0477&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;200 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.92&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_DeleteBackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;237.2 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.74 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.80 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.70&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_DeleteBackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,400.6 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;45.94 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;54.68 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17.20&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.52&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.8392&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3512 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;33.77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_SelectBackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;501.0 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.87 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.74 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.59&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0401&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;168 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_SelectBackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;592.5 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.65 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;13.87 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.25&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.13&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0629&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;264 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_RotateMatcher&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;164.6 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.76 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.83 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.18&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0496&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;208 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_NoSearch&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;138.5 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.70 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.00 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.99&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_Search&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;525.2 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.47 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;13.62 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.76&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.12&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1564&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;656 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_Rotate&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;425.4 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.46 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.66 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1392&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;584 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.62&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;以下は benchmark の project を &lt;code&gt;net10.0&lt;/code&gt; で回した場合。&lt;/p&gt;
&lt;p&gt;TFM が &lt;code&gt;netstandard2.0&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;BenchmarkDotNet v0.15.7, Windows 11 (10.0.26200.7171/25H2/2025Update/HudsonValley2)
Intel Core i7-8550U CPU 1.80GHz (Max: 2.00GHz) (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
.NET SDK 10.0.100
[Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v3 DEBUG
DefaultJob : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v3&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;invokeAction_Noop&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;61.81 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.711 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.593 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.01&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_AddQuery&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;634.17 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.236 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.018 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.26&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.21&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.3920&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1640 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;181.10 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.864 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.679 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.93&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;269.64 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.362 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.585 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.36&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0477&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;200 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.92&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_DeleteBackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;94.00 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.895 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.773 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.52&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_DeleteBackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,820.17 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;35.804 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;42.623 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;29.45&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.73&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.8392&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3512 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;33.77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_SelectBackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;199.02 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.845 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.577 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.22&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.08&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0401&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;168 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_SelectBackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;272.08 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.230 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.136 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.40&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.09&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0629&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;264 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_RotateMatcher&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;87.81 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.705 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.963 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.42&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0497&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;208 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_NoSearch&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;67.76 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.424 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.801 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_Search&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;363.46 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.280 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.207 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.88&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.16&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1564&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;656 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_Rotate&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;307.18 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.190 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.996 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.97&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.17&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1392&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;584 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.62&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;TFM が &lt;code&gt;net6.0&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;BenchmarkDotNet v0.15.7, Windows 11 (10.0.26200.7171/25H2/2025Update/HudsonValley2)
Intel Core i7-8550U CPU 1.80GHz (Max: 2.00GHz) (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
.NET SDK 10.0.100
[Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v3 DEBUG
DefaultJob : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v3&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;invokeAction_Noop&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;64.63 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.324 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.416 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_AddQuery&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;647.66 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.872 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.642 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.28&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.3920&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1640 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;185.61 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.599 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.145 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.87&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.09&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;309.75 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.180 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.863 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.79&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.17&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0477&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;200 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.92&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_DeleteBackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;95.88 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.965 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.117 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.48&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_DeleteBackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,802.35 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;35.392 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;33.106 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;27.90&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.77&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.8392&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3512 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;33.77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_SelectBackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;214.03 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.136 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.231 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.31&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0401&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;168 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_SelectBackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;275.16 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.398 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.742 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.26&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.15&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0629&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;264 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_RotateMatcher&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;91.23 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.822 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.305 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.41&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0497&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;208 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_NoSearch&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;68.79 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.428 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.386 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_Search&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;365.48 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.125 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.988 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.66&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.19&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1564&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;656 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_CompleteProperty_Rotate&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;306.81 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.065 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.965 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.75&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.18&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1392&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;584 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.62&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;見ての通り、高速化されたといわれてる .NET 10 を benchmark project の Target framework にした場合は明らかに速かった。
つまり実行するところの runtime が一番影響するから、 PowerShell であれば PowerShell 自体の .NET version が影響するって考えたらいいかな。&lt;/p&gt;
&lt;p&gt;PowerShell 自体が速くなるのを待っても良いけど、新しい framework 向けの最適化を入れていきたいと検討してる。
今回の prerelease で Multi targeting を実現したが、 prerelease を外す際にはサポートする platform のルール策定をしておきたい。
一番シンプルなのは LTS の PowerShell に合わせる方法なので、現行 LTS の PowerShell 7.4 つまり .NET 8.0 を基準にするのが 1 つの選択肢かな。
つまり今だと PowerShell 7.2 で .NET 8 が最適化サポート最低ライン。
ほかは .NET Standard 2.0 になる。
いま試しに Multi targeting を始めてみた時点では .NET 6.0 と .NET Standard 2.0 なので、 それの最適化される方の閾値を上げる感じ。
ひとつの問題として LTS が進んだらどんどん最適化ラインから外されてしまうという課題もあるのだけど、 PowerShell の LTS を考えたら妥当と思える。
とりまサポート戦略を決めたら &lt;code&gt;README.md&lt;/code&gt; に書くなりして alpha 外した 0.22.0 として publish してみるのがよさそうかな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 23 Nov 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-11-16-writing-cmdlet-in-fsharp-pt81.html</guid><link>https://krymtkts.github.io/posts/2025-11-16-writing-cmdlet-in-fsharp-pt81.html</link><title>F# で Cmdlet を書いてる pt.81 - Central Package Management と .NET 10</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。
開発というかメンテ。&lt;/p&gt;
&lt;p&gt;まずは &lt;a href=&quot;https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management&quot; title=&quot;Central Package Management&quot;&gt;Central Package Management&lt;/a&gt; を導入した話。&lt;/p&gt;
&lt;p&gt;ちょっと前に .NET の &lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates&quot; title=&quot;Dependabot version updates&quot;&gt;Dependabot version updates&lt;/a&gt; の挙動が変わって壊れたとき、 &lt;code&gt;dependabot.yml&lt;/code&gt; を書き換えた内容が間違ってたみたい。
それが原因で一部の package が更新されない状態が続いてたのに気付いた。
それは pocof に限った話じゃないのだけで、自作の PowerShell cmdlet の repository 全体的に直した。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/377&quot; title=&quot;#377&quot;&gt;#377&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;それで期待通り Dependabot が働き始めたのだけど、 pocof のような 1 solution に複数(pocof は 4) project ある package 管理が面倒に感じた。
いい機会なので Central Package Management(CPM) を導入してみた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/382&quot; title=&quot;#382&quot;&gt;#382&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;もともと &lt;a href=&quot;https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory?view=vs-2022#directorybuildprops-and-directorybuildtargets&quot; title=&quot;&lt;code&gt;Directory.Build.props&lt;/code&gt;&quot;&gt;&lt;code&gt;Directory.Build.props&lt;/code&gt;&lt;/a&gt; は &lt;a href=&quot;https://ionide.io/ionide-analyzers/&quot; title=&quot;Ionide.Analyzer&quot;&gt;Ionide.Analyzer&lt;/a&gt; を全 project へ導入するのに使ってた。
CPM ではこれとは別に &lt;code&gt;Directory.Packages.props&lt;/code&gt; を置く。
そこで &lt;code&gt;&amp;lt;PackageVersion&amp;gt;&lt;/code&gt; を定義して package ごとの version を集中管理する。
配下の各 project では &lt;a href=&quot;https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files&quot; title=&quot;&lt;code&gt;PackageReference&lt;/code&gt;&quot;&gt;&lt;code&gt;PackageReference&lt;/code&gt;&lt;/a&gt; に &lt;code&gt;Version&lt;/code&gt; 属性を指定せず、 &lt;code&gt;Directory.Packages.props&lt;/code&gt; で集中管理する。
これにより複数 project で参照される同一 package も同じ version を使うので手間が省けるってことみたい。&lt;/p&gt;
&lt;p&gt;CPM を使うと、これまで project の管理に入れてなかった F# の package &lt;a href=&quot;https://www.nuget.org/packages/fsharp.core&quot; title=&quot;&lt;code&gt;FSharp.Core&lt;/code&gt;&quot;&gt;&lt;code&gt;FSharp.Core&lt;/code&gt;&lt;/a&gt; も明示的に入れる必要があり、管理が厳密化された。
また &lt;a href=&quot;https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management#transitive-pinning&quot; title=&quot;&lt;code&gt;CentralPackageTransitivePinningEnabled=true&lt;/code&gt;&quot;&gt;&lt;code&gt;CentralPackageTransitivePinningEnabled=true&lt;/code&gt;&lt;/a&gt; にしてる。
これは transitive dependencies に同じ package がいた場合も強制するための設定。
他に &lt;a href=&quot;https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management#overriding-package-versions&quot; title=&quot;&lt;code&gt;CentralPackageVersionOverrideEnabled&lt;/code&gt;&quot;&gt;&lt;code&gt;CentralPackageVersionOverrideEnabled&lt;/code&gt;&lt;/a&gt; というのもあって、これは中央管理してる version の上書きを許可するかを指定できる。
pocof は指定忘れたので既定値で動いてるはず(既定値が &lt;code&gt;true&lt;/code&gt; &lt;code&gt;false&lt;/code&gt; どちらかは文書に書いてなかった)。
ガチガチ管理を進めるなら明示的に &lt;code&gt;false&lt;/code&gt; が良さそう。
これは後ほど変更しておきたい。&lt;/p&gt;
&lt;p&gt;CPM だと package 更新は手で直すしかないのかなと気になって試してみた。
以下の通り dotnet CLI で CPM でもうまく &lt;code&gt;Directory.Packages.props&lt;/code&gt; を更新できた。
あと地味に .NET 10 から sub command 体系が変わってるのをここで知った。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10/sdk#more-consistent-command-order&quot; title=&quot;What&amp;#39;s new in the SDK and tooling for .NET 10 | Microsoft Learn&quot;&gt;What&amp;#39;s new in the SDK and tooling for .NET 10 | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# .NET 9 まで(.NET 10 でも動く)&lt;/span&gt;&lt;br /&gt;dotnet add ./src/pocof package FSharp.Core &lt;span class=&quot;hljs-literal&quot;&gt;--version&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# .NET 10 から&lt;/span&gt;&lt;br /&gt;dotnet package add FSharp.Core &lt;span class=&quot;hljs-literal&quot;&gt;--version&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--project&lt;/span&gt; ./src/pocof
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ただ &lt;code&gt;Directory.Packages.props&lt;/code&gt; に体裁を整えるための改行とか入れてると全部吹っ飛ぶので、まあ考えどころやな。&lt;/p&gt;
&lt;p&gt;CPM 導入により package version がひとつのファイルにまとまっただけだが、結構 package の見通しが良くなったと気がするので、気に入っている。&lt;/p&gt;
&lt;p&gt;次は .NET 10 に上げた話。&lt;/p&gt;
&lt;p&gt;毎年恒例の最新 &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/announcing-dotnet-10/&quot; title=&quot;.NET 10 が出た&quot;&gt;.NET 10 が出た&lt;/a&gt;ので、 pocof は &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/389&quot; title=&quot;#389&quot;&gt;#389&lt;/a&gt; で対応した。
やることは決まりきってるのでそんなに困ることもないが、いつもと少し手順を変えている。
今回はいつも使ってる &lt;a href=&quot;https://chocolatey.org/install&quot; title=&quot;Chocolatey&quot;&gt;Chocolatey&lt;/a&gt; では &lt;a href=&quot;https://community.chocolatey.org/packages/dotnet-sdk/10.0.100&quot; title=&quot;.NET 10 SDK&quot;&gt;.NET 10 SDK&lt;/a&gt; がまだ承認されてなかったので、 &lt;a href=&quot;https://github.com/microsoft/winget-cli&quot; title=&quot;winget&quot;&gt;winget&lt;/a&gt; を使うことにした。
いま自分の PC の package 管理で winget を使ってるのは &lt;a href=&quot;https://github.com/microsoft/winget-pkgs/tree/452a15ba1a4d61db861fa381487d97a22127d164/manifests/m/Microsoft/OpenSSH/Preview&quot; title=&quot;OpenSSH&quot;&gt;OpenSSH&lt;/a&gt; だけなので、使い方を忘れるしメモっておく。
以下のコマンドで .NET 10 SDK を install した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# これだと確認 prompt が面倒&lt;/span&gt;&lt;br /&gt;winget install &lt;span class=&quot;hljs-literal&quot;&gt;--id&lt;/span&gt; Microsoft.DotNet.SDK.&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# これで完全自動化できる(管理者権限で実行すると)&lt;/span&gt;&lt;br /&gt;winget install &lt;span class=&quot;hljs-literal&quot;&gt;--id&lt;/span&gt; Microsoft.DotNet.SDK.&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--silent&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--accept-package-agreements&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--accept-source-agreements&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--exact&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コメントのとおりだが winget はデフォで確認プロンプトが面倒なのでゴテゴテと options をつけないといけないのが少し残念。
Chocolatey なら &lt;code&gt;choco upgrade dotnet -y&lt;/code&gt; やからな。&lt;/p&gt;
&lt;p&gt;あとは手で SDK version を書き換える感じだけど、今回は PowerShell で簡単に &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/tools/global-json&quot; title=&quot;&lt;code&gt;global.json&lt;/code&gt;&quot;&gt;&lt;code&gt;global.json&lt;/code&gt;&lt;/a&gt; を変更できる関数を作った(初版 AI に作らせて)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Set-DotnetGlobalJson&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;(&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;# Path to global.json (default: ./global.json)&lt;/span&gt;&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Position&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Alias&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSPath&amp;#x27;&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;ValidateNotNullOrEmpty&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Path&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;global.json&amp;#x27;&lt;/span&gt;,&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;# Target major version (e.g. 10, 9)&lt;/span&gt;&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Major&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;,&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;# rollForward value to write&lt;/span&gt;&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;ValidateSet&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;disable&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;latestPatch&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;minor&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;latestMinor&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;major&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;latestMajor&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;latestFeature&amp;#x27;&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$RollForward&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;latestFeature&amp;#x27;&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Get-LatestDotnetSdkVersionForMajor&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;(&lt;br /&gt;            [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$Major&lt;/span&gt;&lt;br /&gt;        )&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$sdks&lt;/span&gt; = dotnet &lt;span class=&quot;hljs-literal&quot;&gt;--list-sdks&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&amp;gt;&lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$sdks&lt;/span&gt;) {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;No dotnet SDKs found. Make sure dotnet is on PATH.&amp;#x27;&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$versions&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$sdks&lt;/span&gt; |&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;                &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;quot;10.0.100 [C:\...]&amp;quot; → &amp;quot;10.0.100&amp;quot;&lt;/span&gt;&lt;br /&gt;                (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-split&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\s+&amp;#x27;&lt;/span&gt;)[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]&lt;br /&gt;            } |&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; {&lt;br /&gt;                &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;^\d+\.\d+\.\d+&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-and&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.StartsWith(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$Major&lt;/span&gt;.&amp;quot;&lt;/span&gt;)&lt;br /&gt;            } |&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;                [&lt;span class=&quot;hljs-type&quot;&gt;version&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$versions&lt;/span&gt;) {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;No .NET &lt;span class=&quot;hljs-variable&quot;&gt;$Major&lt;/span&gt; SDKs found. Please install .NET &lt;span class=&quot;hljs-variable&quot;&gt;$Major&lt;/span&gt; SDK first.&amp;quot;&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        (&lt;span class=&quot;hljs-variable&quot;&gt;$versions&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Sort-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Descending&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-First&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;).ToString()&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$version&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-LatestDotnetSdkVersionForMajor&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Major&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Major&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Detected latest .NET &lt;span class=&quot;hljs-variable&quot;&gt;$Major&lt;/span&gt; SDK: &lt;span class=&quot;hljs-variable&quot;&gt;$version&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$jsonObject&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;            sdk = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;                version = &lt;span class=&quot;hljs-variable&quot;&gt;$version&lt;/span&gt;&lt;br /&gt;                rollForward = &lt;span class=&quot;hljs-variable&quot;&gt;$RollForward&lt;/span&gt;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$json&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$jsonObject&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-Json&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Depth&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$resolved&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Resolve-Path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; SilentlyContinue&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$resolved&lt;/span&gt;) {&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$targetPath&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Join-Path&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Location&lt;/span&gt;) &lt;span class=&quot;hljs-variable&quot;&gt;$Path&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Creating new global.json at: &lt;span class=&quot;hljs-variable&quot;&gt;$targetPath&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$json&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Encoding&lt;/span&gt; UTF8 &lt;span class=&quot;hljs-variable&quot;&gt;$targetPath&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Updating existing global.json at: &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$resolved&lt;/span&gt;.Path)&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$json&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Encoding&lt;/span&gt; UTF8 &lt;span class=&quot;hljs-variable&quot;&gt;$resolved&lt;/span&gt;.Path&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;global.json updated to use SDK &lt;span class=&quot;hljs-variable&quot;&gt;$version&lt;/span&gt; (rollForward=&lt;span class=&quot;hljs-variable&quot;&gt;$RollForward&lt;/span&gt;).&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ForegroundColor&lt;/span&gt; Green&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Error&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この関数を作った動機は dotnet CLI に指定する full version をいちいち覚えてないから自動で設定したいというものだ。
&lt;code&gt;dotnet new globaljson --force --sdk-version 10&lt;/code&gt; でも full version が入ってほしいがそうはいかない。
あと &lt;code&gt;dotnet new globaljson --force&lt;/code&gt; で &lt;code&gt;global.json&lt;/code&gt; の末尾改行が削れるのも好きじゃない。
ちょっと安全じゃないかもなという気はすれど、自前でやるのがいいかなと考えた。
これで &lt;code&gt;Set-DotnetGlobalJson -Major 10&lt;/code&gt; のようにして簡単に &lt;code&gt;10.0.100&lt;/code&gt; に変更できる。楽だ。
(SDK を事前に install 済みである必要があるが)&lt;/p&gt;
&lt;p&gt;まだ pocof しか .NET SDK を更新してないから、他の repository でもちまちま更新していく予定。
その間 pocof は放置気味になるかも知れんが、できる限りぼちぼち進めたい。
Multi targeting にしたことで &lt;code&gt;netstandard2.0&lt;/code&gt; と &lt;code&gt;net6.0&lt;/code&gt; でパフォに差があるのかとか benchmark を見てないから測定するとか。
速くなってるなら、ここらで次の version として公開するのもいいしね。
Multi targeting した初回は怖いので alpha が妥当かも知れん。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 16 Nov 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-11-09-writing-cmdlet-in-fsharp-pt80.html</guid><link>https://krymtkts.github.io/posts/2025-11-09-writing-cmdlet-in-fsharp-pt80.html</link><title>F# で Cmdlet を書いてる pt.80 - Multi targeting</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発を少し進めた。
必要最低限の &lt;a href=&quot;https://learn.microsoft.com/en-us/visualstudio/msbuild/net-sdk-multitargeting&quot; title=&quot;Multi targeting&quot;&gt;Multi targeting&lt;/a&gt; を実現する変更をした。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/376&quot; title=&quot;#376&quot;&gt;#376&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PowerShell module で Multi targeting で build した dll を配信するなら、 .NET の Multi targeting の情報だけでは準備が足りない。
platform に適切な dll を読み込めるように PowerShell の module 構成についても知る必要がある。
&lt;a href=&quot;/posts/2025-11-02-writing-cmdlet-in-fsharp-pt79.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;、 PowerShell の loader script について書いてる文書がないと書いたが、見つけた。
ちゃんと準備されてたみたいで見つけられなかったのが恥ずかしい。
ここに &lt;a href=&quot;https://github.com/PowerShell/PSScriptAnalyzer&quot; title=&quot;PSScriptAnalyzer&quot;&gt;PSScriptAnalyzer&lt;/a&gt; の例が載ってる。これが公式版といえそう。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/gallery/concepts/module-psedition-support?view=powershellget-3.x#targeting-multiple-editions&quot; title=&quot;Modules with compatible PowerShell Editions - PowerShell | Microsoft Learn&quot;&gt;Modules with compatible PowerShell Editions - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PSScriptAnalyzer の repository のものはこちら。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSScriptAnalyzer/blob/main/Engine/PSScriptAnalyzer.psm1&quot; title=&quot;PSScriptAnalyzer/Engine/PSScriptAnalyzer.psm1 at main · PowerShell/PSScriptAnalyzer · GitHub&quot;&gt;PSScriptAnalyzer/Engine/PSScriptAnalyzer.psm1 at main · PowerShell/PSScriptAnalyzer · GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_editions?view=powershell-7.5#the-psedition-automatic-variable&quot; title=&quot;&lt;code&gt;$PSEdition&lt;/code&gt;&quot;&gt;&lt;code&gt;$PSEdition&lt;/code&gt;&lt;/a&gt; を利用する方法と loader script で細かく制御する方法の 2 つがあると書いてある。
ただ loader script という熟語は出てこないので、これは俗語みたいなもんか。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$PSEdition&lt;/code&gt; を利用する方法は PowerShell 5.1 以上で利用できるらしいので、 Windows PowerShell 5.1 と PowerShell すべてで使えることになる&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;。
因みに使える変数はいくつかあるが、使えないものを参照すると error になる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;PS C:\Users\takatoshi\dev\github.com\krymtkts\pocof&amp;gt; import-Module .\publish\pocof\pocof.psd1&lt;br /&gt;Import-Module: The module manifest &amp;#x27;C:\Users\takatoshi\dev\github.com\krymtkts\pocof\publish\pocof\pocof.psd1&amp;#x27; could not be processed because it is not a valid PowerShell module manifest file. Remove the elements that are not permitted: At C:\Users\takatoshi\dev\github.com\krymtkts\pocof\publish\pocof\pocof.psd1:12 char:22&lt;br /&gt;+     RootModule = if ($PSVersionTable) {&lt;br /&gt;+                      ~~~~~~~~~~~~~~~&lt;br /&gt;A variable that cannot be referenced in restricted language mode or a Data section is being referenced. Variables that can be referenced include the following: $PSCulture, $PSUICulture, $true, $false, $null, $PSScriptRoot, $PSEdition, $EnabledExperimentalFeatures.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;$PSEdition&lt;/code&gt; を使った分岐は記述が簡素になるが、今回は loader script を採用した。
これはなるべく広く PowerShell を最適化するために下限を .NET 6 としたため、 loader script でないと書けないからだ。
.NET 6 の PowerShell 7.2 はもう EOL してるので要らないといえばそうなので、そのうち .NET 8 を下限に変える可能性はある。&lt;/p&gt;
&lt;p&gt;pocof では以下のようにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_module_manifests?view=powershell-7.5#rootmodule&quot; title=&quot;&lt;code&gt;RootModule&lt;/code&gt;&quot;&gt;&lt;code&gt;RootModule&lt;/code&gt;&lt;/a&gt; は loader script を指定。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# Script module or binary module file associated with this manifest.&lt;/span&gt;&lt;br /&gt;    RootModule = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;pocof.psm1&amp;#x27;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;pocof.psm1&lt;/code&gt; で &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_automatic_variables?view=powershell-7.5#psversiontable&quot; title=&quot;&lt;code&gt;$PSVersionTable.PSVersion&lt;/code&gt;&quot;&gt;&lt;code&gt;$PSVersionTable.PSVersion&lt;/code&gt;&lt;/a&gt; を検査し load し分ける。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Script module for module &amp;#x27;pocof&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Based on https://learn.microsoft.com/en-us/powershell/gallery/concepts/module-psedition-support?view=powershellget-3.x#targeting-multiple-editions&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set-StrictMode&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Version&lt;/span&gt; Latest&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$PSModule&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$ExecutionContext&lt;/span&gt;.SessionState.Module&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$PSModuleRoot&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$PSModule&lt;/span&gt;.ModuleBase&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# NOTE: Import the appropriate nested binary module based on the current PowerShell version.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# https://learn.microsoft.com/en-us/powershell/scripting/install/powershell-support-lifecycle?view=powershell-7.5#powershell-end-of-support-dates&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$PSVersionTable&lt;/span&gt;.PSVersion &lt;span class=&quot;hljs-operator&quot;&gt;-lt&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Version&lt;/span&gt;]&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;7.2&amp;#x27;&lt;/span&gt;) {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$targetFramework&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;netstandard2.0&amp;#x27;&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$targetFramework&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;net6.0&amp;#x27;&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# NOTE: Build paths separately for Windows PowerShell compatibility.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$binaryModuleRoot&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Join-Path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$PSModuleRoot&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ChildPath&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$targetFramework&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$binaryModulePath&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Join-Path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$binaryModuleRoot&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ChildPath&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;pocof.dll&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$binaryModule&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Import-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$binaryModulePath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-PassThru&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Write-Verbose&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;pocof: Loaded &lt;span class=&quot;hljs-variable&quot;&gt;$targetFramework&lt;/span&gt; binary from &lt;span class=&quot;hljs-variable&quot;&gt;$binaryModulePath&lt;/span&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Verbose&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# NOTE: When the module is unloaded, remove the nested binary module that was loaded with it.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$PSModule&lt;/span&gt;.OnRemove = {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Remove-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ModuleInfo&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$binaryModule&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;loader script は後方互換を意識しないと、対応したい古い PowerShell で利用できない可能性がある。
例えば &lt;code&gt;Join-Path&lt;/code&gt; で &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/join-path?view=powershell-7.5#-additionalchildpath&quot; title=&quot;&lt;code&gt;AdditionalChildPath&lt;/code&gt;&quot;&gt;&lt;code&gt;AdditionalChildPath&lt;/code&gt;&lt;/a&gt; が使えるのは PowerShell 6.0 以降なので、後方互換のため複数回呼ぶ。&lt;/p&gt;
&lt;p&gt;あと、わたしがまだ Multi targeting に慣れてないので &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-verbose?view=powershell-7.5&quot; title=&quot;&lt;code&gt;Write-Verbose&lt;/code&gt;&quot;&gt;&lt;code&gt;Write-Verbose&lt;/code&gt;&lt;/a&gt; で読み込む module の情報を出力するようにしている。&lt;/p&gt;
&lt;p&gt;このようにして Multi targeting された project は明示的に &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build#options&quot; title=&quot;&lt;code&gt;framework&lt;/code&gt; option&quot;&gt;&lt;code&gt;framework&lt;/code&gt; option&lt;/a&gt; で対象を指定しないと build できない。
&lt;code&gt;net6.0&lt;/code&gt; と &lt;code&gt;netstandard2.0&lt;/code&gt; を明示的に指定するよう build script を調整した。
build した dll を publish 用の directory 出力するよう project の調整も必要だ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- Deploy the produced assembly --&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PublishDir&lt;/span&gt;&amp;gt;&lt;/span&gt;../../publish/pocof/$(TargetFramework)/&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;PublishDir&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで publish 用の directory にあるファイルはすべて Publish-PSResource で publish されるはず。
module 構成は以下のようにした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;C:\USERS\TAKATOSHI\DEV\GITHUB.COM\KRYMTKTS\POCOF\PUBLISH\POCOF&lt;br /&gt;|   .gitkeep&lt;br /&gt;|   pocof-Help.xml&lt;br /&gt;|   pocof.psd1&lt;br /&gt;|   pocof.psm1&lt;br /&gt;|&lt;br /&gt;+---net6.0&lt;br /&gt;|       FSharp.Core.dll&lt;br /&gt;|       pocof.dll&lt;br /&gt;|&lt;br /&gt;\---netstandard2.0&lt;br /&gt;        FSharp.Core.dll&lt;br /&gt;        pocof.dll
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;配信ファイルが増えてサイズが大きくなるがそれは許容するしかないか。
あとほんとにこれで publish が上手くいくか試してないので、テスト用の module で挙動をチェックしたい感じではある。&lt;/p&gt;
&lt;p&gt;Multi targeting で注意したい点がいくつかある。&lt;/p&gt;
&lt;p&gt;まず &lt;code&gt;net6.0&lt;/code&gt; を target して build した場合に &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/values/null-values#null-values-starting-with-f-9&quot; title=&quot;&lt;code&gt;Nullable&lt;/code&gt;&quot;&gt;&lt;code&gt;Nullable&lt;/code&gt;&lt;/a&gt; 有効化時の検査が &lt;code&gt;netstandard2.0&lt;/code&gt; より厳しくなる。
これは &lt;code&gt;null&lt;/code&gt; 避けすればいいだけだが、再現が難しい path は coverage を下げる原因にもなり得る。
また F# 開発を Visual Studio Code + Ionide で行っているが、 Multi targeting していると片方の build error しか検知できない。
Ionide は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#targetframeworks&quot; title=&quot;&lt;code&gt;TargetFrameworks&lt;/code&gt;&quot;&gt;&lt;code&gt;TargetFrameworks&lt;/code&gt;&lt;/a&gt; の先頭に書いた framework で build するようなので、 よりチェックが厳しい &lt;code&gt;net6.0&lt;/code&gt; を先頭にした。
開発時に &lt;code&gt;netstandard2.0&lt;/code&gt; での build 結果を見ることができないのは少し不安だが、 build script と CI でその点をカバーするつもり。&lt;/p&gt;
&lt;p&gt;あと、今後 framework の &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives#conditional-compilation&quot; title=&quot;conditional compilation symbols&quot;&gt;conditional compilation symbols&lt;/a&gt; で分岐するので、 unit testing や coverage もそれぞれ実行する必要がある。
test project が pocof の project 参照しているため、 parameter を付与して指定の &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#targetframework&quot; title=&quot;&lt;code&gt;TargetFramework&lt;/code&gt;&quot;&gt;&lt;code&gt;TargetFramework&lt;/code&gt;&lt;/a&gt; で build できるよう変更した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;ItemGroup&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;ProjectReference&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Include&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;..\pocof\pocof.fsproj&amp;quot;&lt;/span&gt;&lt;br /&gt;                      &lt;span class=&quot;hljs-attr&quot;&gt;Properties&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;TargetFramework=$(TestTargetFramework)&amp;quot;&lt;/span&gt;&lt;br /&gt;                      &lt;span class=&quot;hljs-attr&quot;&gt;Condition&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;#x27;$(TestTargetFramework)&amp;#x27; != &amp;#x27;&amp;#x27;&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;ProjectReference&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Include&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;..\pocof\pocof.fsproj&amp;quot;&lt;/span&gt;&lt;br /&gt;                      &lt;span class=&quot;hljs-attr&quot;&gt;Condition&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;#x27;$(TestTargetFramework)&amp;#x27; == &amp;#x27;&amp;#x27;&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;ItemGroup&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで 2 つの framework で実行できるので、まとめて実行するのは build script で吸収する。
まだ benchmark や memory layout を確認する project ではこれに対応していないので、特に benchmark については必要になり次第調整したい。&lt;/p&gt;
&lt;p&gt;2 つの &lt;code&gt;TargetFramework&lt;/code&gt; で coverage 計測したら当然 report も 2 つになる。
pocof では CI の coverage report に &lt;a href=&quot;https://about.codecov.io/&quot; title=&quot;Codecov&quot;&gt;Codecov&lt;/a&gt; を使っているが、幸い&lt;a href=&quot;https://github.com/codecov/codecov-action?tab=readme-ov-file#arguments&quot; title=&quot;複数 report に対応している&quot;&gt;複数 report に対応している&lt;/a&gt;のでまとめて送りつけることにした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Execute&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;All&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Tests&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;id:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;run_tests&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${{&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;inputs.shell&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;}}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|&lt;br /&gt;    Invoke-Psake -taskList TestAll&lt;br /&gt;    if (-not $psake.build_success) { exit 1 }&lt;br /&gt;    $reports = (Get-ChildItem ./src/pocof.Test/TestResults/coverage.*.cobertura.xml) -join &amp;#x27;,&amp;#x27;&lt;br /&gt;    &amp;quot;REPORT_PATHS=$reports&amp;quot; | Out-File -FilePath $env:GITHUB_OUTPUT -Append&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Upload&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;coverage&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;reports&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Codecov&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;codecov/codecov-action@v5&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;if:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;runner.os&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Linux&amp;#x27;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;with:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;file:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${{&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;steps.run_tests.outputs.REPORT_PATHS&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;}}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;env:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;CODECOV_TOKEN:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${{&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;inputs.codecov_token&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この日記を書いてる途中に気付いたが、 &lt;code&gt;file&lt;/code&gt; は非推奨なので &lt;code&gt;files&lt;/code&gt; に変えるのが正しいな。あとで直す。&lt;/p&gt;
&lt;p&gt;とりま build 構成と PowerShell module 構成についてのまとめはこんな感じかな。
ここまでやればこれまでの開発と同じように Multi targeting での開発もできるはずだ。
あとは conditional compilation symbols を使った実装で、 &lt;code&gt;net6.0&lt;/code&gt; と &lt;code&gt;netstandard2.0&lt;/code&gt; の両方でうまく開発する工夫が必要になってくる。
これは開発を進める中でよい落とし所を模索していきたい。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/install/powershell-support-lifecycle?view=powershell-7.5#powershell-end-of-support-dates&quot; title=&quot;PowerShell Support Lifecycle - PowerShell | Microsoft Learn&quot;&gt;PowerShell Support Lifecycle - PowerShell | Microsoft Learn&lt;/a&gt; の表を参照 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 09 Nov 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-11-02-writing-cmdlet-in-fsharp-pt79.html</guid><link>https://krymtkts.github.io/posts/2025-11-02-writing-cmdlet-in-fsharp-pt79.html</link><title>F# で Cmdlet を書いてる pt.79 - pocof 0.21.0</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今週末はビールとワインのイベントにのもあって &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発はできてない。
代わりにこれまでの改善を含めた &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.21.0&quot; title=&quot;0.21.0&quot;&gt;0.21.0&lt;/a&gt; をリリースをした。
2025-11 は .NET 10 が来るので、 pocof を .NET 10 で開発する準備として、これまでの改善をリリースを挟んでおくのが良いと考えた。&lt;/p&gt;
&lt;p&gt;0.21.0 での変更点は基本的に速度面メモリ面でのパフォ改善に尽きるので、 bug を仕込んでなければ特に使用感の変化なく使えるはずだ。
さらりと触ってる感覚では、内部的な最適化よりも描画の効率化が一番利いており、キビキビ描画されるようになった気がする。&lt;/p&gt;
&lt;p&gt;今後考えている pocof 開発の大きな変更点としては、 &lt;a href=&quot;https://learn.microsoft.com/en-us/visualstudio/msbuild/net-sdk-multitargeting&quot; title=&quot;Multi targeting&quot;&gt;Multi targeting&lt;/a&gt; に挑戦してみたいと考えている。
やはり &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-2-0&quot; title=&quot;.NET Standard 2.0&quot;&gt;.NET Standard 2.0&lt;/a&gt; に縛られたままだと高速化に限界があるので、新し目の platform に関してより最適化するならこれしかない。
ここで手を加えておくことによって、万が一にでも Windows PowerShell がくたばったとしても次に繋げやすいはずだ。&lt;/p&gt;
&lt;p&gt;ただこれまでの単純な PowerShell module 構造でなくなるので多少勉強が必要だが、多分やれる。
それもいい経験になるだろう。
これまで loader script で import する dll を切り分けるような PowerShell module はいくつか見たことがある。
アレの具体的な仕組みは勉強したことないので、これを機に学ぶ。
探し方が良くないのかそれを示した具体的な公式文書は見たことがないし、ダメもとでまずそれを探すところからかな。
これまで経験的にはそういうのは公式になさそうなので、検証用の module で色々試して、まとめればよいかと考えている。&lt;/p&gt;
&lt;p&gt;これは日記に何度も書いていることだが、仕事ではコスパ的にバランスしなくてやらないようなことでも、趣味プロならとことんやることができる。
改めて、これはほんと良いなと感じる。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 02 Nov 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-10-26-writing-cmdlet-in-fsharp-pt78.html</guid><link>https://krymtkts.github.io/posts/2025-10-26-writing-cmdlet-in-fsharp-pt78.html</link><title>F# で Cmdlet を書いてる pt.78</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; を開発した。&lt;/p&gt;
&lt;p&gt;前回に続き query の構文解析と実行部分に手を入れた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/373&quot; title=&quot;#373&quot;&gt;#373&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;query の構文解析は、従来の正規表現の利用をやめ自前の parser で組み立てるようにした。&lt;a href=&quot;/posts/2025-10-19-writing-cmdlet-in-fsharp-pt77.html&quot; title=&quot;前の日記&quot;&gt;前の日記&lt;/a&gt;のときとさほど変わってないかと。&lt;/p&gt;
&lt;p&gt;before&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;QueryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.353 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0343 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1007 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.01&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.6523&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.66 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.428 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0277 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0330 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.08&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.6866&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.8 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.672 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0522 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0813 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.2970&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.3 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.845 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0560 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0803 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.3657&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.58 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.018 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0741 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1317 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.9379&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.95 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.299 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0852 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2229 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.0370&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.34 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.332 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1034 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1669 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.5864&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.59 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.651 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1125 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1156 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.7237&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.13 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;after&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;QueryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.307 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0308 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0903 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.6638&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.71 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.278 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0254 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0465 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.98&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.08&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.6809&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.78 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.03&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.447 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0487 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0813 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.3199&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.4 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.532 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0501 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0634 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.3542&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.53 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.473 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2554 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.7449 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.24&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.9760&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.09 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.852 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0760 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1519 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.88&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.15&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.0218&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.28 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.879 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0973 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2073 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.6321&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.77 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.087 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1007 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1655 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.7008&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.04 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.02&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;次に手を加えたのは、絞り込みのための述語を生成していた部分。
わかりやすさのために関数を分けていたのを統合し、再帰による繰り返しを減らした。
そして色々試してより良くする方法を探した結果、&lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/fsharp/language-reference/code-quotations&quot; title=&quot;コードクォート&quot;&gt;コードクォート&lt;/a&gt;の利用をやめて lambda expression と loop に書き直した。
クエリの数が増えるほど効果があるのでコードクォートを使っていたが、実際のところ 10 クエリも組み合わせることがなく、 overhead が目立つと考えた。
また loop を使う等他の再帰化も合わせれば断然 lambda expression の方が速くてメモリも軽くできるので、コードクォートをやめ結局元に戻った。&lt;/p&gt;
&lt;p&gt;before&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;EntryCount&lt;/th&gt;
&lt;th&gt;QueryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Median&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen1&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;542.6 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.11 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18.99 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;535.4 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.6250&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.9766&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;63.91 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;541.9 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.68 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.31 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;539.3 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.6250&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.9766&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;64.04 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;257.3 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.62 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.50 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;256.6 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.38 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;260.2 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.10 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.31 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;261.3 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.38 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;792.0 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;22.19 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;61.85 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;771.3 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;35.1563&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;148.65 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;771.8 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.32 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;29.15 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;775.6 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;35.1563&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;148.64 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;262.8 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.24 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.75 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;262.5 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.48 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;258.5 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.76 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.35 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;258.5 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.48 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,040.2 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;20.52 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;34.29 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,037.0 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;62.5000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.9531&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;255.39 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,039.5 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;20.41 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;36.80 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,033.0 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;62.5000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.9531&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;255.39 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;259.9 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.14 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.01 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;259.5 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.6 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;261.1 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.11 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.64 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;259.8 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.6 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;539.5 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.77 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.82 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;538.3 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.6250&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.9766&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;63.9 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;539.7 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.67 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.98 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;539.0 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.6250&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.9766&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;63.9 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;256.6 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.11 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.89 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;256.0 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.38 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;265.8 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.29 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;14.11 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;261.6 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.38 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;769.6 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.05 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;24.30 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;766.6 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;35.1563&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;148.64 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;775.4 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;14.84 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;19.82 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;765.8 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;35.1563&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;148.64 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;262.3 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.20 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.39 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;263.0 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.48 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;260.7 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.10 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.48 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;259.6 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.48 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,054.5 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;19.16 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;33.05 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,052.0 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;62.5000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.9531&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;255.39 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,031.6 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;20.54 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;30.74 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,031.5 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;62.5000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.9531&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;255.39 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;261.9 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.59 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.59 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;259.7 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.6 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;259.9 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.10 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.98 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;258.9 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.3945&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.6 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;after&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;EntryCount&lt;/th&gt;
&lt;th&gt;QueryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Median&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen1&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;71.51 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.311 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.227 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;71.35 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.4512&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;50.85 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;61.02 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.835 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.740 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;60.98 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18.0664&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2441&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;73.76 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;45.92 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.737 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.928 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;44.66 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.8359&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;27.75 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;39.69 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.785 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.880 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;39.13 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.9063&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.06 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;68.25 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.129 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.056 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;67.89 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.9395&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;52.46 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;59.26 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.780 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.729 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;59.08 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18.0664&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;73.28 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;44.90 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.366 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.874 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;44.39 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.8359&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;27.84 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;39.88 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.797 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.815 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;40.17 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.9063&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.13 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;65.97 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.596 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.528 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;65.81 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.4512&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2441&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;50.87 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;61.32 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.718 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.671 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;61.38 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.8457&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;68.59 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;43.40 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.867 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.010 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;43.09 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.8359&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;27.96 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;38.44 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.767 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.788 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;38.41 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.0283&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.26 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;440.59 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.743 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;19.734 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;435.38 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;109.3750&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.9063&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;444.76 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;368.63 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.227 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.463 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;368.76 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;215.8203&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.9766&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;874.71 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;254.84 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.116 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17.647 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;250.79 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;50.2930&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;204.5 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;159.27 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.195 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.010 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;159.45 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.1133&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;65.35 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;421.16 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.228 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;13.972 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;421.89 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;112.3047&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;456.53 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;360.14 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.111 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.481 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;359.22 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;216.7969&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;878.04 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;252.63 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.263 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18.170 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;248.13 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;50.2930&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;204.58 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;163.12 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.105 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.974 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;161.47 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.1133&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;65.45 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;369.26 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.483 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.708 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;364.90 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;111.3281&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;457.44 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_normal&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;343.91 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.037 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.468 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;344.69 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;199.2188&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;809.26 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_obj_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;257.50 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.539 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;19.073 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;251.57 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;50.2930&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;204.71 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;run_dict_property&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;156.66 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.260 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9.247 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;155.36 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.1133&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;65.56 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;コードクォートは非常に魅力的だが、式の複雑化で node が増えると重くなる・ IL の最適化が効かないといったところで活かしきれなかった。
今後速さを求められるメタプロが必要な場面なら活かせるかなと。 pocof ではなさそうだが。&lt;/p&gt;
&lt;p&gt;修正して benchmark を取って... の繰り返しだととにかく benchmark 取得のための時間が必要なので、なかなか実装進められず疲れた。
改善アイディアを実装するたびに 5 ~ 10 分の検証時間がかかるのは結構ストレスだし、限られた時間しかない状態だと中々許容しにくい。
でも家事の隙間に benchmark を回したりで工夫したおかげでそこそこ満足がいく最適化にはなったかなという感触。
これで pocof の 次の version を出して使い始められる。
benchmark はなんかもう少し気軽に回せるような改善ができないか考えたい。&lt;/p&gt;
&lt;p&gt;この先もちまちま最適化していく。
クエリ関連では、述語を構築する際に差分コンパイルができたらいいなと考えているので、実験してみたい。
以前も触れたが、最適化において &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-2-0&quot; title=&quot;.NET Standard 2.0&quot;&gt;.NET Standard 2.0&lt;/a&gt; で使えない機能を使いたい場面が増えた。
そろそろ Windows PowerShell だけ .NET Standard 2.0 にして他はより新しい target framework にするとか考えた方が良いかも知れない。
多少なりとも複雑性をもたらすからおいそれと始められないけど、いい経験にはなりそうだ。&lt;/p&gt;
&lt;p&gt;あと 2025-11 は .NET 10 が来るので、乗り換えて高速化されるのを期待したい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 26 Oct 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-10-19-writing-cmdlet-in-fsharp-pt77.html</guid><link>https://krymtkts.github.io/posts/2025-10-19-writing-cmdlet-in-fsharp-pt77.html</link><title>F# で Cmdlet を書いてる pt.77</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; を開発した。&lt;/p&gt;
&lt;p&gt;とりあえず query を正規表現で分割してから組み立てるのでなくて自前の parser で組み立てるのに書き直し始めたところ。
Parser Combinator にするっつってたが、アレはやめた。
どうしても抽象度が上がって関数の数が増えることによる overhead で、さほど速くならないのがわかったからだ。
結局 pocof のような小規模な構文だと、小さな関数にまとめた方が圧倒的に速いのがわかってそうした。速さは正義だ。&lt;/p&gt;
&lt;p&gt;まず既存のコードに不足しているテストを足して benchmark を足して、そんでからまず単純に書き換えた版を作った。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/372&quot; title=&quot;#372&quot;&gt;#372&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;benchmark は以下の通り。&lt;/p&gt;
&lt;p&gt;before(regular expression)&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;QueryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Median&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.455 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0291 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0638 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.429 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.6828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.79 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.658 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0327 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0573 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.652 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.14&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.7210&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.95 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.06&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.872 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0574 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1353 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.830 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.3275&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.45 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.310 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0650 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1067 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.330 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.16&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.4267&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.84 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.07&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.249 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0847 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1484 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.224 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.9989&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.19 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.064 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0920 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2187 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.011 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.19&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.1439&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.78 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.07&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.615 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1081 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1585 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.626 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.6550&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.84 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.571 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1270 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1901 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.597 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.17&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.8381&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.6 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.07&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;after(tokenizer + parser)&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;QueryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.273 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0241 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0237 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.6828&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.79 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.334 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0261 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0428 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.7210&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.95 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.06&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.446 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0485 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0539 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.3313&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.45 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.640 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0527 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0881 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.08&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.4267&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.84 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.07&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.735 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0730 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1179 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.9989&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.19 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.968 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0778 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1115 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.1439&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.78 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.07&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.959 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0979 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1005 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.6550&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.84 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.168 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0983 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1244 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.8381&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.6 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.07&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;after(parser index)&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;QueryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.208 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0238 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0491 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.6523&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.66 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.239 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0245 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0490 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.6866&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.8 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.358 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0467 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1054 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.2970&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.3 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.517 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0492 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0875 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.3657&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.58 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.524 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0691 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1155 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.9455&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.95 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.753 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0741 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1530 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.0370&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.34 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prepareNormalQuery&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.680 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0932 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1861 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.5864&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.59 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preparePropertyQuery&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.999 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0990 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1810 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.7237&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.13 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;before(regular expression) が元で、 after(parser index) が最終形。
after(tokenizer + parser) は中間の状態で、元の tokenizer と parser が別れてたやつ。これも統合したほうが速くなった。
結果的に、普通の query と property query 共に元の 2 割ほど実行時間を短縮できた。&lt;/p&gt;
&lt;p&gt;さらにここから、差分 compile を導入するだとか、コードクォートで filtering の predicate を構築するのが別れてるのを統合するだとかができたら、更に良さそう。&lt;/p&gt;
&lt;p&gt;今回書いてみて思ったのが、効率が良い自前の parser を書くのは、実際のところ &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-2-0&quot; title=&quot;.NET Standard 2.0&quot;&gt;.NET Standard 2.0&lt;/a&gt; を target framework にしてると厳しい。
benchmark を取った訳では無いが、多分 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.readonlyspan-1?view=net-9.0&quot; title=&quot;ReadOnlySpan&quot;&gt;ReadOnlySpan&lt;/a&gt; を使えばまだ追求できるんじゃないかな。
やっぱ文字列操作が重いからな。
でも .NET Standard 2.0 では使えないから仕方がないね。&lt;/p&gt;
&lt;p&gt;将来的に multi target で build して配布するというのもアリかも知れないが、ややこしいしまだ本気では考えてない。
でも Windows PowerShell がいつなくなるかも決まってないから、 multi target が今後性能を追求していくとしたら一番現実的かな。&lt;/p&gt;
&lt;p&gt;query の parser を自前で書くのに着手する前は、気持ちを整えるため、ムダに割当されていた List の除去だったり諸々の改善と、その過程で見つけた旧来からの bug を修正していた。
結構しょぼい bug が残ってたので、前にも触れたがテストケースを更新するのも重要になってきたな～。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/370&quot; title=&quot;#370&quot;&gt;#370&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/371&quot; title=&quot;#371&quot;&gt;#371&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;結構書き換わってる気がするので、もうそろそろ新しいの出して自分の日々の仕事でも使おうかな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 19 Oct 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-10-12-writing-cmdlet-in-fsharp-pt76.html</guid><link>https://krymtkts.github.io/posts/2025-10-12-writing-cmdlet-in-fsharp-pt76.html</link><title>F# で Cmdlet を書いてる pt.76</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;漸くまとまった時間が取れるようになった。とりあえず毎週何もできないとかは当面ないと思われる。&lt;/p&gt;
&lt;p&gt;早速 &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; を開発した。
主に &lt;code&gt;String&lt;/code&gt; 操作の効率化だ。 hot path ではなるべく F# の &lt;code&gt;String&lt;/code&gt; module も使わないようにしてみている。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/368&quot; title=&quot;#368&quot;&gt;#368&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;benchmark をとってもみて極端に良くできたところもあれば、何故速くなった・遅くなったかわからないところもある。
効果が顕著そうなところを benchmark ピックアップする。&lt;/p&gt;
&lt;p&gt;修正前。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;QueryState_getCurrentProperty&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;89.43 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.249 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.595 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0267&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;112 B&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;QueryCondition_toString&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;26.93 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.862 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.486 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.0142&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8.38 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;invokeAction_AddQuery&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.144 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0228 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0577 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.4005&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.64 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;590.3 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11.59 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;24.44 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;681.4 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.35 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;14.70 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0477&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;200 B&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;修正後。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;QueryState_getCurrentProperty&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;51.49 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.229 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3.547 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0153&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;64 B&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;QueryCondition_toString&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.406 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0873 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2361 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;invokeAction_AddQuery&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.093 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0217 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0434 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.4005&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.64 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardChar&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;535.8 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10.61 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18.57 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0248&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;104 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;invokeAction_BackwardWord&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;689.1 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12.58 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;22.68 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0477&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;200 B&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-stringmodule.html#length&quot; title=&quot;&lt;code&gt;String.length&lt;/code&gt;&quot;&gt;&lt;code&gt;String.length&lt;/code&gt;&lt;/a&gt; が不要な箇所は直に &lt;code&gt;String.Length&lt;/code&gt; を使ってみるのは、実際に &lt;code&gt;StringModule.Length&lt;/code&gt; の呼び出しがなくなる分僅かに速くなる。
&lt;code&gt;invokeAction&lt;/code&gt; の &lt;code&gt;AddQuery&lt;/code&gt; や &lt;code&gt;BackwardChar&lt;/code&gt; はそれに当たるとだろう。
何故か &lt;code&gt;BackwardWord&lt;/code&gt; は遅くなってしまったが軽微な差なので誤差かな。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;QueryState.getCurrentProperty&lt;/code&gt; は中間文字列を生成していたのをやめて 4 割ほど高速化した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-patch&quot;&gt;         let getCurrentProperty (state: QueryState) =&lt;br /&gt;             let s =&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                state.Query&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                |&amp;gt; String.upToIndex state.Cursor&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                |&amp;gt; fun x -&amp;gt; String.fromIndex &amp;lt;| x.LastIndexOf &amp;quot; &amp;quot; + 1 &amp;lt;| x&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                let q, c = state.Query, state.Cursor&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                let start = if c &amp;gt; 0 then q.LastIndexOf(&amp;#x27; &amp;#x27;, c - 1) + 1 else 0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                q.Substring(start, c - start)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;また &lt;code&gt;QueryCondition.toString&lt;/code&gt; に関しては &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-list-1.html&quot; title=&quot;&lt;code&gt;list&lt;/code&gt;&quot;&gt;&lt;code&gt;list&lt;/code&gt;&lt;/a&gt; の生成と中間文字列の生成を一切なくすことで、比較にならないほど劇的に速くメモリも少なくできた。
代わりに愚直な match expression を採用したので、全てのケースがベタ書きされているので、一見するとギョッとする。
でもある意味 match expression で経路も網羅できてるし「正しい」使い方ではあるかな。
速さと省メモリは正義なのだ。&lt;/p&gt;
&lt;p&gt;今回修正を試みた中で、完全に読みが外れたのは String interpolation だ。
以下に例を示す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; InternalState &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; queryInfo (state&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; InternalState) (count&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot; %s&lt;span class=&quot;hljs-subst&quot;&gt;{state.QueryCondition &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; QueryCondition.toString}&lt;/span&gt; [%d&lt;span class=&quot;hljs-subst&quot;&gt;{count}&lt;/span&gt;]&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; InternalState &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; queryInfo (state&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; InternalState) (count&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            String.Concat(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;, QueryCondition.toString state.QueryCondition, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; [&amp;quot;&lt;/span&gt;, string count, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;]&amp;quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これらは C# での表現だと以下に compile されていた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[&lt;span class=&quot;hljs-meta&quot;&gt;CompilationArgumentCounts(new int[&lt;/span&gt;] { &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; })]&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;queryInfo&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;InternalState state, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; count&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; PrintfModule.PrintFormatToStringThen(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; PrintfFormat&amp;lt;&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;, Unit, &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;, Tuple&amp;lt;&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&amp;gt;&amp;gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; %s%P() [%d%P()]&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;object&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]&lt;br /&gt;    {&lt;br /&gt;        QueryConditionModule.toString(state.QueryCondition@),&lt;br /&gt;        count&lt;br /&gt;    }, &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;));&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[&lt;span class=&quot;hljs-meta&quot;&gt;CompilationArgumentCounts(new int[&lt;/span&gt;] { &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; })]&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;queryInfo&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;InternalState state, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; count&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt; + QueryConditionModule.toString(state.QueryCondition@) + &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; [&amp;quot;&lt;/span&gt; + ((IFormattable)(&lt;span class=&quot;hljs-built_in&quot;&gt;object&lt;/span&gt;)count).ToString(&lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;, CultureInfo.InvariantCulture) + &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;]&amp;quot;&lt;/span&gt;;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.string.concat?view=net-9.0&quot; title=&quot;&lt;code&gt;String.Concat&lt;/code&gt;&quot;&gt;&lt;code&gt;String.Concat&lt;/code&gt;&lt;/a&gt; の方が期待しない形になっているのがよく分かる。
なので断然 String interpolation の方が速い。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Median&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;InternalState_queryInfo&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0462 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0330 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0968 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Median&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;InternalState_queryInfo&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1410 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0528 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1516 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0935 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;このような細かいチューニングで、しかも最も遅いところから着手するわけでないという進め方は、仕事だと中々できない。
やはり趣味のプログラミングだからこそ、そのような重箱の隅をドリルしまくれる。&lt;/p&gt;
&lt;p&gt;当然、これらの分析と改善は今 pocof が使ってる .NET 9 でのみこうなるという可能性が十分にある。
それでもこういう挙動を少しずつ頭の中に積んでいくことで、一般的に F# のチューニングで言われているようなパターンの原理を理解できて、良い感じがする。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 12 Oct 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-10-05-writing-cmdlet-in-fsharp-pt75.html</guid><link>https://krymtkts.github.io/posts/2025-10-05-writing-cmdlet-in-fsharp-pt75.html</link><title>F# で Cmdlet を書いてる pt.75</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; を開発した。
でも週末の家族のお出かけがずっと続いていて、まとまった時間が取れず簡単なもののみ。
今日は大して実装もできてないし、今後の方針を定めるメモを記しておく。要はただの時間稼ぎだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/365&quot; title=&quot;#365&quot;&gt;#365&lt;/a&gt; しか merge してないが、コツコツと効果を測っては改善、あるいはコードが不整合な部分を徐々に直しているつもり。
そのプロセスの中で感じた課題感がいくつかある。&lt;/p&gt;
&lt;p&gt;例えば pocof の Sample-based testing が結構穴があるのは前から知ってたが、今回 refactoring 始めてみて改めて実感している。
微妙にエッジケースを外してたりして心もとない感じ。
そのへんも強化するとなれば Property-based testing に書き直すまとまった時間が必要となり、これまたハードルが高い。
でもそういう作り直しこそやる意味がある点ではある。&lt;/p&gt;
&lt;p&gt;他に、カーソルの制御に関してはもう実装が各所に散りすぎてるので、大幅に整理しないと自分でも何が起こってるかわからない感じはしてきた。
内部状態の整理はずっと課題感あったが億劫でやってなかった。そろそろ本格的にやるしかないか。&lt;/p&gt;
&lt;p&gt;あとキー入力から始まる一連の処理の中で、文字列操作が処理速度の中でそれなりに支配的であることが理解できてきた。
これについては比較的着手が容易だ。
なのでこれからは文字列の操作を減らしていく方向でも調整したいと考えている。
具体的には中間文字列の生成を減らすのが目的になる。
そうすることで heap に積む量を減らすのが狙いだ。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;InternalState&lt;/code&gt; や &lt;code&gt;QueryState&lt;/code&gt; ではそれなりに単発の &lt;code&gt;String&lt;/code&gt; 操作しかされない形になっているので、それ以外の箇所で中間文字列を作成しているような箇所を減らす。
ここまで対応したい内容が狭まると、自ずと対象も定まる。
pocof では入力した query を正規表現で分割するし、その結果を取り回すのも文字列操作だ。
なので query を読み取ってデータ構造に落とし込むには自前の parser を作るのがいいねという話になる。
これについては既に最近でいうと &lt;a href=&quot;https://krymtkts.github.io/posts/2025-08-10-writing-cmdlet-in-fsharp-pt69.html&quot; title=&quot;8 月ごろ&quot;&gt;8 月ごろ&lt;/a&gt; に触れてる。
つまり自分でもわかってたけど放置してただけの課題だ。&lt;/p&gt;
&lt;p&gt;2025-10 の半ばも過ぎれば毎週末何処かに行くような状況ではなくなるはずなので、なんとかまとまった時間が取りたい。
ただこの言葉自体何度も言っているし、もしそれも叶わないなら、今の生活スタイル自体を改める必要がある。
具体的には平日に個人開発の時間を確保するような感じ。
でもそれも家事育児で難易度が高い現状なので、仕事の成果を落とさず稼働時間を減らすような試みが必要なのかもなーというのが最近の悩み。
うまく実現できれば一段レベルアップできるかな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 05 Oct 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-09-28-writing-cmdlet-in-fsharp-pt74.html</guid><link>https://krymtkts.github.io/posts/2025-09-28-writing-cmdlet-in-fsharp-pt74.html</link><title>F# で Cmdlet を書いてる pt.74 - Reference Tuple と Struct Tuple</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; を開発した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/364&quot; title=&quot;#364&quot;&gt;#364&lt;/a&gt; で Reference Tuple を Struct Tuple に置き換えて allocation を抑えた。
全てのケースではないが一部高速化に寄与した。
色々勉強になったので、メモがてら記録しておく。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Reference Tuple は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.tuple?view=net-9.0&quot; title=&quot;&lt;code&gt;System.Tuple&lt;/code&gt;&quot;&gt;&lt;code&gt;System.Tuple&lt;/code&gt;&lt;/a&gt; に compile される。
Struct Tuple は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.valuetuple?view=net-9.0&quot; title=&quot;&lt;code&gt;System.ValueTuple&lt;/code&gt;&quot;&gt;&lt;code&gt;System.ValueTuple&lt;/code&gt;&lt;/a&gt; に compile される。
そのため F# の Struct Tuple は C# と Visual Basic の tuple と相互運用できる特徴があるらしい。
これらの情報は Microsoft Learn のページが詳しい(当然か)。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/tuples&quot; title=&quot;Tuples - F# | Microsoft Learn&quot;&gt;Tuples - F# | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Reference Tuple は、(64 bit なら) object header の 8B と method table pointer の 8B の計 16B がデフォルトで確保される&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;。
追加で定義した field 分のメモリが heap に確保される。
value type ではこの object header/method table pointer 分が節約できる。
代わりに引数等で渡したときに参照アドレスでなく値がコピーされる。
つまりサイズが大きい tuple だとコピー効率が悪くなって遅くなることがある。
小さい tuple であれば十分速くてメモリ効率もよく、特に hot path で改善効果が見込める。
概ね節約分に収まれば大丈夫だろう。&lt;/p&gt;
&lt;p&gt;ここまではわたしも知っていた value type の特徴だ。&lt;/p&gt;
&lt;p&gt;ここからは今回初めて知った Reference Tuple の振る舞いについて。
よく知られたものと思われるが、個人的におもしろかったので残しておく。&lt;/p&gt;
&lt;p&gt;先述の通り Reference Tuple を使っていると heap 割当が発生しそうで全部 Struct Tuple に変えたくなる。
だが benchmark 計測してみると、必ずしも heap 割当が発生するわけではなく、小さな Struct Tuple でも遅くなることもある。&lt;/p&gt;
&lt;p&gt;例えば以下は &lt;a href=&quot;https://github.com/icsharpcode/ILSpy&quot; title=&quot;ILSpy&quot;&gt;ILSpy&lt;/a&gt; で F# のコードを decompile して C# のコードで表したものだ。
前者は関数内の値の受け渡しに Struct Tuple を使っていた版で、後者は Reference Tuple を使っていた版。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// pocof, Version=0.20.0.0, Culture=neutral, PublicKeyToken=null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// Pocof.Handle&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;using&lt;/span&gt; Microsoft.FSharp.Core;&lt;br /&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-meta&quot;&gt;CompilationArgumentCounts(new int[&lt;/span&gt;] { &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; })]&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;Data.InternalState, Query.QueryContext&lt;/span&gt;) &lt;span class=&quot;hljs-title&quot;&gt;deleteForwardInput&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;Data.InternalState state, Query.QueryContext context&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; num = StringModule.Length(state.QueryState@.Query@);&lt;br /&gt;    Data.InputMode inputMode = state.QueryState@.InputMode@;&lt;br /&gt;    (Data.InternalState, Query.QueryContext, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;) valueTuple;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; num2;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (inputMode.Tag != &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        valueTuple = (state, context, state.QueryState@.Cursor@);&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        num2 = inputMode.count;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; num3 = state.QueryState@.Cursor@;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; num4 = state.QueryState@.Cursor@ - num2;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; num5 = ((num3 &amp;gt;= num4) ? num4 : num3);&lt;br /&gt;        (Data.InternalState, Query.QueryContext) tuple = FSharpFunc&amp;lt;&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, Data.InputMode&amp;gt;.InvokeFast(setCursor, num5, Data.InputMode.Input, state, context);&lt;br /&gt;        valueTuple = (tuple.Item1, tuple.Item2, num5);&lt;br /&gt;    }&lt;br /&gt;    Data.InternalState state2;&lt;br /&gt;    Query.QueryContext context2;&lt;br /&gt;    (state2, context2, num2) = valueTuple;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; removeCharsWithInputMode(Direction.Forward, num - num2, state2, context2);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// pocof, Version=0.20.0.0, Culture=neutral, PublicKeyToken=null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// Pocof.Handle&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;using&lt;/span&gt; Microsoft.FSharp.Core;&lt;br /&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-meta&quot;&gt;CompilationArgumentCounts(new int[&lt;/span&gt;] { &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; })]&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;Data.InternalState, Query.QueryContext&lt;/span&gt;) &lt;span class=&quot;hljs-title&quot;&gt;deleteForwardInput&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;Data.InternalState state, Query.QueryContext context&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; num = StringModule.Length(state.QueryState@.Query@);&lt;br /&gt;    Data.InputMode inputMode = state.QueryState@.InputMode@;&lt;br /&gt;    Data.InternalState state2;&lt;br /&gt;    Query.QueryContext context2;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; num2;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (inputMode.Tag != &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        state2 = state;&lt;br /&gt;        context2 = context;&lt;br /&gt;        num2 = state.QueryState@.Cursor@;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; num3 = inputMode.count;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; num4 = state.QueryState@.Cursor@;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; num5 = state.QueryState@.Cursor@ - num3;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; num6 = ((num4 &amp;gt;= num5) ? num5 : num4);&lt;br /&gt;        (Data.InternalState, Query.QueryContext) tuple = FSharpFunc&amp;lt;&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, Data.InputMode&amp;gt;.InvokeFast(setCursor, num6, Data.InputMode.Input, state, context);&lt;br /&gt;        Data.InternalState item = tuple.Item1;&lt;br /&gt;        Query.QueryContext item2 = tuple.Item2;&lt;br /&gt;        state2 = item;&lt;br /&gt;        context2 = item2;&lt;br /&gt;        num2 = num6;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; removeCharsWithInputMode(Direction.Forward, num - num2, state2, context2);&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Reference Tuple の方は、最適化で Reference Tuple の存在が消し去られているのだろうとわかる。
Struct Tuple の方は、そのまま関数内の値の受け渡しにも tuple が使われたままになることがあった。
その tuple がある分のコストがかかるので、この場合は Reference Tuple の方が速いしメモリの割当も少ない。
このような tuple が公開されていない場合は Struct Tuple が不利となる場合があると理解できる。&lt;/p&gt;
&lt;p&gt;でも例えば、公開された関数の戻り値が Reference Tuple の場合は、確実に Reference Tuple の利用が発生する。
以下は、前者は戻り値の型が Struct Tuple を使っていた版で、後者は Reference Tuple を使っていた版の F# → (decompile) → C# のコード。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;hljs-title&quot;&gt;Invoke&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;Unit unitVar0&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; windowHeight = &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.@this.rui.GetWindowHeight();&lt;br /&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, windowHeight - &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; Tuple&amp;lt;&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;Invoke&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;Unit unitVar0&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; windowHeight = &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.@this.rui.GetWindowHeight();&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Tuple&amp;lt;&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&amp;gt;(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, windowHeight - &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;);&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このケースでは前者が圧倒的に良い。
メモリも 4 + 4 + 4 + 4 = 16 byte のみ。
Reference Tuple なら object header + method table pointer = 16 byte が更に乗って 32 byte だからだ。&lt;/p&gt;
&lt;p&gt;端的に言えば Reference Tuple は F# の compile 時の optimization で優遇されているみたい、というのが今回具体的にわかった。
この特徴からも、よく言われる「 Benchmark を測って利用が最適か評価する」必要があるということになる。
いちいち計測するのも時間がかかって大変だが。
勉強になったわ～。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;どうも &lt;a href=&quot;https://github.com/dotnet/runtime/tree/main/docs/design/coreclr/botr&quot; title=&quot;The Book of the Runtime&quot;&gt;The Book of the Runtime&lt;/a&gt; を読めばそれがわかるらしいが調べられてない。わたしは &lt;a href=&quot;https://github.com/SergeyTeplyakov/ObjectLayoutInspector&quot; title=&quot;ObjectLayoutInspector&quot;&gt;ObjectLayoutInspector&lt;/a&gt; を使ってその存在を知っているだけだ。
また、いくつかの古い文書では可視化されたそれらの画像を確認できる。
&lt;a href=&quot;https://devblogs.microsoft.com/premier-developer/managed-object-internals-part-1-layout/&quot; title=&quot;Managed object internals, Part 1. The layout - Developer Support&quot;&gt;Managed object internals, Part 1. The layout - Developer Support&lt;/a&gt; は ObjectLayoutInspector 作者の記事。
&lt;a href=&quot;https://learn.microsoft.com/en-us/archive/msdn-magazine/2005/may/net-framework-internals-how-the-clr-creates-runtime-objects&quot; title=&quot;.NET Framework Internals: How the CLR Creates Runtime Objects | Microsoft Learn&quot;&gt;.NET Framework Internals: How the CLR Creates Runtime Objects | Microsoft Learn&lt;/a&gt; の ObjectInstance の節とか。 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 28 Sep 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-09-21-uninstall-pyenv-win.html</guid><link>https://krymtkts.github.io/posts/2025-09-21-uninstall-pyenv-win.html</link><title>Chocolatey で install した pyenv-win を uninstall する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;休みの日が家族とのお出かけで潰れがちで開発ネタが無くなってきたので、今日は小ネタを書く。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/astral-sh/uv&quot; title=&quot;uv&quot;&gt;uv&lt;/a&gt; を使うまでは長らく &lt;a href=&quot;https://github.com/pyenv-win/pyenv-win&quot; title=&quot;pyenv-win&quot;&gt;pyenv-win&lt;/a&gt; を使ってた。
でも uv 導入後は使わなくなって以降もそのまま放置していたので、思い立って pyenv-win を uninstall してみた。&lt;/p&gt;
&lt;p&gt;pyenv-win を &lt;a href=&quot;https://chocolatey.org/&quot; title=&quot;Chocolatey&quot;&gt;Chocolatey&lt;/a&gt; で install してたのでまずは &lt;code&gt;chocolatey&lt;/code&gt; で uninstall する。
わたしはいつも &lt;code&gt;chocolatey&lt;/code&gt; を使うときは &lt;code&gt;cmd&lt;/code&gt; でやる。 PowerShell を更新するときとかに面倒だからだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://community.chocolatey.org/packages/pyenv-win&quot; title=&quot;Chocolatey Software | pyenv-win 3.1.1&quot;&gt;Chocolatey Software | pyenv-win 3.1.1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;管理者権限で以下を実行した。
(&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/advanced-settings/sudo/&quot; title=&quot;Sudo for Windows&quot;&gt;Sudo for Windows&lt;/a&gt; が使えるようになってるがまだ余り試していないので古き良き手法で)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;C:\Users\takatoshi&amp;gt;choco uninstall pyenv-win -y&lt;br /&gt;Chocolatey v2.5.1&lt;br /&gt;Uninstalling the following packages:&lt;br /&gt;pyenv-win&lt;br /&gt;&lt;br /&gt;pyenv-win v3.1.1&lt;br /&gt; Skipping auto uninstaller - No registry snapshot.&lt;br /&gt; pyenv-win has been successfully uninstalled.&lt;br /&gt;Environment Vars (like PATH) have changed. Close/reopen your shell to&lt;br /&gt; see the changes (or in powershell/cmd.exe just type `refreshenv`).&lt;br /&gt;&lt;br /&gt;Chocolatey uninstalled 1/1 packages.&lt;br /&gt; See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Chocolatey の package によくある uninstall は何もしないやつだった。
なのでバイナリの除去とばらまかれた環境変数の掃除は自分でやる必要がある。&lt;/p&gt;
&lt;p&gt;まず、ばらまかれた環境変数に何があるかは以下の文書が参考になる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/pyenv-win/pyenv-win/blob/a22a0e2415ef0f9e7a95ce6e2aede468b18658ec/docs/installation.md#add-system-settings&quot; title=&quot;Add System Settings | pyenv-win/docs/installation.md at master · pyenv-win/pyenv-win&quot;&gt;Add System Settings | pyenv-win/docs/installation.md at master · pyenv-win/pyenv-win&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この辺を消せば良さそうだとわかる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;System.Environment&lt;/span&gt;]::SetEnvironmentVariable(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PYENV&amp;#x27;&lt;/span&gt;,&lt;span class=&quot;hljs-variable&quot;&gt;$env:USERPROFILE&lt;/span&gt; + &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\.pyenv\pyenv-win\&amp;quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;User&amp;quot;&lt;/span&gt;)&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;System.Environment&lt;/span&gt;]::SetEnvironmentVariable(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PYENV_ROOT&amp;#x27;&lt;/span&gt;,&lt;span class=&quot;hljs-variable&quot;&gt;$env:USERPROFILE&lt;/span&gt; + &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\.pyenv\pyenv-win\&amp;quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;User&amp;quot;&lt;/span&gt;)&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;System.Environment&lt;/span&gt;]::SetEnvironmentVariable(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PYENV_HOME&amp;#x27;&lt;/span&gt;,&lt;span class=&quot;hljs-variable&quot;&gt;$env:USERPROFILE&lt;/span&gt; + &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\.pyenv\pyenv-win\&amp;quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;User&amp;quot;&lt;/span&gt;)&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;System.Environment&lt;/span&gt;]::SetEnvironmentVariable(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;path&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$env:USERPROFILE&lt;/span&gt; + &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\.pyenv\pyenv-win\bin;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hljs-variable&quot;&gt;$env:USERPROFILE&lt;/span&gt; + &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\.pyenv\pyenv-win\shims;&amp;quot;&lt;/span&gt; + [&lt;span class=&quot;hljs-type&quot;&gt;System.Environment&lt;/span&gt;]::GetEnvironmentVariable(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;path&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;User&amp;quot;&lt;/span&gt;),&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;User&amp;quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;しかしわたしの環境では上記とは違った。 Chocolatey で入れてるからかな。
User variable の &lt;code&gt;path&lt;/code&gt; に含まれる pyenv-win の値は文書通りだった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;System.Environment&lt;/span&gt;]::GetEnvironmentVariables(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;User&amp;quot;&lt;/span&gt;).GetEnumerator() | ? Name &lt;span class=&quot;hljs-operator&quot;&gt;-Like&lt;/span&gt; pyenv&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 出力なし&lt;/span&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;System.Environment&lt;/span&gt;]::GetEnvironmentVariables(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Machine&amp;quot;&lt;/span&gt;).GetEnumerator() | ? Name &lt;span class=&quot;hljs-operator&quot;&gt;-Like&lt;/span&gt; pyenv&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name                           Value&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ----                           -----&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PYENV                          %USERPROFILE%\.pyenv\pyenv-win\&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;System.Environment&lt;/span&gt;]::GetEnvironmentVariable(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Path&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;User&amp;#x27;&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;-split&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;;&amp;#x27;&lt;/span&gt; | ? {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;pyenv&amp;#x27;&lt;/span&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# C:\Users\takatoshi\.pyenv\pyenv-win\bin&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# C:\Users\takatoshi\.pyenv\pyenv-win\shims&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以下を管理者権限で実行して消す。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.environment.setenvironmentvariable?view=net-9.0&quot; title=&quot;&lt;code&gt;SetEnvironmentVariable&lt;/code&gt;&quot;&gt;&lt;code&gt;SetEnvironmentVariable&lt;/code&gt;&lt;/a&gt; の第 2 引数を &lt;code&gt;&amp;#39;&amp;#39;&lt;/code&gt; と &lt;code&gt;$null&lt;/code&gt; にしても環境変数を消せなかったため reg 直に消した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$pyenv&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ItemProperty&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PYENV&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Remove-ItemProperty&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$pyenv&lt;/span&gt;.PSPath &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PYENV&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$filtered&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;System.Environment&lt;/span&gt;]::GetEnvironmentVariable(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;path&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;User&amp;#x27;&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;-split&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;;&amp;#x27;&lt;/span&gt; | ? {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-notmatch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;pyenv&amp;#x27;&lt;/span&gt;}&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;Environment&lt;/span&gt;]::SetEnvironmentVariable(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Path&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$filtered&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;;&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;User&amp;#x27;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;pyenv-win のバイナリがどこにあるかを確認し、消す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Command&lt;/span&gt; pyenv&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# CommandType     Name                                               Version    Source&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# -----------     ----                                               -------    ------&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ExternalScript  pyenv.ps1                                                     C:\Users\takatoshi\.pyenv\pyenv-win\bin\pyenv.ps1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt; ~/.pyenv
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ファイル数が多くて古い自機だと削除に十数秒かかった。&lt;/p&gt;
&lt;p&gt;多分これできれいになったはず。
他にも使わなくなったものが溜まってるだろうけど、目についたら消すって感じで。
今年買い替えるつもりだったがなんか時期を逃してしまって、いつまでこの古い Razer blade stealth 2017 を使うかわからない。
新しいのに買い替えるなら、ガッツリ使えるタイミングで買い替えたいもんな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 21 Sep 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-09-14-writing-cmdlet-in-fsharp-pt73.html</guid><link>https://krymtkts.github.io/posts/2025-09-14-writing-cmdlet-in-fsharp-pt73.html</link><title>F# で Cmdlet を書いてる pt.73 - pocof 0.20.0</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; を開発した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.20.0&quot; title=&quot;0.20.0&quot;&gt;0.20.0&lt;/a&gt; をリリースをした。&lt;/p&gt;
&lt;p&gt;benchmark 上は 100 万件とかの追加だともとより遅くなってそうだが、メモリ効率は良くなっているし全ての件数に於いて走査は速くなって。
あとは実際に使ってみて変な bug が無いかを見たい。
次はこれまた細かい効率化の修正を入れていこうと考えている。&lt;/p&gt;
&lt;p&gt;今回のリリースで更新を忘れていた Command help(&lt;code&gt;pocof-Help.xml&lt;/code&gt;) に word 単位の操作の shortcut が反映された。
その作業自体はたいしたことなかったが、最新の &lt;a href=&quot;https://github.com/PowerShell/platyPS&quot; title=&quot;PlatyPS&quot;&gt;PlatyPS&lt;/a&gt; を使うのが結構面倒だった。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/361&quot; title=&quot;#361&quot;&gt;#361&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今の最新は &lt;a href=&quot;https://www.powershellgallery.com/packages/Microsoft.PowerShell.PlatyPS/1.0.1&quot; title=&quot;Microsoft.PowerShell.PlatyPS v1.0.1&quot;&gt;Microsoft.PowerShell.PlatyPS v1.0.1&lt;/a&gt; 。
多分前回は &lt;a href=&quot;https://www.powershellgallery.com/packages/Microsoft.PowerShell.PlatyPS/1.0.0-preview1&quot; title=&quot;&lt;code&gt;1.0.0-preview1&lt;/code&gt;&quot;&gt;&lt;code&gt;1.0.0-preview1&lt;/code&gt;&lt;/a&gt; を使ってるのかな？随分変わってる。
この手の作業はいつもわからなくなるので &lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;&lt;code&gt;psake&lt;/code&gt;&quot;&gt;&lt;code&gt;psake&lt;/code&gt;&lt;/a&gt; の task にまとめているが、今まで通りのやり方だと出力結果がめちゃくちゃになるので、1 つずつ手で行った。
余談として、いつものことだが PowerShell Gallery の検索が機能してないときは、 &lt;code&gt;/packages/&lt;/code&gt; の後ろに直に package 名を打ち込んで飛ぶのが良い。&lt;/p&gt;
&lt;p&gt;まず最初に &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/update-markdowncommandhelp?view=ps-modules&quot; title=&quot;&lt;code&gt;Update-MarkdownCommandHelp&lt;/code&gt;&quot;&gt;&lt;code&gt;Update-MarkdownCommandHelp&lt;/code&gt;&lt;/a&gt; で既存の Markdown help を更新してみた。
この手順でセクション内の要素が何故か 2 重 3 重に出力されてしまうのでもうダメだなと判断。
既存ファイルを削除して &lt;a href=&quot;https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.platyps/new-markdowncommandhelp?view=ps-modules&quot; title=&quot;&lt;code&gt;New-MarkdownCommandHelp&lt;/code&gt;&quot;&gt;&lt;code&gt;New-MarkdownCommandHelp&lt;/code&gt;&lt;/a&gt; を実行後、差分を反映した。
こんな感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;New-MarkdownCommandHelp&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ModuleInfo&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Module&lt;/span&gt; pocof) &lt;span class=&quot;hljs-literal&quot;&gt;-OutputFolder&lt;/span&gt; .\docs\ &lt;span class=&quot;hljs-literal&quot;&gt;-HelpUri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://github.com/krymtkts/pocof/blob/main/docs/pocof/Select-Pocof.md&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Locale&lt;/span&gt; en&lt;span class=&quot;hljs-literal&quot;&gt;-US&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;前回リリース時にどの version を使ったか忘れてしまったが、 parameter に余分な &lt;code&gt;ParameterValue: []&lt;/code&gt; が生えて問題だった。
それが v1.0.1 だと解消されていた。
これは version up によるいいところだが、個人的には悪いところの方が多いと感じた。&lt;/p&gt;
&lt;p&gt;他、 Markdown の表の中に &lt;code&gt;.&lt;/code&gt; があると余計な改行が挟まれて表が崩れるようだった。
幸い実装予定から削った shortcut の除去により &lt;code&gt;.&lt;/code&gt; が消えて正しく生成されるようになった。&lt;/p&gt;
&lt;p&gt;そして最後の問題が、 &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/export-mamlcommandhelp?view=ps-modules&quot; title=&quot;&lt;code&gt;Export-MamlCommandHelp&lt;/code&gt;&quot;&gt;&lt;code&gt;Export-MamlCommandHelp&lt;/code&gt;&lt;/a&gt; 。
MAML help export 後に example の各 code block 直後に &lt;code&gt;&amp;lt;maml:para&amp;gt;&amp;amp;#x80;&amp;lt;/maml:para&amp;gt;&lt;/code&gt; が差し込まれてしまう。なんじゃこりゃ。
以下の issue と同じ問題に悩まされた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/platyPS/issues/799&quot; title=&quot;Export-MamlCommandHelp doesn&amp;#39;t handle fenced code blocks in examples · Issue #799 · PowerShell/platyPS&quot;&gt;Export-MamlCommandHelp doesn&amp;#39;t handle fenced code blocks in examples · Issue #799 · PowerShell/platyPS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上記の issue を読むに、この挙動は PlatyPS の仕様であり、 code block による sample code の例示が非推奨であるような印象を受けた。
ただし「bug ではありません。仕様です。」で issue が閉じられて以降は特に回答もなく、推奨される example の書き方はわからないままだ。
結局自動化の policy に反するが、出力結果に含まれる余計な &lt;code&gt;&amp;lt;maml:para&amp;gt;&amp;amp;#x80;&amp;lt;/maml:para&amp;gt;&lt;/code&gt; を手で削って MAML help を仕上げた。
実に残念や。&lt;/p&gt;
&lt;p&gt;今回はこれで乗り切ったが、次回もこれだとちょっと嫌だな。
挙動が意図したものか否かがわからないってのは結構きつい。
なのでもう少し PlatyPS の設計(&lt;a href=&quot;https://github.com/PowerShell/platyPS/tree/main/docs&quot; title=&quot;&lt;code&gt;/docs&lt;/code&gt;&quot;&gt;&lt;code&gt;/docs&lt;/code&gt;&lt;/a&gt; にあるみたい)を読んで理解を深めたい。
分量的にまありえられるものがなさそうだけど。&lt;/p&gt;
&lt;p&gt;パッと見 PlatyPS 自体は PlatyPS を使ってない。
&lt;a href=&quot;https://www.powershellgallery.com/packages/Microsoft.PowerShell.PlatyPS/&quot; title=&quot;&lt;code&gt;PowerShell Gallery&lt;/code&gt;&quot;&gt;&lt;code&gt;PowerShell Gallery&lt;/code&gt;&lt;/a&gt; を見ても downloads が他の PowerShell の package に比べてかなり低い。
これらから考えるとあまり使われてなくて機能が磨かれてないと見るのが妥当か。
こういう状況なので、自力でなんとかして調べていくための動機づけが中々難しいが、 AI サンに手伝ってもらったりで誤魔化しつつ進めていくかー。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 14 Sep 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-09-07-writing-cmdlet-in-fsharp-pt72.html</guid><link>https://krymtkts.github.io/posts/2025-09-07-writing-cmdlet-in-fsharp-pt72.html</link><title>F# で Cmdlet を書いてる pt.72 - Single-producer/single-consumer append-only buffer 改善</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; を開発した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentqueue-1?view=net-9.0&quot; title=&quot;&lt;code&gt;ConcurrentQueue&lt;/code&gt;&quot;&gt;&lt;code&gt;ConcurrentQueue&lt;/code&gt;&lt;/a&gt; に代わる collection の実装をまだやってた。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/358&quot; title=&quot;#358&quot;&gt;#358&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/359&quot; title=&quot;#359&quot;&gt;#359&lt;/a&gt; で実施。&lt;/p&gt;
&lt;p&gt;分岐の改善、 property access の削減等ちまちました改善と、あと bug が混入してたので coverage 100% にするためのテストを AI に追加させてみた。
大幅に性能が改善された感じではない。
でも個人的には勉強なったものもある。例えば &lt;a href=&quot;https://en.wikipedia.org/wiki/Happened-before&quot; title=&quot;Happened-before&quot;&gt;Happened-before&lt;/a&gt; や &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.methodimploptions?view=net-9.0&quot; title=&quot;&lt;code&gt;MethodImplOptions.AggressiveInlining&lt;/code&gt;&quot;&gt;&lt;code&gt;MethodImplOptions.AggressiveInlining&lt;/code&gt;&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;元々 SPSC append-only buffer では件数の読み書きと次の segment の更新に &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.volatile?view=net-9.0&quot; title=&quot;&lt;code&gt;Volatile&lt;/code&gt;&quot;&gt;&lt;code&gt;Volatile&lt;/code&gt;&lt;/a&gt; を利用していた。
次の segment の読みに &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.volatile.read?view=net-9.0&quot; title=&quot;&lt;code&gt;Volatile.Read&lt;/code&gt;&quot;&gt;&lt;code&gt;Volatile.Read&lt;/code&gt;&lt;/a&gt; が不要なのは happens-before 関係があるためだった。
実はこの次の segment の更新も同様みたいで、結局件数の読み書きによって次の segment の更新は保証されてるようだった。
以下にざっくり変更箇所を示す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;type SpscSegment&amp;lt;&amp;#x27;T&amp;gt;(capacity: int) =&lt;br /&gt;     let mutable next: SpscSegment&amp;lt;&amp;#x27;T&amp;gt; | null = null&lt;br /&gt;     member __.Items = items&lt;br /&gt;     member __.Capacity = items.Length&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    // NOTE: Non-volatile read: safe after reader has observed published count.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    member __.Next = next&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    // NOTE: Writer-side publish with volatile write to establish happens-before with count increment.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    member __.PublishNext(seg: SpscSegment&amp;lt;&amp;#x27;T&amp;gt;) = Volatile.Write(&amp;amp;next, seg)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    // NOTE: Non-volatile reads/writes are safe once the reader has observed the published SpscAppendOnlyBuffer.count.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    member __.Next&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        with get () = next&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        and set v = next &amp;lt;- v&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;type SpscAppendOnlyBuffer&amp;lt;&amp;#x27;T&amp;gt;() =&lt;br /&gt;     let readCount () = Volatile.Read(&amp;amp;count)&lt;br /&gt;     let writeCount (v: int) = Volatile.Write(&amp;amp;count, v)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    [&amp;lt;MethodImpl(MethodImplOptions.AggressiveInlining)&amp;gt;]&lt;/span&gt;&lt;br /&gt;     member __.Add(item: &amp;#x27;T) : unit =&lt;br /&gt;         // NOTE: Acquire local view of the current tail segment.&lt;br /&gt;         let t = tail&lt;br /&gt;         let idx = tailIndex&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        let cap = t.Capacity&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        if idx &amp;gt;= t.Capacity then&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        if idx &amp;gt;= cap then&lt;/span&gt;&lt;br /&gt;             // NOTE: Current segment is full: create a new one, link it, and advance tail.&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            let newSeg = SpscSegment&amp;lt;&amp;#x27;T&amp;gt;(min (t.Capacity &amp;lt;&amp;lt;&amp;lt; 1) segSizeMax)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            let newSeg = SpscSegment&amp;lt;&amp;#x27;T&amp;gt;(min (cap &amp;lt;&amp;lt;&amp;lt; 1) segSizeMax)&lt;/span&gt;&lt;br /&gt;             // NOTE: Publish linkage before the element becomes observable via count.&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            t.PublishNext newSeg&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            t.Next &amp;lt;- newSeg&lt;/span&gt;&lt;br /&gt;             tail &amp;lt;- newSeg&lt;br /&gt;             // NOTE: Write into the new tail&lt;br /&gt;             newSeg.Items[0] &amp;lt;- item&lt;br /&gt;             tailIndex &amp;lt;- 1&lt;br /&gt;         else&lt;br /&gt;             t.Items[idx] &amp;lt;- item&lt;br /&gt;             tailIndex &amp;lt;- idx + 1&lt;br /&gt;&lt;br /&gt;         // NOTE: Publish new count after the element write (happens-before for reader).&lt;br /&gt;         // NOTE: A volatile read is not required because SPSC guarantees a single writer.&lt;br /&gt;         writeCount (count + 1)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;AI に説明させたり順を追って注意深く読むとわかるのだけど、一目で「あ～ happens-before 関係やな(ｷﾘｯ」といえるくらいには理解したいな。&lt;/p&gt;
&lt;p&gt;あと &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.methodimploptions?view=net-9.0&quot; title=&quot;&lt;code&gt;MethodImplOptions.AggressiveInlining&lt;/code&gt;&quot;&gt;&lt;code&gt;MethodImplOptions.AggressiveInlining&lt;/code&gt;&lt;/a&gt; を初めて知った。
.NET の JIT に対して(少しは AOT に対しても) inlining したいというヒントを強く与える属性みたい。
あくまでヒントで必ずではない。例えばクソデカメソッドなんかだと inlining されないらしい。
SPSC append-only buffer の場合は元々付与したいメソッドが小さいので付けてなくても inlining されることが多いようだが、 hot path では付与する価値がある。
F# の inline は IL を複製するパターンで、こちらは JIT の実行時に複製を判断するという違いがある。&lt;/p&gt;
&lt;p&gt;今振り返ると &lt;code&gt;MoveNext&lt;/code&gt; と &lt;code&gt;Add&lt;/code&gt; にはつける意味あるが &lt;code&gt;GetEnumerator&lt;/code&gt; は呼び出し回数がさほど多くないだろうし意味なさそうだ。
まとめて属性を付けて bench 結果が改善したようだったのでそのままにしてたけど、削っていいな。&lt;/p&gt;
&lt;p&gt;最終的な benchmark はこんな感じだった。&lt;/p&gt;
&lt;p&gt;Add&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;EntryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen1&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen2&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ConcurrentQueue&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,853.6 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;49.35 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;141.60 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.01&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.0529&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.31 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;829.8 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16.53 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;33.40 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.45&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2575&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ConcurrentQueue&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;278,770.7 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5,498.68 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9,773.89 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;41.5039&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;41.5039&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;41.5039&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;257.83 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;88,778.9 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,691.91 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3,177.83 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.32&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.02&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;19.4092&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;79.66 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ConcurrentQueue&lt;/td&gt;
&lt;td&gt;1000000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;23,523,948.8 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;438,956.52 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;505,502.98 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;125.0000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;93.7500&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;93.7500&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16387.36 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer&lt;/td&gt;
&lt;td&gt;1000000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;27,094,229.8 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;427,652.16 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;357,108.92 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.15&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1281.2500&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;937.5000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7868.55 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.48&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Iterate&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;EntryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Median&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ConcurrentQueue_iterate&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;950.3 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18.94 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;54.04 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;950.3 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.08&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0172&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;72 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer_iterate&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;733.9 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;14.60 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;22.29 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;737.6 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.77&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0134&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;56 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.78&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ConcurrentQueue_iterate&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;79,012.7 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,571.08 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,989.13 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;78,779.6 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;72 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer_iterate&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;65,541.9 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,287.66 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,541.71 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;65,775.4 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.83&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;56 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.78&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ConcurrentQueue_iterate&lt;/td&gt;
&lt;td&gt;1000000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12,770,833.4 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;727,602.69 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,099,300.27 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12,829,000.0 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.25&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;74 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer_iterate&lt;/td&gt;
&lt;td&gt;1000000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8,072,519.3 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;442,006.93 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,232,138.74 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7,454,282.8 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.65&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.15&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;62 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.84&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;大量件数の追加以外は &lt;code&gt;ConcurrentQueue&lt;/code&gt; より良さそう。
&lt;code&gt;ConcurrentQueue&lt;/code&gt; は 32 ~ 1,048,576(1024 * 1024) の範囲で segment の要素数を決めてる。
これが大量件数の場合に利いてくるっぽい。
&lt;a href=&quot;https://github.com/dotnet/runtime/blob/4076cf5ddd119af41bc1122be8e079ff23003095/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs#L42-L49&quot; title=&quot;runtime/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs&quot;&gt;runtime/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;代わりに bench で gen2 が発生してるし、多分大量の要素があるケースで &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/large-object-heap&quot; title=&quot;LOH&quot;&gt;LOH&lt;/a&gt; が発生することは諦めてる設計と思われる。
まあ確かに queue にそんな件数溜まるのは、データが適切に捌けてないケースだけか。&lt;/p&gt;
&lt;p&gt;PowerShell の場合だと、 Cmdlet は呼び出しが終われば破棄されるが、そのときに LOH があると破棄のときに必ず回収されるものではない。
つまり同じ PowerShell の session で Cmdlet の実行を繰り返すと LOH が溜まり続けることになる。
この認識で合ってるかな。
こうしてみると、 pocof はなるべく LOH を発生させないようにして session を clean に保った方が無難に思えるな。
いま LOH の発生を嫌って segment 内の配列サイズを最大 1024 にしてる。
もし &lt;code&gt;ConcurrentQueue&lt;/code&gt; と同じようなクソデカ segment 方式にすれば多分速くなるけど LOH が発生しメモリが肥大化し続けそう。
.NET や PowerShell Cmdlet のメモリの仕組みに詳しくないので、もっと研究しておく必要があるな。&lt;/p&gt;
&lt;p&gt;とりあえず今のままが一旦良さそうに思えてきたな。
一応この現状で良さそうな踏ん切りはついてきたので、いい加減 pocof を新しい version で公開する方向で動くか。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 07 Sep 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-08-31-booklog-one-year.html</guid><link>https://krymtkts.github.io/posts/2025-08-31-booklog-one-year.html</link><title>booklog はじめて 1 年間過ぎてた</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;気づいたら booklog を始めてから 1 年間を超えてた。
&lt;a href=&quot;https://krymtkts.github.io/booklogs/2024.html#2024-08-19-1&quot; title=&quot;2024-08-19&quot;&gt;2024-08-19&lt;/a&gt; から booklog が始まって、昨日時点で 377 日連続して読書できてるらしい。
在宅勤務で失われてた読書習慣を取り戻した感じには十分なってんじゃないかな。&lt;/p&gt;
&lt;p&gt;1 年とちょっとの間、再読・つまみ読み・読み終わっていない本も含め 24 冊読めた。
真面目に選り分けた訳ではないのでアレだが、だいたい積読消化と買った本で半々くらいの割合になってると思われる。
今は昔ほど何でもかんでも気になった本を買ってるわけじゃないけど、今くらいのスピード感で買いつつ積読消化しつつをバランスよく運用するのが、現状ベストか。
当時とて読書スピードが積読スピードに負けて溜まっていくばかりだったし。&lt;/p&gt;
&lt;p&gt;単純計算して 1 ヶ月で 1 ~ 2 冊は読めてるのだけど、積読量が多いからもっと処理できる冊数を増やせると嬉しいところだ。
ただそうなると現状の booklog をつけるだけでは強制力が足りなくて、より多く時間を確保するための習慣が必要になるだろう。
例えば昼飯の休憩をきっかり 1 時間取って、その間に読めるだけ読み切るとか。
とはいえ瞬時に昼飯を処理して仕事を再開・フロー状態を維持するというような休憩の仕方なので、どうかな。
仕事は極めて裁量が高いので時間はどうとでも調整できるだろうけど、日中は割とずっと仕事モード ON なので影響がなあ。&lt;/p&gt;
&lt;p&gt;あと 1 年ほど続けてみてわかったのは、寝る前に読書するよりもなるべく夕方ぐらいまでに読書が済んでいる方が、自分の生活では就寝までのリズムがスムースなところ。
寝る前に落ち着いて読書して就寝、みたいなのも憧れるが、子どもの世話をしてるとそうはいかないし、読みきれなかったら寝る時間が遅くなって寝不足になりそうなので良くない。
子どもの宿題を見るタイミングで自分も読書するのが一番好みの感じだったのだが、あまり上手くいかなかった。
やれる日もあるが、並行して家事をする必要がある日になると確実に読書できるわけじゃなく、結局夕食後や寝る前の読書になりがちだった。
自分の習慣に関しては、締切に追われて何かするより、もっと制御できている計画通り感がほしい。&lt;/p&gt;
&lt;p&gt;ということで、今既に 2 年目に突入しているが、差し込みたい変化としては読むタイミングの調整を意識的に行うことかな。
当然予定がある休日等は日中の読書ができないわけだが(今日が早速まさにそう)、そこも何か別の手法を編み出したい。
1 年間できたらもうこの先も同じ負荷なら絶対できるというのが手にとってわかるのは、実によろしい。
絶対にできるという実感があれば、多少の変化でリスクを持ち込むのも楽しいものになる。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 31 Aug 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-08-24-writing-cmdlet-in-fsharp-pt71.html</guid><link>https://krymtkts.github.io/posts/2025-08-24-writing-cmdlet-in-fsharp-pt71.html</link><title>F# で Cmdlet を書いてる pt.71 - Single-producer/single-consumer append-only buffer</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; を開発した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentqueue-1?view=net-9.0&quot; title=&quot;&lt;code&gt;ConcurrentQueue&lt;/code&gt;&quot;&gt;&lt;code&gt;ConcurrentQueue&lt;/code&gt;&lt;/a&gt; に代わる collection の実装 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/357&quot; title=&quot;#357&quot;&gt;#357&lt;/a&gt; に関して。
書き込み / 読み込み thread が 1 つずつで追加しかしないという限定用途から Single-producer/single-consumer append-only buffer と呼ぶことにした。
前回は、 MPMC の &lt;code&gt;ConcurrentQueue&lt;/code&gt; より機能が少ない SPSC append-only buffer の方が遅くて残念な結果だったので、色々直した。
その結果、 &lt;code&gt;ConcurrentQueue&lt;/code&gt; を置き換える価値があるものにできた。
以下に比較の benchmark を記す。&lt;/p&gt;
&lt;p&gt;書き込みは以下の通り。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;EntryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen1&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen2&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ConcurrentQueue&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,803.8 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;43.06 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;124.25 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.0529&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.31 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;794.2 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15.84 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;30.14 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.44&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2575&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ConcurrentQueue&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;283,355.0 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5,653.88 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;13,326.85 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;41.5039&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;41.5039&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;41.5039&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;257.83 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;89,695.3 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,787.21 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,886.01 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.32&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.02&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;31.0059&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7.6904&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;127.38 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.49&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ConcurrentQueue&lt;/td&gt;
&lt;td&gt;1000000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;29,405,508.3 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,432,592.75 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4,178,940.60 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.02&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.20&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;125.0000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;93.7500&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;93.7500&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16387.36 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer&lt;/td&gt;
&lt;td&gt;1000000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;26,947,905.9 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;522,309.93 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;436,152.45 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.93&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.13&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1281.2500&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1187.5000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7878 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.48&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;読み込みは以下の通り。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;EntryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ConcurrentQueue_iterate&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;948.1 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;19.01 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;51.73 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.08&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0172&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;72 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer_iterate&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;858.9 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17.18 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;30.09 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.91&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0134&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;56 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.78&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ConcurrentQueue_iterate&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;81,575.8 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,601.53 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,445.71 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;72 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer_iterate&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;74,501.3 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,406.56 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,674.41 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.91&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;56 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.78&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ConcurrentQueue_iterate&lt;/td&gt;
&lt;td&gt;1000000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9,323,906.6 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;184,295.18 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;270,137.50 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;78 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer_iterate&lt;/td&gt;
&lt;td&gt;1000000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7,588,917.4 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;123,090.41 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;155,669.97 ns&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.81&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;59 B&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.76&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;書き込みで中規模まで大幅優位で、大規模でもわずかながら優位な感じ。
大規模でも性能を落としてきてるのは、 segment の拡張戦略があまり良くないことによるみたい。
ここはもっと改善ができたら良さそう。&lt;/p&gt;
&lt;p&gt;読み込みは全サイズで優位そう。大規模(1M)での効果が高く、全体的にメモリ確保量が半分以下なので、これも良さそう。
segment がでかすぎて長寿命化(Gen1 昇格)してるみたいなので、ここはもっと改善ができそうかな。
ただし segment のサイズを縮めた場合は segment の数が増えて列挙の遅さに繋がる可能性がある。&lt;/p&gt;
&lt;p&gt;性能改善に大きく寄与した具体的な変更は以下の通り。備忘のため GitHub Copilot と分析した結果も添えておく。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.volatile.read?view=net-9.0&quot; title=&quot;&lt;code&gt;Volatile.Read&lt;/code&gt;&quot;&gt;&lt;code&gt;Volatile.Read&lt;/code&gt;&lt;/a&gt; &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.volatile.write?view=net-9.0&quot; title=&quot;&lt;code&gt;Volatile.Write&lt;/code&gt;&quot;&gt;&lt;code&gt;Volatile.Write&lt;/code&gt;&lt;/a&gt; を極力少なくする&lt;ul&gt;
&lt;li&gt;&lt;code&gt;volatile&lt;/code&gt; 利用により、 .NET の JIT 最適化の制限とメモリアクセス増加で遅くなる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;(読みのみ)&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.ienumerator?view=net-9.0&quot; title=&quot;&lt;code&gt;IEnumerator&lt;/code&gt;&quot;&gt;&lt;code&gt;IEnumerator&lt;/code&gt;&lt;/a&gt; 実装に &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/sequences&quot; title=&quot;&lt;code&gt;seq&lt;/code&gt;&quot;&gt;&lt;code&gt;seq&lt;/code&gt;&lt;/a&gt; を使わず専用の struct enumerator を実装する&lt;ul&gt;
&lt;li&gt;&lt;code&gt;seq&lt;/code&gt; の汎用コードを使わないことで JIT 最適化したのと、 struct 化によるヒープ除去&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.volatile?view=net-9.0&quot; title=&quot;&lt;code&gt;Volatile&lt;/code&gt;&quot;&gt;&lt;code&gt;Volatile&lt;/code&gt;&lt;/a&gt; を少なくした改善はちょっとややこしかった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt; type SpscSegment&amp;lt;&amp;#x27;T&amp;gt;(capacity: int) =&lt;br /&gt;     let items: &amp;#x27;T array = Array.zeroCreate capacity&lt;br /&gt;     let mutable next: SpscSegment&amp;lt;&amp;#x27;T&amp;gt; | null = null&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    member _.Items = items&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    member _.Capacity = items.Length&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    member _.Next&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        with get () = Volatile.Read(&amp;amp;next)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        and set (v) = Volatile.Write(&amp;amp;next, v)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    member __.Items = items&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    member __.Capacity = items.Length&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    // NOTE: Non-volatile read: safe after reader has observed published count.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    member __.Next = next&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    // NOTE: Writer-side publish with volatile write to establish happens-before with count increment.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    member __.PublishNext(seg: SpscSegment&amp;lt;&amp;#x27;T&amp;gt;) = Volatile.Write(&amp;amp;next, seg)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;[&amp;lt;Sealed&amp;gt;]&lt;br /&gt; type SpscAppendOnlyBuffer&amp;lt;&amp;#x27;T&amp;gt;() =&lt;br /&gt;     // 略&lt;br /&gt;&lt;br /&gt;     // NOTE: Volatile helpers for count.&lt;br /&gt;     let readCount () = Volatile.Read(&amp;amp;count)&lt;br /&gt;     let writeCount (v: int) = Volatile.Write(&amp;amp;count, v)&lt;br /&gt;&lt;br /&gt;     member __.Add(item: &amp;#x27;T) : unit =&lt;br /&gt;         // NOTE: Acquire local view of the current tail segment.&lt;br /&gt;         let t = tail&lt;br /&gt;         let idx = tailIndex&lt;br /&gt;&lt;br /&gt;         if idx &amp;gt;= t.Capacity then&lt;br /&gt;             // NOTE: Current segment is full: create a new one, link it, and advance tail.&lt;br /&gt;             let newSeg = SpscSegment&amp;lt;&amp;#x27;T&amp;gt;(min (t.Capacity &amp;lt;&amp;lt;&amp;lt; 1) segSizeMax)&lt;br /&gt;             // NOTE: Publish linkage before the element becomes observable via count.&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            t.Next &amp;lt;- newSeg&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            t.PublishNext newSeg&lt;/span&gt;&lt;br /&gt;             tail &amp;lt;- newSeg&lt;br /&gt;             // NOTE: Write into the new tail&lt;br /&gt;             newSeg.Items[0] &amp;lt;- item&lt;br /&gt;             tailIndex &amp;lt;- 1&lt;br /&gt;         else&lt;br /&gt;             t.Items[idx] &amp;lt;- item&lt;br /&gt;             tailIndex &amp;lt;- idx + 1&lt;br /&gt;&lt;br /&gt;         // NOTE: Publish new count after the element write (happens-before for reader).&lt;br /&gt;         // NOTE: A volatile read is not required because SPSC guarantees a single writer.&lt;br /&gt;         writeCount (count + 1)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この seq を使った &lt;code&gt;IEnumerator&lt;/code&gt; 実装は遅かった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;     interface IEnumerable&amp;lt;&amp;#x27;T&amp;gt; with&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        member __.GetEnumerator() : IEnumerator&amp;lt;&amp;#x27;T&amp;gt; =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            // NOTE: Snapshot the count once; traverse segments accordingly.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            let snapshotCount = readCount ()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            let mutable remaining = snapshotCount&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            let mutable seg = head&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            let mutable idx = 0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            (seq {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                while remaining &amp;gt; 0 do&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    if idx &amp;gt;= seg.Capacity then&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                        seg &amp;lt;- seg.Next&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                        idx &amp;lt;- 0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    yield seg.Items[idx]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    idx &amp;lt;- idx + 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    remaining &amp;lt;- remaining - 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            })&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                .GetEnumerator()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;struct enumerator を実装することでコードは増えたが断然速くなった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+[&amp;lt;Struct&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+type SpscSegmentEnumerator&amp;lt;&amp;#x27;T&amp;gt; =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    val mutable private remaining: int&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    val mutable private seg: SpscSegment&amp;lt;&amp;#x27;T&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    val mutable private items: &amp;#x27;T array&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    val mutable private cap: int&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    val mutable private idx: int&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    val mutable private current: &amp;#x27;T&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    new(head: SpscSegment&amp;lt;&amp;#x27;T&amp;gt;, total: int) =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        let items = head.Items&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        { remaining = total&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          seg = head&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          items = items&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          cap = items.Length&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          idx = 0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          current = Unchecked.defaultof&amp;lt;&amp;#x27;T&amp;gt; }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    // NOTE: for F# pattern enumeration optimization (zero allocation via struct enumerator).&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    member __.Current = __.current&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    // NOTE: for F# pattern enumeration optimization (zero allocation via struct enumerator).&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    member __.MoveNext() =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        if __.remaining &amp;lt;= 0 then&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            false&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        else&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            if __.idx &amp;gt;= __.cap then&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                match __.seg.Next with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                | null -&amp;gt; __.remaining &amp;lt;- 0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                | next -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    __.seg &amp;lt;- next&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    let items = next.Items&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    __.items &amp;lt;- items&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    __.cap &amp;lt;- items.Length&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    __.idx &amp;lt;- 0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            if __.remaining &amp;gt; 0 then&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                let i = __.idx&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                __.current &amp;lt;- __.items[i]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                __.idx &amp;lt;- i + 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                __.remaining &amp;lt;- __.remaining - 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            else&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                false&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    // NOTE: No resources to release.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    member __.Dispose() = ()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    interface IEnumerator&amp;lt;&amp;#x27;T&amp;gt; with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        member __.Current = __.current&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    interface IEnumerator with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        member __.Current = box __.current&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        member __.MoveNext() = __.MoveNext()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        member _.Reset() = raise (NotSupportedException())&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    interface IDisposable with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        member __.Dispose() = __.Dispose()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;SpscSegmentEnumerator&lt;/code&gt; で &lt;code&gt;count&lt;/code&gt; 書き側の release (&lt;code&gt;Volatile.Write&lt;/code&gt;) と読み側の acquire (&lt;code&gt;Volatile.Read&lt;/code&gt;) が噛む publish 境界(&lt;a href=&quot;https://en.wikipedia.org/wiki/Happened-before&quot; title=&quot;happens-before&quot;&gt;happens-before&lt;/a&gt; の境界)になっている。
なので単調に一方向へ連結された segment の、読み込みに必要な範囲については余計な &lt;code&gt;volatile&lt;/code&gt; を省ける。
読み込み時は最初に snapshot した &lt;code&gt;count&lt;/code&gt; の要素数分は書き終えていることが保証され、残り要素数が 0 なら &lt;code&gt;next&lt;/code&gt; にアクセスすることもない。
だから &lt;code&gt;next&lt;/code&gt; の読みは &lt;code&gt;volatile&lt;/code&gt; なしでも安全に読める。
実は書き側も理論上 &lt;code&gt;next&lt;/code&gt; の &lt;code&gt;Volatile.Write&lt;/code&gt; を外せるようなのだが、まだちゃんと確認しきれていない。
release/acquire 、 happens-before といったキーワードをもっと理解したら削ってみるか。&lt;/p&gt;
&lt;p&gt;またこのデータ型は、大前提として SPSC append-only という限定用途のみにしか適さないので、他の用途が出てきたら使い物にならなくなる。
でも pocof であれば、今のところ他の用途の可能性がないので、多分当分このままでいける。&lt;/p&gt;
&lt;p&gt;改善できそうなところがまだ少し残ってるし、もう少し改善できたら良さげ。
&lt;code&gt;ConcurrentQueue&lt;/code&gt; が pocof の性能の支配的な部分ではないからここばかり改善しても大差ないのだが、趣味なのでヨシッ！&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 24 Aug 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-08-17-writing-cmdlet-in-fsharp-pt70.html</guid><link>https://krymtkts.github.io/posts/2025-08-17-writing-cmdlet-in-fsharp-pt70.html</link><title>F# で Cmdlet を書いてる pt.70 - Single-producer/single-consumer lock-free buffer(仮)</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.io.streamwriter.autoflush?view=net-9.0&quot; title=&quot;&lt;code&gt;StreamWriter.AutoFlush&lt;/code&gt;&quot;&gt;&lt;code&gt;StreamWriter.AutoFlush&lt;/code&gt;&lt;/a&gt; を無効にした console output の最適化は失敗した。
カーソル位置の計算が難しく、期待通りの挙動をさせるには、書き込みの都度 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.io.streamwriter.flush?view=net-9.0&quot; title=&quot;&lt;code&gt;StreamWriter.Flush&lt;/code&gt;&quot;&gt;&lt;code&gt;StreamWriter.Flush&lt;/code&gt;&lt;/a&gt; する必要があり、意味ないなと諦めた。
代わりに &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.console.write?view=net-9.0&quot; title=&quot;&lt;code&gt;Console.Write&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.Write&lt;/code&gt;&lt;/a&gt; の呼び出し回数を減らすための改善をした。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/351&quot; title=&quot;#351&quot;&gt;#351&lt;/a&gt;
I/O が減った分、 CPU が忙しいときも多少キビキビするようになった気はするかな。
&lt;code&gt;StreamWriter.AutoFlush&lt;/code&gt; 作戦は、経験を積んだあと再挑戦してもいいか。&lt;/p&gt;
&lt;p&gt;他にも hot path での list 生成をなくすとか struct を利用することで heap 割り当てをなくすとか。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/352&quot; title=&quot;#352&quot;&gt;#352&lt;/a&gt;
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/354&quot; title=&quot;#354&quot;&gt;#354&lt;/a&gt;
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/356&quot; title=&quot;#356&quot;&gt;#356&lt;/a&gt;
劇的に性能に影響のある修正ではないので、コツコツ積み重ねるようなものばかり。&lt;/p&gt;
&lt;p&gt;list 生成を減らすパターンは極端に hot な箇所なら劇的な効果があるが、今回特に顕著な差はなかった。
これ系の最適化を進めていると、やはり pocof の状態管理を担っている record が気になってくるところ。
小さい record に分割するか、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/byrefs&quot; title=&quot;&lt;code&gt;byref&lt;/code&gt;&quot;&gt;&lt;code&gt;byref&lt;/code&gt;&lt;/a&gt; を組み合わせるか。
この話はもう何度も書いてるが着手してないのはひとえに先述のようにそこまで劇的な変化がないからやる気が出ないのかもな。&lt;/p&gt;
&lt;p&gt;他方、今気になってるのは絞り込み対象のデータを保管するのに &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentqueue-1?view=net-9.0&quot; title=&quot;ConcurrentQueue&quot;&gt;ConcurrentQueue&lt;/a&gt; を利用している点だ。
書き込みのみの thread と読み込みのみの thread が分かれているので、安全に読み書きするためにと思って .NET にすでにある順序を保持するデータ構造を採用したらこうなった。
このケースはいわゆる Single-producer/single-consumer (SPSC) というパターンみたいで、 lock-free なデータ構造でも捌けるみたい。
内部的には分割された &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/arrays&quot; title=&quot;&lt;code&gt;array&lt;/code&gt;&quot;&gt;&lt;code&gt;array&lt;/code&gt;&lt;/a&gt; を持っているだけで、参照は head の、追加は tail の pointer を参照する。
例えば .NET の &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.arraylist?view=net-9.0&quot; title=&quot;&lt;code&gt;ArrayList&lt;/code&gt;&quot;&gt;&lt;code&gt;ArrayList&lt;/code&gt;&lt;/a&gt; 実装はサイズ拡張時に内部配列を swap するので、そのときに競合しうる。
SPSC lock-free buffer(仮) だと参照で決まったサイズまでしか読まないので書き込みと競合しない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ConcurrentQueue&lt;/code&gt; は複数 thread からの書き込みに対応してる点からも書き込み時点で順序保持するため何らかの lock をしていそうと考えた。
であれば lock-free なデータ構造よりも追加時の overhead がある。
なので、もしかしたらデータ構造の変更で速くなるかもなと検証を始めた。&lt;/p&gt;
&lt;p&gt;ところが試しに実装してみたところ成果が出なかった。
&lt;a href=&quot;https://github.com/dotnet/BenchmarkDotNet&quot; title=&quot;BenchmarkDotNet&quot;&gt;BenchmarkDotNet&lt;/a&gt; で追加だけ 100 件・ 10,000 件・ 1,000,000 件を計測してみた。
10,000 件はなぜか順調だが、 100 件は差がなく、 1,000,000 件のような大量件数だとむしろ遅い。&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/357&quot; title=&quot;#357&quot;&gt;#357&lt;/a&gt;
segment のサイズを固定にしてるので、件数が少ないとメモリが過剰だが、多いときは良さそう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;// Benchmark Process Environment Information:&lt;br /&gt;// BenchmarkDotNet v0.14.0&lt;br /&gt;// Runtime=.NET 9.0.8 (9.0.825.36511), X64 RyuJIT AVX2&lt;br /&gt;// GC=Concurrent Workstation&lt;br /&gt;// HardwareIntrinsics=AVX2,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256&lt;br /&gt;// Job: DefaultJob
&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;EntryCount&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Mean&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Error&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;StdDev&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Ratio&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;RatioSD&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen0&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen1&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Gen2&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Allocated&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Alloc Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ConcurrentQueue&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.413 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1075 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2492 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.2948&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.0076&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21.63 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5.507 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.1088 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.2069 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.02&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6.2103&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;25.41 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ConcurrentQueue&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,019.421 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;40.3491 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;76.7684 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;351.5625&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;230.4688&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;82.0313&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2279.87 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,071.990 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;20.8937 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;35.4790 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.53&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;353.5156&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;335.9375&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;-&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2102.62 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.92&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ConcurrentQueue&lt;/td&gt;
&lt;td&gt;100000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;54,099.111 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,072.9361 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1,235.5948 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4100.0000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2400.0000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;800.0000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;22354.19 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpscAppendOnlyBuffer&lt;/td&gt;
&lt;td&gt;100000&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;56,827.114 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2,239.2215 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6,167.4668 us&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1.05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.12&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4181.8182&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2454.5455&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;818.1818&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21093.03 KB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.94&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;当然だが &lt;code&gt;ConcurrentQueue&lt;/code&gt; は相当速いな。
実装見てなかったので調べてみたら、同じ原理を利用して極力 lock-free で動くようになってた。
実装をみたらわかるが、 Compare And Swap (CAS)というパターンを使っているみたい。
なので lock が必要になるような競合が発生しない限りは十分に速いわ。振り出しに戻ってしまった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/runtime/blob/58d1c2e3e9bc76a4a9e02af75eeba210800f54eb/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs&quot; title=&quot;runtime/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs&quot;&gt;runtime/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/faq-are-all-of-the-new-concurrent-collections-lock-free/&quot; title=&quot;FAQ :: Are all of the new concurrent collections lock-free? - .NET Blog&quot;&gt;FAQ :: Are all of the new concurrent collections lock-free? - .NET Blog&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;blockquote&gt;
&lt;p&gt;ConcurrentQueue&lt;T&gt; and ConcurrentStack&lt;T&gt; are completely lock-free in this way. They will never take a lock, but they may end up spinning and retrying an operation when faced with contention (when the CAS operations fail).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;薄々気づいてはいたが、もうデータ保持の形式に関しては trie を採用しない状態でできることはなさそうな感じしてきた。
でも pocof での SPSC append-only な用途の方が明らかにやること少ないし、このまま諦めるのはなんか違う気がするな。
少しでも何かできることないんかな～。悪あがきしたい。
特に今回計測した追加のときよりも絞り込みのときの速度改善が肝(なんで今やらないかな)なので、そこも含めて見極めたいな。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 17 Aug 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-08-10-writing-cmdlet-in-fsharp-pt69.html</guid><link>https://krymtkts.github.io/posts/2025-08-10-writing-cmdlet-in-fsharp-pt69.html</link><title>F# で Cmdlet を書いてる pt.69 - Task.Run と task expression</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;keyboard 入力を読み取り描画イベントを起こす main loop を async + tail recursion から task + while loop に変えた。
はじめ単純に &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/async-expressions&quot; title=&quot;async expression&quot;&gt;async expression&lt;/a&gt; を &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/task-expressions&quot; title=&quot;task expression&quot;&gt;task expression&lt;/a&gt; に変えてみたが、処理が始まらなくなってしまった。
これは current thread で即座に task が実行されるから期待しない blocking が発生していたことによるらしい。
task expression は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions#do&quot; title=&quot;&lt;code&gt;do!&lt;/code&gt;&quot;&gt;&lt;code&gt;do!&lt;/code&gt;&lt;/a&gt; のような非同期操作を切り替わりのタイミングとして、別の thread に移るらしい。
なので初めから別 thread で動く &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run?view=net-9.0&quot; title=&quot;&lt;code&gt;Task.Run&lt;/code&gt;&quot;&gt;&lt;code&gt;Task.Run&lt;/code&gt;&lt;/a&gt; で実行するようにし、さらに結果を待ち受けるタイミングも変える必要があった。
考えたこともなかったが、 &lt;code&gt;Task.Run&lt;/code&gt; と task expression は実行が初めから別 thread に乗るか乗らないかの違いがあるらしい。
これは async expression で開始方法が様々提供されてるのと違う点なのかな。
以下の引用辺りか。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/task-expressions#syntax&quot; title=&quot;Task expressions - F# | Microsoft Learn&quot;&gt;Task expressions - F# | Microsoft Learn&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;blockquote&gt;
&lt;p&gt;The task is started immediately after this code is executed and runs on the current thread until its first asynchronous operation is performed (for example, an asynchronous sleep, asynchronous I/O, or other primitive asynchronous operation).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run?view=net-9.0#system-threading-tasks-task-run(system-func((system-threading-tasks-task)))&quot; title=&quot;Task.Run Method (System.Threading.Tasks) | Microsoft Learn&quot;&gt;Task.Run Method (System.Threading.Tasks) | Microsoft Learn&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;blockquote&gt;
&lt;p&gt;Queues the specified work to run on the thread pool and returns a proxy for the task returned by function.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;今回の変更により、元の async + tail recursion から多少の overhead は減ったろうが、 tail recursion 最適化があるし速度への寄与は微々たるものと思われる。
でもこの基礎的な挙動をちゃんと理解できたという点で収穫ありかな。
.NET 力の低さを多少は改善できただろう。&lt;/p&gt;
&lt;p&gt;これからやりたいこととしては、やっぱり console output の最適化はやりたいなと考えている。
標準出力の &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.io.streamwriter.autoflush?view=net-9.0&quot; title=&quot;&lt;code&gt;StreamWriter.AutoFlush&lt;/code&gt;&quot;&gt;&lt;code&gt;StreamWriter.AutoFlush&lt;/code&gt;&lt;/a&gt; を無効にして、手動で flush するやつ。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.console.writeline?view=net-9.0&quot; title=&quot;&lt;code&gt;Console.WriteLine&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.WriteLine&lt;/code&gt;&lt;/a&gt; を利用するための行数の調整が必要になるので多少難しかろうが。
100 万件を pocof で操作するような自機(Razer blade stealth 2017)の CPU 負荷が高いときだと顕著に描画が遅くモッサリ感あるので、速くしたい。&lt;/p&gt;
&lt;p&gt;クエリ構築部分も、正規表現で文字列を分割するようなのでなく、自前で parser を書いて構築するやつにしたい。&lt;/p&gt;
&lt;p&gt;あと全体的な高速化を一番やらないといけない。
だが、 state の受け渡し箇所を &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/byrefs&quot; title=&quot;&lt;code&gt;byref&lt;/code&gt;&quot;&gt;&lt;code&gt;byref&lt;/code&gt;&lt;/a&gt; を使って heap 割当を避けコピー削減するようなパターンしか思いつかない。
この部類の最適化は効果がさほどでないことも多いしあまり期待はできない。
一番遅いであろう &lt;code&gt;ConcurrentQueue&lt;/code&gt; の絞り込み部分をどうにかせんと極限のパフォーマンスに迫らないのだけど、まだ解決策を考えられてない。
非同期で描画する対応のとき手っ取り早く使える方法として &lt;code&gt;ConcurrentQueue&lt;/code&gt; を使ったが、読みと書きの thread が別れてるだけなのでより良い方法があるような。
より最適なデータ構造を選択するなり作るのが良さそうな気配はしてる。&lt;/p&gt;
&lt;p&gt;今後は、とりま抜本的な改善を GitHub Copilot なんかと相談しつつ、まず実装イメージが掴めている console output の最適化とクエリの parser 実装かな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 10 Aug 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-08-03-writing-cmdlet-in-fsharp-pt68.html</guid><link>https://krymtkts.github.io/posts/2025-08-03-writing-cmdlet-in-fsharp-pt68.html</link><title>F# で Cmdlet を書いてる pt.68 - WaitHandle を使う</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今週はまるで開発の時間が取れなかったが、久しぶりに &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。
&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/PSGameOfLife&quot;&gt;krymtkts/PSGameOfLife&lt;/a&gt; でいくつか高速化に関わる Tips を手に入れたので、それを輸入しようという魂胆だ。
ただ今のところは、それらをすぐに pocof で実現するのは難しそうだ、という結論になった。&lt;/p&gt;
&lt;p&gt;ひとつは、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.console.out?view=net-9.0&quot; title=&quot;&lt;code&gt;Console.Out&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.Out&lt;/code&gt;&lt;/a&gt; を &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.io.streamwriter.autoflush?view=net-9.0&quot; title=&quot;&lt;code&gt;StreamWriter.AutoFlush&lt;/code&gt;&quot;&gt;&lt;code&gt;StreamWriter.AutoFlush&lt;/code&gt;&lt;/a&gt; を無効にした &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.io.streamwriter?view=net-9.0&quot; title=&quot;&lt;code&gt;StreamWriter&lt;/code&gt;&quot;&gt;&lt;code&gt;StreamWriter&lt;/code&gt;&lt;/a&gt; で置き換える方法。
書き込み完了後に &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.io.streamwriter.flush?view=net-9.0&quot; title=&quot;&lt;code&gt;Flush&lt;/code&gt;&quot;&gt;&lt;code&gt;Flush&lt;/code&gt;&lt;/a&gt; することで &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.console?view=net-9.0&quot; title=&quot;&lt;code&gt;Console&lt;/code&gt;&quot;&gt;&lt;code&gt;Console&lt;/code&gt;&lt;/a&gt; の書き込み性能を高められる。
PSGameOfLife の CUI では非常に上手くいったが、 pocof の方は単純に導入できるものではなさそうだった。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.console.writeline?view=net-9.0&quot; title=&quot;&lt;code&gt;Console.WriteLine&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.WriteLine&lt;/code&gt;&lt;/a&gt; を使わないと 1 行の改行が適切に出力されない&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;ため、狙った印字にならない。
pocof は初期カーソル位置下部に必要な数の行を出力して描画スクリーンを作っている関係で、 &lt;code&gt;Console.WriteLine&lt;/code&gt; で自動で出力される改行と相性が悪いので、その調整が必要そう。
閾値の調整位で済めば導入も容易いのだけど、ややこしい部分なので億劫だ。&lt;/p&gt;
&lt;p&gt;もう 1 つは &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/async-expressions&quot; title=&quot;async expression&quot;&gt;async expression&lt;/a&gt; を &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/task-expressions&quot; title=&quot;task expression&quot;&gt;task expression&lt;/a&gt; に置き換える方法。
置き換えるだけなのでとても簡単なのだが、 pocof では F#らしく async expression と末尾再帰による無限 loop をしているので、 task だと末尾再帰を最適化できない。
つまり再帰をやめて &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/loops-while-do-expression&quot; title=&quot;&lt;code&gt;while&lt;/code&gt;&quot;&gt;&lt;code&gt;while&lt;/code&gt;&lt;/a&gt; に変える必要がある。
それは性能のために F# らしさをやめるということで、 pocof ではどうするかというのが悩ましい。
速いは正義なのでそれでいいのだけど、もうちょっと悩んでもいいかなと思ってやらなかった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;そんな感じで打つ手がなくなってしまった。
仕方ないので、これらの代わりに pocof での main loop(UI Thread) に相当する箇所の効率化を試しているところ。
最早 PSGameOfLife から得たアイディアでもない。
外出中に pocof のコードを読んでて &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.threading.thread.sleep?view=net-9.0&quot; title=&quot;&lt;code&gt;Thread.Sleep&lt;/code&gt;&quot;&gt;&lt;code&gt;Thread.Sleep&lt;/code&gt;&lt;/a&gt; があるのを思い出したので、これは良くないなと GitHub Copilot に相談して出てきたアイディア。
再帰による無限 loop で &lt;code&gt;Thread.Sleep&lt;/code&gt; を使っていたところを &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.waithandle?view=net-9.0&quot; title=&quot;&lt;code&gt;WaitHandle&lt;/code&gt;&quot;&gt;&lt;code&gt;WaitHandle&lt;/code&gt;&lt;/a&gt; で置き換えることで、 CPU の無駄使いを取り除く。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/347&quot; title=&quot;#347&quot;&gt;#347&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;diff --git a/src/pocof/Pocof.fs b/src/pocof/Pocof.fs&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;index d31c9c9..b29993b 100644&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;--- a/src/pocof/Pocof.fs&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;+++ b/src/pocof/Pocof.fs&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -188,6 +188,8 @@&lt;/span&gt; module Pocof =&lt;br /&gt;         let renderStack: RenderEvent Concurrent.ConcurrentStack =&lt;br /&gt;             Concurrent.ConcurrentStack()&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        let event = new AutoResetEvent(false)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;         [&amp;lt;TailCall&amp;gt;]&lt;br /&gt;         let rec getLatestEvent (h: RenderEvent) (es: RenderEvent list) =&lt;br /&gt;             match h with&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -205,9 +207,14 @@&lt;/span&gt; module Pocof =&lt;br /&gt;             | [] -&amp;gt; RenderMessage.None&lt;br /&gt;             | h :: es -&amp;gt; getLatestEvent h es |&amp;gt; RenderMessage.Received&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        member __.Publish = renderStack.Push&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        member __.Publish e =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            renderStack.Push e&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            event.Set() |&amp;gt; ignore&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        member __.Receive(block: bool) =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            if block then&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                event.WaitOne() |&amp;gt; ignore&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        member __.Receive() =&lt;/span&gt;&lt;br /&gt;             let items =&lt;br /&gt;                 match renderStack.Count with&lt;br /&gt;                 // NOTE: case of 0 is required for .NET Framework forward compatibility.&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -222,9 +229,12 @@&lt;/span&gt; module Pocof =&lt;br /&gt;&lt;br /&gt;     [&amp;lt;TailCall&amp;gt;]&lt;br /&gt;     let rec render (buff: Screen.Buff) (handler: RenderHandler) =&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        match handler.Receive() with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        match handler.Receive(block = true) with&lt;/span&gt;&lt;br /&gt;         | RenderMessage.None -&amp;gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            Thread.Sleep 10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            // NOTE: for backward compatibility.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+#if DEBUG&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            Logger.LogFile [ &amp;quot;render received RenderMessage.None.&amp;quot; ]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+#endif&lt;/span&gt;&lt;br /&gt;             render buff handler&lt;br /&gt;         | RenderMessage.Received RenderEvent.Quit -&amp;gt; ()&lt;br /&gt;         | RenderMessage.Received(RenderEvent.Render(state, entries, props)) -&amp;gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -257,7 +267,7 @@&lt;/span&gt; module Pocof =&lt;br /&gt;         | StopUpstreamCommands&lt;br /&gt;&lt;br /&gt;     let renderOnce (handler: RenderHandler) (buff: Screen.Buff) =&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        match handler.Receive() with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        match handler.Receive(block = false) with&lt;/span&gt;&lt;br /&gt;         | RenderMessage.None -&amp;gt; RenderProcess.Noop&lt;br /&gt;         | RenderMessage.Received RenderEvent.Quit -&amp;gt; RenderProcess.StopUpstreamCommands&lt;br /&gt;         | RenderMessage.Received(RenderEvent.Render(state, entries, props)) -&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;元々 &lt;code&gt;Thread.Sleep&lt;/code&gt; していた箇所は取り除き、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.waithandle.waitone?view=net-9.0&quot; title=&quot;&lt;code&gt;WaitOne&lt;/code&gt;&quot;&gt;&lt;code&gt;WaitOne&lt;/code&gt;&lt;/a&gt; で待ち受ける。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.cmdlet.processrecord?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;ProcessRecord&lt;/code&gt;&quot;&gt;&lt;code&gt;ProcessRecord&lt;/code&gt;&lt;/a&gt; から呼び出される描画処理を詰まらせないために non-blocking な option も提供する。&lt;/p&gt;
&lt;p&gt;いい感じなのだが、これらの差分はまだ実装途中で merge もしてない。
というのも pocof は結構 coverage が厳しいので、 engine 部分以外はゆるい PSGameOfLife と違い下手は変更が許容されないのを忘れてた。
&lt;code&gt;RenderMessage.None&lt;/code&gt; は発生することがないので消したいがまだ消せてない。おかげで coverage が低下している。なんとかせな。&lt;/p&gt;
&lt;p&gt;自分が書いてる F# の中では poof は legacy な部類なので、この様な形でちょいちょい更新していけたら良いなと考えている。&lt;/p&gt;
&lt;p&gt;多分続く。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;確か改行コードや ANSI escape sequence でもダメだったと記憶だが今度再確認する &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 03 Aug 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-07-27-writing-mini-game-in-fsharp-pt9.html</guid><link>https://krymtkts.github.io/posts/2025-07-27-writing-mini-game-in-fsharp-pt9.html</link><title>F# でミニゲームを書いてる Part 9</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife&quot; title=&quot;krymtkts/PSGameOfLife&quot;&gt;krymtkts/PSGameOfLife&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;世代交代の並列化と main loop を &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/async-expressions&quot; title=&quot;async expression&quot;&gt;async expression&lt;/a&gt; から &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/task-expressions&quot; title=&quot;task expression&quot;&gt;task expression&lt;/a&gt; に置き換えた。
&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/17&quot; title=&quot;#17&quot;&gt;#17&lt;/a&gt;
これで瞬間最大風速 3000 FPS 超えまできた(1 cell 10x10 dot の 50 x 50)。 2017 Razer blade stealth で。
速いなー。つまり理論上 300 ~ 400ns で 1 frame 描いてるのか。
これまで F# で書いてきたプログラムは &lt;code&gt;async&lt;/code&gt; と &lt;code&gt;task&lt;/code&gt; を使わけなくても &lt;code&gt;async&lt;/code&gt; で十分速いケースが多かった。
また &lt;code&gt;async&lt;/code&gt; の方が機能のサポートが手厚いし中々 &lt;code&gt;task&lt;/code&gt; を使うことがない。
でも実際に 1ms 以下の処理時間が必要なケースだと &lt;code&gt;task&lt;/code&gt; の方が .NET の最適化や overhead の少なさで速いみたい。
もっと積極的に &lt;code&gt;task&lt;/code&gt; を使ってもいいなと。いい経験になった。&lt;/p&gt;
&lt;p&gt;ただ、この改善により &lt;a href=&quot;https://docs.avaloniaui.net/docs/guides/development-guides/accessing-the-ui-thread&quot; title=&quot;UIThread&quot;&gt;UIThread&lt;/a&gt; が詰まるという現象が発生、 window を終了できなくなる問題が再発した。
今回のは何のことはない、 &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/T_Avalonia_Threading_Dispatcher&quot; title=&quot;&lt;code&gt;Dispatcher&lt;/code&gt;&quot;&gt;&lt;code&gt;Dispatcher&lt;/code&gt;&lt;/a&gt; で実行する優先順位が &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/F_Avalonia_Threading_DispatcherPriority_Render&quot; title=&quot;&lt;code&gt;Render&lt;/code&gt;&quot;&gt;&lt;code&gt;Render&lt;/code&gt;&lt;/a&gt; では高すぎて、 closed 等の event を block してしまうみたい。
代わりに何を選ぶべきか、提供されてる &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/T_Avalonia_Threading_DispatcherPriority#fields&quot; title=&quot;&lt;code&gt;DispatcherPriority&lt;/code&gt;&quot;&gt;&lt;code&gt;DispatcherPriority&lt;/code&gt;&lt;/a&gt; の文書を見てみたが、順位がよくわからなかった。書いてないようだけど。&lt;/p&gt;
&lt;p&gt;結局 &lt;a href=&quot;https://github.com/AvaloniaUI/Avalonia/blob/a15eae6833b934f2470d1af1c78fec896a19dc72/src/Avalonia.Base/Threading/DispatcherPriority.cs&quot; title=&quot;Avalonia の &lt;code&gt;DispatcherPriority&lt;/code&gt; のコード&quot;&gt;Avalonia の &lt;code&gt;DispatcherPriority&lt;/code&gt; のコード&lt;/a&gt;を直に参照した。
読み間違いがなければ、優先順位は以下の通りだった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;9: &lt;code&gt;MaxValue&lt;/code&gt;, &lt;code&gt;Send&lt;/code&gt;&lt;/li&gt;&lt;li&gt;8: &lt;code&gt;Normal&lt;/code&gt;&lt;/li&gt;&lt;li&gt;7: (obsolete) &lt;code&gt;DataBind&lt;/code&gt;&lt;/li&gt;&lt;li&gt;6: (private) &lt;code&gt;AsyncRenderTargetResize&lt;/code&gt;&lt;/li&gt;&lt;li&gt;5: (private) &lt;code&gt;BeforeRender&lt;/code&gt;&lt;/li&gt;&lt;li&gt;4: &lt;code&gt;Render&lt;/code&gt;&lt;/li&gt;&lt;li&gt;3: (internal) &lt;code&gt;AfterRender&lt;/code&gt;&lt;/li&gt;&lt;li&gt;2: (private) &lt;code&gt;UiThreadRender&lt;/code&gt;&lt;/li&gt;&lt;li&gt;1: &lt;code&gt;Loaded&lt;/code&gt;&lt;/li&gt;&lt;li&gt;0: &lt;code&gt;Default&lt;/code&gt;, (internal) &lt;code&gt;MinimumForegroundPriority&lt;/code&gt;&lt;/li&gt;&lt;li&gt;-1: &lt;code&gt;Input&lt;/code&gt;&lt;/li&gt;&lt;li&gt;-2: &lt;code&gt;Background&lt;/code&gt;&lt;/li&gt;&lt;li&gt;-3: &lt;code&gt;ContextIdle&lt;/code&gt;&lt;/li&gt;&lt;li&gt;-4: &lt;code&gt;ApplicationIdle&lt;/code&gt;&lt;/li&gt;&lt;li&gt;-5: &lt;code&gt;SystemIdle&lt;/code&gt;, (internal) &lt;code&gt;MinimumActiveValue&lt;/code&gt;&lt;/li&gt;&lt;li&gt;-6: &lt;code&gt;Inactive&lt;/code&gt;, (internal) &lt;code&gt;MinValue&lt;/code&gt;&lt;/li&gt;&lt;li&gt;-7: &lt;code&gt;Invalid&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;これに基づいて、強すぎず弱すぎずな &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/F_Avalonia_Threading_DispatcherPriority_Input&quot; title=&quot;&lt;code&gt;Input&lt;/code&gt;&quot;&gt;&lt;code&gt;Input&lt;/code&gt;&lt;/a&gt; にしておいた。
正直 &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/F_Avalonia_Threading_DispatcherPriority_Default&quot; title=&quot;&lt;code&gt;Default&lt;/code&gt;&quot;&gt;&lt;code&gt;Default&lt;/code&gt;&lt;/a&gt; でも問題なかろうが、 &lt;code&gt;Background&lt;/code&gt; 寄りは優先されて他の割り込みを許容するよう、調整してみたつもり。
GUI mode を作ってみて結構 Avalonia は文書に書いてないから、コードを見た方が理解しやすいこともわかってきた。&lt;/p&gt;
&lt;p&gt;GUI mode 追加に伴って MAML ヘルプファイル等の文書も整えた。 &lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/18&quot; title=&quot;#18&quot;&gt;#18&lt;/a&gt;
あとで PowerShell Gallery に公開しよう。
心配なのは大量の依存関係がある Cmdlet を公開したことがないので、上手くいくのかというところかな。
それも経験しないとわからんので、やってみるしかないな。&lt;/p&gt;
&lt;p&gt;今後は、PSGameOfLife には他にも追加していきたい機能があるので、それに着手しようか。
あるいは PSGameOfLife で得た知見を他のツールに反映するか。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 27 Jul 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-07-20-writing-mini-game-in-fsharp-pt8.html</guid><link>https://krymtkts.github.io/posts/2025-07-20-writing-mini-game-in-fsharp-pt8.html</link><title>F# でミニゲームを書いてる Part 8</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife&quot; title=&quot;krymtkts/PSGameOfLife&quot;&gt;krymtkts/PSGameOfLife&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2025-07-13-writing-mini-game-in-fsharp-pt7.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt; こう書いた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ゲームの core な部分はまだ改善できそう。
array を使うようにはしてるけど、 array の再生成を最小限にするとかの最適化はそれほどやってないし。
ただそこに手をいれるには現状の simple な盤面の管理を二重にしてやる必要があって、気が進まない。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;面倒だったのだけど試しに array の生成をやめてみたら FPS が 2 倍ほど高速化された。流石に笑える。
なので気が進まないとかそっちのけで対応した。
描画範囲外の隣接 cell を除外するところで &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-arraymodule.html#choose&quot; title=&quot;&lt;code&gt;Array.choose&lt;/code&gt;&quot;&gt;&lt;code&gt;Array.choose&lt;/code&gt;&lt;/a&gt; を使って array を生成していたので、単純な &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/loops-for-in-expression&quot; title=&quot;&lt;code&gt;for&lt;/code&gt;&quot;&gt;&lt;code&gt;for&lt;/code&gt;&lt;/a&gt; loop に置き換え。
FP ぽくないが性能のためには仕方ないのだ。&lt;/p&gt;
&lt;p&gt;またこれも前回触れた二重 buffer 方式を一番単純な関数の引数にとる形で実装した。
世代交代の度に 2 つの buffer を入れ替えて使う。
そのため &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/byrefs#outref-semantics&quot; title=&quot;&lt;code&gt;outref&lt;/code&gt;&quot;&gt;&lt;code&gt;outref&lt;/code&gt;&lt;/a&gt; を用いて mutable な操作を使うように変えている。
&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/blob/0140b2104bbb72558f462042134d85dc31ffbd20/src/PSGameOfLife/Core.fs#L49-L70&quot; title=&quot;コード&quot;&gt;コード&lt;/a&gt;は以下のようにした。
処理を関数に小分けして分かりやすくしていたのもやめて全部統合したので、ちょっと見通しは悪いかも知れない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; nextGeneration (buffer&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;outref&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;Cell[,]&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;) (board&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;outref&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;Board&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; columns &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; int board.Column&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; rows &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; int board.Row&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; tmp &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; buffer&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; y &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;..&lt;/span&gt; rows &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;..&lt;/span&gt; columns &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;mutable&lt;/span&gt; lives &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; dx, dy &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; neighborOffsets &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; nx, ny &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; dx, y &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; dy&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; nx &lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; nx &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt; columns &lt;span class=&quot;hljs-operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ny &lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ny &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt; rows &lt;span class=&quot;hljs-operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; board.Cells.[ny, nx].IsLive &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;                    lives &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; lives &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            tmp.[y, x] &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; nextCellState board.Cells.[y, x] lives&lt;br /&gt;&lt;br /&gt;    buffer &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; board.Cells&lt;br /&gt;    board.Generation &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; board.Generation &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;    board.Lives &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; tmp &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; countLiveCells&lt;br /&gt;    board.Cells &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; tmp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これらの対応により、愚直な実装にしては結構速くなったんじゃないかな。
今のところ GUI は CUI より速いのだけど、瞬間最高風速 1800 FPS 台だったので、理論上 0.5ms くらいで 1 frame 描画してる。速いなー。
でも game of life ガチ勢は専用の algorithm を採用し、極めて大きな盤面でももの凄い高速の simulation ができるらしい。
盤面が大きいとこちらは数十 FPS なのでまだまだやな。
まだ並列化を施してないから改善の余地は残されてる。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;他に対応したいものは、これも前回触れた Linux でのみ shortcut key で終了すると window が残る bug だ。
Windows では発生しなくて、 Ubuntu on WSL2 でのみこの現象を確認している。 純 Linux は持ってないのでわからん。
まだ原因がわかっておらず対処できてない。&lt;/p&gt;
&lt;p&gt;調査の過程で 1 つわかったのは、 Avalonia の &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/P_Avalonia_Threading_Dispatcher_UIThread&quot; title=&quot;&lt;code&gt;UIThread&lt;/code&gt;&quot;&gt;&lt;code&gt;UIThread&lt;/code&gt;&lt;/a&gt; に &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/M_Avalonia_Threading_Dispatcher_InvokeAsync_2&quot; title=&quot;&lt;code&gt;InvokeAsync&lt;/code&gt;&quot;&gt;&lt;code&gt;InvokeAsync&lt;/code&gt;&lt;/a&gt; したところで何か処理が詰まっていそうということだ。
一応 &lt;code&gt;InvokeAsync&lt;/code&gt; に cancellation token を渡せる overload があったし、ワンチャン願ってお作法的に渡すようには変えた。
でも結果は変わらず。
また &lt;code&gt;InvokeAsync&lt;/code&gt; で得られた Avalonia の &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/T_Avalonia_Threading_DispatcherOperation&quot; title=&quot;&lt;code&gt;DispatcherOperation&lt;/code&gt;&quot;&gt;&lt;code&gt;DispatcherOperation&lt;/code&gt;&lt;/a&gt; を &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/M_Avalonia_Threading_DispatcherOperation_Abort&quot; title=&quot;&lt;code&gt;Abort&lt;/code&gt;&quot;&gt;&lt;code&gt;Abort&lt;/code&gt;&lt;/a&gt; を実行してもこの詰まりは解消されなかった。
log を仕込んで動きを追ってみても、 cancellation token による中断で例外が発生するでもなく、単に詰まっているようにみえる。
この見解があってるのかもよくわからん。&lt;/p&gt;
&lt;p&gt;原因がさっぱりなので、この現象の再現のために個別の project を作って細かく見るしかないなという感じ。
イつ解決できるかもわからないし、 PSGameOfLife の暫定対応として Linux では shortcut key による終了を無効化した。
Avalonia 単体で使えば問題ないのか、 PowerShell module として Application を破棄せず持ってることに問題があるのか、色々調べないとわからん。
因みに &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/T_Avalonia_Controls_ApplicationLifetimes_ClassicDesktopStyleApplicationLifetime&quot; title=&quot;&lt;code&gt;ClassicDesktopStyleApplicationLifetime&lt;/code&gt;&quot;&gt;&lt;code&gt;ClassicDesktopStyleApplicationLifetime&lt;/code&gt;&lt;/a&gt; を &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/M_Avalonia_Controls_ApplicationLifetimes_ClassicDesktopStyleApplicationLifetime_Shutdown&quot; title=&quot;&lt;code&gt;Shutdown&lt;/code&gt;&quot;&gt;&lt;code&gt;Shutdown&lt;/code&gt;&lt;/a&gt; しても消えない。どうやったら消えるんだよ。
現状把握している唯一 window を消すのが可能な方法は、 process 自体を止めること。&lt;/p&gt;
&lt;p&gt;取り敢えず現状臭い物に蓋をしたので、世代交代の並列化をして高速化し、 PowerShell Gallery に公開したあと、腰を据えて取り組んでみるかー。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 20 Jul 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-07-13-writing-mini-game-in-fsharp-pt7.html</guid><link>https://krymtkts.github.io/posts/2025-07-13-writing-mini-game-in-fsharp-pt7.html</link><title>F# でミニゲームを書いてる Part 7</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife&quot; title=&quot;krymtkts/PSGameOfLife&quot;&gt;krymtkts/PSGameOfLife&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/7&quot; title=&quot;#7&quot;&gt;#7&lt;/a&gt; で cell のサイズ指定に対応した。
&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/10&quot; title=&quot;#10&quot;&gt;#10&lt;/a&gt; で CUI にも FPS の debug 機能を追加した。
CUI の FPS が見られるようになったことで、 GUI で同等の FPS が出せてるのもわかっていい感じ。
あと &lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/9&quot; title=&quot;#9&quot;&gt;#9&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/11&quot; title=&quot;#11&quot;&gt;#11&lt;/a&gt; でちょっとした描画処理の改善した。&lt;/p&gt;
&lt;p&gt;前回、 cell のサイズが小さいと &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/simd&quot; title=&quot;SIMD 命令&quot;&gt;SIMD 命令&lt;/a&gt;の恩恵を受けられなくなる話を書いた。
&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/blob/2616f36ffe851ff0b302fd4956fda600a099037f/src/PSGameOfLife/View.Avalonia.fs#L100-L149&quot; title=&quot;現状の実装&quot;&gt;現状の実装&lt;/a&gt;は以下の通り。
&lt;code&gt;Vector&amp;lt;byte&amp;gt;.Count&lt;/code&gt; に満たないデータはエラーになって使えないから、使わないようにしている。
(cell の byte 数が小さいと &lt;code&gt;createCellTemplate&lt;/code&gt; で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector?view=net-9.0&quot; title=&quot;&lt;code&gt;Vector&lt;/code&gt;&quot;&gt;&lt;code&gt;Vector&lt;/code&gt;&lt;/a&gt; が作られないから書き込み時も &lt;code&gt;Vector&lt;/code&gt; を使わない)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; createCellTemplate (cellSize&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;) (color&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;byte&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; Vector&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; b, g, r, a &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; color&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; byteLength &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; cellSize &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; bytes &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Array.zeroCreate&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;byte&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; byteLength&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;..&lt;/span&gt; cellSize &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; idx &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;            bytes.[idx] &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; b&lt;br /&gt;            bytes.[idx &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; g&lt;br /&gt;            bytes.[idx &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;] &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; r&lt;br /&gt;            bytes.[idx &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;] &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; a&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; nvec &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; byteLength &lt;span class=&quot;hljs-operator&quot;&gt;/&lt;/span&gt; vectorSize&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; vectors &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Array.init nvec (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; i &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; Vector&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;byte&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;(bytes, i &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; vectorSize))&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; offset &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nvec &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; vectorSize&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; rem &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; byteLength &lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; offset &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; bytes.[offset&lt;span class=&quot;hljs-operator&quot;&gt;..&lt;/span&gt;] &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; [&lt;span class=&quot;hljs-operator&quot;&gt;||&lt;/span&gt;]&lt;br /&gt;        rem, vectors&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; writeTemplateSIMD (dst&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;nativeptr&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;) (vectors&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Vector&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;array&lt;/span&gt;) (rem&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;array&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; baseAddr &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; NativePtr.toNativeInt dst&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;to&lt;/span&gt; vectors.Length &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;            Unsafe.WriteUnaligned((baseAddr &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; nativeint (i &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; vectorSize)).ToPointer(), vectors.[i])&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; offset &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; vectors.Length &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; vectorSize&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; rem.Length &lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; dstRemPtr &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; NativePtr.add dst offset&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; pinning the template array to avoid GC moving it.&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;use&lt;/span&gt; ptr &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fixed&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;&amp;amp;&lt;/span&gt;rem.[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]&lt;br /&gt;&lt;br /&gt;            Unsafe.CopyBlockUnaligned(NativePtr.toVoidPtr dstRemPtr, NativePtr.toVoidPtr ptr, uint32 rem.Length)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このため、 1x1 みたいな極端に dot の数が小さい cell の場合に SIMD を使わないので書き込みメモリ効率が落ちる。
これを改善したかったので、試しに毎 frame &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-45#span-and-byref-like-structs&quot; title=&quot;stackalloc&quot;&gt;stackalloc&lt;/a&gt; で確保した buffer へデータを溜め込んで行データをまとめて SMID で書き込む方法を試してみたのだけど、大差なかった。
現状の定義済み &lt;code&gt;Vector&lt;/code&gt; と余りの byte を書き込む方法だと、毎 frame で BGRA のための loop や &lt;code&gt;Vector&lt;/code&gt; の生成が不要なので同等に速いみたい。
なんか直感的にはまだまだできそうな感じはするけどな～、今はまだ技量が足りない。
他に思いつく高速化は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/byrefs&quot; title=&quot;byref&quot;&gt;byref&lt;/a&gt; で破壊的操作をして copy を減らすとかかな。効果あるかな...&lt;/p&gt;
&lt;p&gt;あと、現状 GUI で可能な最大サイズ 1000x1000 にすると、 2 FPS とかで極めて重い。
cell の数を減らして、代わりに size を増やして window が大きくしても描画が劣化しないので、多分 cell が多いことに起因してる。
ゲームの core な部分はまだ改善できそう。
array を使うようにはしてるけど、 array の再生成を最小限にするとかの最適化はそれほどやってないし。
ただそこに手をいれるには現状の simple な盤面の管理を二重にしてやる必要があって、気が進まない。
game of life は cell の生死を判断するのに周りの cell の状態に依存するから、逐次書き換えができないのよね。
都度盤面を copy するとそれだけ時間がかかるし、だとしたら二重 buffer しかないと。
速さのためには多少の不満も受け入れないといけないか。
当面大きい盤面での処理効率が向上しない間は全画面機能を追加せずいこう。&lt;/p&gt;
&lt;p&gt;他にも Linux でのみ shortcut key で終了すると window が残る bug もあったりして、 cross platform は改めて難しいな～というのを感じている。
現状はいちいち動作確認してるから、 GUI の end-to-end testing が要るのかなと思ってる。
一応それに使えそうな &lt;a href=&quot;https://docs.avaloniaui.net/docs/concepts/headless/&quot; title=&quot;Avalonia の Headless platform&quot;&gt;Avalonia の Headless platform&lt;/a&gt; というのがあるらしい。
実際に使えるのかは試してみないとちょっとわからんな。&lt;/p&gt;
&lt;p&gt;何にせよもうそろそろ PowerShell Gallery へ公開してもいいなという気持ちになってきてる。
GUI 版のための document 拡充とかも始める頃合いか。
自分の仕事 PC で game of life を流しながら休憩する未来はすぐそこにある。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 13 Jul 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-07-06-writing-mini-game-in-fsharp-pt6.html</guid><link>https://krymtkts.github.io/posts/2025-07-06-writing-mini-game-in-fsharp-pt6.html</link><title>F# でミニゲームを書いてる Part 6</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife&quot; title=&quot;krymtkts/PSGameOfLife&quot;&gt;krymtkts/PSGameOfLife&lt;/a&gt; の開発をした。なかなか大変だったが、終了処理の課題を解決できた。
&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/6&quot; title=&quot;#6&quot;&gt;#6&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;元々課題に思ってた終了処理が詰まるのも解決の手立てがなかった。
UI Thread が詰まってるから Window を閉じる操作をしても event に関連づいた処理が起動するのにどうしても時間がかかってしまうという感じか。
Avalonia 内部まで追ったわけではないがそういう挙動に見えた。&lt;/p&gt;
&lt;p&gt;あとどうも &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/T_Avalonia_Media_Imaging_WriteableBitmap&quot; title=&quot;&lt;code&gt;WriteableBitmap&lt;/code&gt;&quot;&gt;&lt;code&gt;WriteableBitmap&lt;/code&gt;&lt;/a&gt; の生成コストが結構高いようだというのがわかってきた。
&lt;code&gt;WriteableBitmap&lt;/code&gt; を使い回す実装に変えたら 1 frame 当たりの処理時間が 1ms くらいは縮む。
でも  &lt;a href=&quot;https://github.com/fsprojects/Avalonia.FuncUI&quot; title=&quot;Avalonia.FuncUI&quot;&gt;Avalonia.FuncUI&lt;/a&gt; か &lt;a href=&quot;https://github.com/fsprojects/Avalonia.FuncUI/tree/master/src/Avalonia.FuncUI.Elmish&quot; title=&quot;Avalonia.FuncUI.Elmish&quot;&gt;Avalonia.FuncUI.Elmish&lt;/a&gt; の制約で、参照が同じままだと変更を検知できなくて再描画できないみたい。
あんま追えてないが &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.object.referenceequals?view=net-9.0&quot; title=&quot;&lt;code&gt;Object.ReferenceEquals&lt;/code&gt;&quot;&gt;&lt;code&gt;Object.ReferenceEquals&lt;/code&gt;&lt;/a&gt; を使ってそう。
Avalonia.FuncUI.Elmish での実現は断念した。&lt;/p&gt;
&lt;p&gt;この通り Avalonia.FuncUI と Avalonia.FuncUI.Elmish の制約が乗り越えられない壁になってたので、いっそのこと利用をやめてみた。
代わりに描画処理を自前の event loop で実行する必要がある。末尾再帰で loop するようにした。
event loop 内で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=net-9.0&quot; title=&quot;&lt;code&gt;CancellationTokenSource&lt;/code&gt;&quot;&gt;&lt;code&gt;CancellationTokenSource&lt;/code&gt;&lt;/a&gt; に基づいて終了できるようにしたら、瞬時に終了処理が実行できるよう改善できた。
きびきび反応していい感じ。
Avalonia.FuncUI の宣言的な DSL とか &lt;a href=&quot;https://elmish.github.io/elmish/#dispatch-loop&quot; title=&quot;MVU&quot;&gt;MVU&lt;/a&gt; の恩恵が受けられなくなったが、最低限の UX を提供するためには仕方ないのだ。
Avalonia.FuncUI と Avalonia.FuncUI.Elmish もパフォや機能的な制約がないのであれば問題ないし、共存の未知を探せるとよいが。&lt;/p&gt;
&lt;p&gt;今回の変更による &lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/blob/4a6da2bc415541cf9a45f47014b710ac587adf2c/src/PSGameOfLife/View.Avalonia.fs#L213-L273&quot; title=&quot;UI 更新と event loop のコード&quot;&gt;UI 更新と event loop のコード&lt;/a&gt;は以下の通り。
宣言的 UI じゃなくなったので見通しは悪くなった。
event loop は一般的な再帰になってわかりやすいといえるが処理が増えたら煩雑化しそうではある。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; stack, updateUI &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; status1 &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            TextBlock(Background &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Brushes.White, Foreground &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Brushes.Black, Height &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Main.statusRowHeight)&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; status2 &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            TextBlock(Background &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Brushes.White, Foreground &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Brushes.Black, Height &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Main.statusRowHeight)&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; image &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Image(Width &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; float width, Height &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; float height)&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; wb &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; WriteableBitmap(PixelSize(width, height), Vector(&lt;span class=&quot;hljs-number&quot;&gt;96&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;96&lt;/span&gt;), PixelFormat.Bgra8888, AlphaFormat.Opaque)&lt;br /&gt;&lt;br /&gt;        image.Source &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; wb&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#if&lt;/span&gt; DEBUG &lt;span class=&quot;hljs-operator&quot;&gt;||&lt;/span&gt; SHOW_FPS&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; fpsText &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; tb &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                TextBlock(Foreground &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Brushes.Yellow, Background &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; SolidColorBrush(Color.Parse(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#80000000&amp;quot;&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;            Canvas.SetTop(tb, &lt;span class=&quot;hljs-number&quot;&gt;0.0&lt;/span&gt;)&lt;br /&gt;            Canvas.SetRight(tb, &lt;span class=&quot;hljs-number&quot;&gt;0.0&lt;/span&gt;)&lt;br /&gt;            tb.SetValue(Canvas.ZIndexProperty, &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt;&lt;br /&gt;            tb&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#else&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; fpsText &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#endif&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; canvas &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Canvas(Width &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; float width, Height &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; float height)&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; stack &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; StackPanel()&lt;br /&gt;&lt;br /&gt;        status1 &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; stack.Children.Add&lt;br /&gt;        status2 &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; stack.Children.Add&lt;br /&gt;        image &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; canvas.Children.Add&lt;br /&gt;        canvas &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; stack.Children.Add&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#if&lt;/span&gt; DEBUG &lt;span class=&quot;hljs-operator&quot;&gt;||&lt;/span&gt; SHOW_FPS&lt;br /&gt;        fpsText &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; canvas.Children.Add&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#endif&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; updateUI board &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            status1.Text &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;#Press Q to quit. Board: &lt;span class=&quot;hljs-subst&quot;&gt;{board.Column}&lt;/span&gt; x &lt;span class=&quot;hljs-subst&quot;&gt;{board.Row}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            status2.Text &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;#Generation: &lt;span class=&quot;hljs-subst&quot;&gt;{board.Generation, &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;}&lt;/span&gt; Living: &lt;span class=&quot;hljs-subst&quot;&gt;{board.Lives, &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            renderBoard board wb&lt;br /&gt;            image.InvalidateVisual()&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#if&lt;/span&gt; DEBUG &lt;span class=&quot;hljs-operator&quot;&gt;||&lt;/span&gt; SHOW_FPS&lt;br /&gt;            fpsText.Text &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;FPS: %.2f&lt;span class=&quot;hljs-subst&quot;&gt;{FpsCounter.&lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt; ()}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#endif&lt;/span&gt;&lt;br /&gt;        stack, updateUI&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;TailCall&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;rec&lt;/span&gt; loop board &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;async&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; cts.IsCancellationRequested &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ()&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;do!&lt;/span&gt;&lt;br /&gt;                Dispatcher.UIThread.InvokeAsync(&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; () &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; updateUI board).GetTask()&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Async.AwaitTask&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;do!&lt;/span&gt; Async.Sleep(int board.Interval)&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; currentBoard &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nextGeneration board&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return!&lt;/span&gt; loop currentBoard&lt;br /&gt;        }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これによって終了処理は改善されたが、同時に不可解な hangup が発生するようになった。 CPU ・ GPU が無風になる。
それも毎回 hangup するのでなくて、特にゲームボードのサイズが大きくて cell の数が多いほど起動時に詰まる確率が高い。
でもデフォのサイズでも確率が多少低いだけで発生することに変わりない。&lt;/p&gt;
&lt;p&gt;原因不明で困ったが、なんとか原因らしき挙動は突き止めた。
どうも &lt;code&gt;WriteableBitmap&lt;/code&gt; が thread safe じゃないことによるみたい。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.parallel.foreach?view=net-9.0&quot; title=&quot;&lt;code&gt;Parallel.ForEach&lt;/code&gt;&quot;&gt;&lt;code&gt;Parallel.ForEach&lt;/code&gt;&lt;/a&gt; を使って並列で重ならない address に書き込んでいても、内部で deadlock するっぽい。
早い話が &lt;code&gt;WriteableBitmap&lt;/code&gt; への並列書き込みが原因ということになる。
つまり一時領域に並列で書きこんで、その結果を &lt;code&gt;WriteableBitmap&lt;/code&gt; に一括コピーすれば回避可能なのがわかった。コピー効率は悪くなるが。
&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/blob/4a6da2bc415541cf9a45f47014b710ac587adf2c/src/PSGameOfLife/View.Avalonia.fs#L167-L211&quot; title=&quot;コード&quot;&gt;コード&lt;/a&gt;は以下のようになった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; renderBoard (board&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Board) (wb&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; WriteableBitmap) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; partitioner &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Partitioner.Create(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, Array2D.length1 board.Cells)&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;use&lt;/span&gt; tempPtr &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fixed&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;&amp;amp;&lt;/span&gt;tempBuffer.[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; lenX &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Array2D.length2 board.Cells &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;            Parallel.ForEach(&lt;br /&gt;                partitioner,&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; (startIdx, endIdx) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; y &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; startIdx &lt;span class=&quot;hljs-keyword&quot;&gt;to&lt;/span&gt; endIdx &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; yc &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; y &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; cellSize&lt;br /&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;to&lt;/span&gt; lenX &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;                            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; xc &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; cellSize&lt;br /&gt;&lt;br /&gt;                            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; vectors, bytes &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                                &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; board.Cells.[y, x] &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Live &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; templates.LiveVectors, templates.LiveBytes&lt;br /&gt;                                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Dead &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; templates.DeadVectors, templates.DeadBytes&lt;br /&gt;&lt;br /&gt;                            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; dy &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;to&lt;/span&gt; cellSize &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;                                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; dstOffset &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ((yc &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; dy) &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; width &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; xc) &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; dstLinePtr &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                                    NativePtr.add&lt;br /&gt;                                        (NativePtr.ofNativeInt&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;byte&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; (NativePtr.toNativeInt tempPtr))&lt;br /&gt;                                        dstOffset&lt;br /&gt;&lt;br /&gt;                                Main.writeTemplateSIMD dstLinePtr vectors bytes&lt;br /&gt;            )&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Parallel write to WriteableBitmap cause a deadlock. so avoid it by using a temporary buffer.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;use&lt;/span&gt; fb &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; wb.Lock()&lt;br /&gt;        System.Runtime.InteropServices.Marshal.Copy(tempBuffer, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, fb.Address, bufferSize)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで Razer Blade Stealth 2017 でも 50x50 で 700 FPS くらい、 100x80 だと 140 ~ 160 FPS くらい。
100x80 があまり高速化してないのだけど、 全画面に近い 160x80 でも 120 FPS は出るようになって割と良いのではないかと。&lt;/p&gt;
&lt;p&gt;ひとまず終了処理の課題と高速化も実現できて満足。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと気になるのは、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/simd&quot; title=&quot;SIMD 命令&quot;&gt;SIMD 命令&lt;/a&gt;の効率。
現状 SIMD 命令は 1 cell 毎に SIMD 命令でのコピーと端数のコピーが実行されてるのだけど、理論的には SIMD 命令の効率をもっと上げられるはず。
でも実際に試してみたら、 SIMD 命令のために &lt;code&gt;Vector&amp;lt;byte&amp;gt;[]&lt;/code&gt; を積み上げる箇所にどうにもコストがかかるみたいで大して速くならなかった。
なので現状だと先述の通り理論上の SIMD 命令の効率は悪いが、現状の定義済みメモリをこまめに SIMD と端数に分けてコピる方式が最も速くなってる。&lt;/p&gt;
&lt;p&gt;でもこれは動作確認する際の cell 数だとそうなるというだけだと思われる。
cell が 10x10 の固定サイズじゃなくて指定できるようになってたらもっと SIMD 命令の効率を上げないと FPS 上がらないんじゃないかなと。
またちまちま試行錯誤して改善を繰り返したい。&lt;/p&gt;
&lt;p&gt;描画効率が更に良くなったら全画面表示なんかも導入していい気がする。
GUI はやることが多くて勉強になるが、お陰で一向にゲームモードの追加とかに進まんのが難点やな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 06 Jul 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-06-29-writing-mini-game-in-fsharp-pt5.html</guid><link>https://krymtkts.github.io/posts/2025-06-29-writing-mini-game-in-fsharp-pt5.html</link><title>F# でミニゲームを書いてる Part 5</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife&quot; title=&quot;krymtkts/PSGameOfLife&quot;&gt;krymtkts/PSGameOfLife&lt;/a&gt; の開発をした。あんまりやれてないが。&lt;/p&gt;
&lt;p&gt;終了のためのショートカットを追加したり、世代とかのステータスを表示できるようにしてみたらぐっと使いやすくなった。
&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/4&quot; title=&quot;#4&quot;&gt;#4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;そこで改めて気付いたが &lt;code&gt;Interval&lt;/code&gt; 0ms にしていると描画は極めて高速でも終了まで時間がかかるようになった。処理が多すぎて UI(main) thread が詰まるみたい。
0ms の利用を推したいわけじゃないが、あまり気持ち良くないのでもう少し最適化できないか調べてみている。&lt;/p&gt;
&lt;p&gt;とりあえず、 cell の数が多いほど計算量が増える状態なのは GitHub Copilot の指摘でもあったので、 1 frame 毎の演算量を減らしてみるとかその他の最適化を試みた。
GitHub Copilot の提案も含め以下を施した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cell の生死を template 化して copy する&lt;/li&gt;&lt;li&gt;描画処理の並列化(描画反映が重ならないので可能)&lt;/li&gt;&lt;li&gt;描画処理の SIMD 命令利用&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;これらを &lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/5&quot; title=&quot;#5&quot;&gt;#5&lt;/a&gt; で実装してみた。
GitHub Copilot は並列化をやたら推すが、他のアイデアについては提案してくれなかったのでこちらからあれこれどうかと聞いてみた感じ。
なんとなーく、段階的に高速化するような感じで 1 つずつ提案してくれるつもりだったのかも知れないが、そんな悠長なことはしてられないので。&lt;/p&gt;
&lt;p&gt;F# で low layer は書いたことなかったので GitHub Copilot のレクチュアのもと行った。
1ms 以下の演算となると CPU キャッシュがとかメモリの転送量がとか、GC で address が変わるからコピーする間はピン留めする必要があるとか色々興味深く、中々いい経験になる。
これらの要素を何となく理解できることから、改めて &lt;a href=&quot;/booklogs/what-a-programmer-should-know-about-the-cpu.html&quot; title=&quot;プログラマーのための CPU 入門&quot;&gt;プログラマーのための CPU 入門&lt;/a&gt; を読んでて良かったなと身にしみて感じた。
ちょっと残念だったのが、これは &lt;a href=&quot;https://avaloniaui.net/&quot; title=&quot;Avalonia&quot;&gt;Avalonia&lt;/a&gt; の話だが &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/T_Avalonia_Media_Imaging_WriteableBitmap&quot; title=&quot;&lt;code&gt;WriteableBitmap&lt;/code&gt;&quot;&gt;&lt;code&gt;WriteableBitmap&lt;/code&gt;&lt;/a&gt; の描画が 1 行単位にしか行えないらしいこと。
お陰で 1 cell 10x10 を 10 回に書き分ける必要があった。
まだ &lt;code&gt;WriteableBitmap&lt;/code&gt; のことはいまいちわかってないからこれが本当に最善手かわからないし、もっと効率的にできる方法があるかもな。&lt;/p&gt;
&lt;p&gt;これらの対応によって、 Razer Blade Stealth 2017 でも随分速くなった。
ゲームのセルの数が デフォ 50x50 だと 120 FPS だったのが 400 FPS ~ に、 100x80 だと ~ 60 FPS が 120 FPS ~ に高速化されてる。&lt;/p&gt;
&lt;p&gt;最適化に際して、描画処理の速度を測るため FPS を計測・表示する仕組みを作った。
昔 Avalonia の &lt;code&gt;Windows&lt;/code&gt; には &lt;code&gt;VisualRoot.VisualRoot.Renderer.DrawFps&lt;/code&gt; が生えてたらしい。
これは &lt;a href=&quot;https://github.com/fsprojects/Avalonia.FuncUI/blob/f86eea3f4b14c72ebb2d27f0143c4a21c896baf1/src/Examples/Elmish%20Examples/Examples.Elmish.GameOfLife/Program.fs#L34&quot; title=&quot;Avalonia.FuncUI&quot;&gt;Avalonia.FuncUI&lt;/a&gt; の sample でもコメントの状態で見られる。
でも今の Avalonia 11 にはそれがなくなってるのか見つけられなかったので、自前で簡単なのを作った。
FPS の計算と表示による負荷が気になったのだけど、 GitHub Copilot 曰く微々たるものとのことなので許容した。&lt;/p&gt;
&lt;p&gt;あと初めて SIMD 命令を使ったので初めて知ったのだけど、 .NET は Release build じゃないと JIT で SIMD の最適化しないみたい。
これについて触れられた文書はまだ探せてない。
Debug build だと SIMD の最適化がないのか、デフォのセル数で 250 FPS くらいになってた。かなり違う。
実際に利用する場合の性能を測りたい。
ということで、最初は &lt;code&gt;#if DEBUG&lt;/code&gt; だけ FPS を表示してたのだけど、独自の symbol を指定した場合も表示できるようにした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dotnet build -p:DefineConstants=SHOW_FPS
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こういう command で独自の symbol を指定できる。
ただ PSGameOfLife では &lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;psake&quot;&gt;psake&lt;/a&gt; に build task を一任してる。
そのため &lt;code&gt;dotnet&lt;/code&gt; 直じゃなく parameter を追加した場合のみ &lt;code&gt;DefineConstants&lt;/code&gt; を追加できるようにしている。&lt;/p&gt;
&lt;p&gt;現時点でも結構いい感じではなかろうか。
でも元々課題に思ってた終了処理が詰まるのは多少軽くなったけどまだ詰まったまま。
それと &lt;a href=&quot;https://github.com/ionide/ionide-analyzers&quot; title=&quot;Ionide.Analyzers&quot;&gt;Ionide.Analyzers&lt;/a&gt; の警告に対応してなかったりするので、その辺直せたら PR を merge しようかな。
週末時間取れない日が続くが少しずつ進められてるところも、中々良い。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 29 Jun 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-06-23-writing-mini-game-in-fsharp-pt4.html</guid><link>https://krymtkts.github.io/posts/2025-06-23-writing-mini-game-in-fsharp-pt4.html</link><title>F# でミニゲームを書いてる Part 4</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;最近週末お出かけばかりで時間が取れないので、今日代わりに休みを取って開発、日記とした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife&quot; title=&quot;krymtkts/PSGameOfLife&quot;&gt;krymtkts/PSGameOfLife&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;まず PSGameOfLife に GUI の prototype を実装した。 &lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/1&quot; title=&quot;#1&quot;&gt;#1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.nativelibrary.setdllimportresolver?view=net-9.0&quot; title=&quot;&lt;code&gt;NativeLibrary.SetDllImportResolver&lt;/code&gt;&quot;&gt;&lt;code&gt;NativeLibrary.SetDllImportResolver&lt;/code&gt;&lt;/a&gt; で native library 読み込みを調整するやつの目処がついたためだ。
&lt;code&gt;NativeLibrary.SetDllImportResolver&lt;/code&gt; は native library の既定の読み込みを上書きする。
なので既定の読み込みも活かすよう自分で実装する必要がある。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.intptr.zero?view=net-9.0&quot; title=&quot;&lt;code&gt;IntPtr.Zero&lt;/code&gt;&quot;&gt;&lt;code&gt;IntPtr.Zero&lt;/code&gt;&lt;/a&gt; を返すと library が見つからなかったことになるので、既定の読み込みに fallback する必要がある。
結果&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/blob/026246251b79e9f21cc16f54f859b412cfa4ac6c/src/PSGameOfLife/View.Avalonia.fs#L36-L73&quot; title=&quot;このような形&quot;&gt;このような形&lt;/a&gt;に落ち着いた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; resolver (ptrCache&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Concurrent.ConcurrentDictionary&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;nativeint&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;) moduleDir extension &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; tryLoadLibrary (moduleDir&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) (extension&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) (libraryName&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; libPath &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; libPath &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; extension &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; libraryName.EndsWith &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;runtimes/&lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.RuntimeIdentifier}&lt;/span&gt;/native/&lt;span class=&quot;hljs-subst&quot;&gt;{libraryName}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;runtimes/&lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.RuntimeIdentifier}&lt;/span&gt;/native/&lt;span class=&quot;hljs-subst&quot;&gt;{libraryName}&lt;/span&gt;.&lt;span class=&quot;hljs-subst&quot;&gt;{extension}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                System.IO.Path.Combine(moduleDir, libPath)&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; libPath &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; IO.File.Exists &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                libPath&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; NativeLibrary.TryLoad&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;, ptr &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; ptr&lt;br /&gt;                    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; IntPtr.Zero&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;                IntPtr.Zero&lt;br /&gt;&lt;br /&gt;        DllImportResolver(&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; libraryName assembly searchPath &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; libraryName &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; ptrCache.TryGetValue &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;, ptr &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; ptr&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; tryLoadLibrary moduleDir extension libraryName &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; ptr &lt;span class=&quot;hljs-keyword&quot;&gt;when&lt;/span&gt; ptr &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; IntPtr.Zero &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; fallback to the default behavior if the library is not found.&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; NativeLibrary.TryLoad(libraryName, assembly, searchPath) &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;, ptr &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                        ptrCache.TryAdd(libraryName, ptr) &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt;&lt;br /&gt;                        ptr&lt;br /&gt;                    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Returning IntPtr.Zero means the library was not found. This will cause an error when P/Invoke is called.&lt;/span&gt;&lt;br /&gt;                        IntPtr.Zero&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; ptr &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                    ptrCache.TryAdd(libraryName, ptr) &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt;&lt;br /&gt;                    ptr)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで Windows / Linux(Ubuntu on WSL) のいずれでもご機嫌な GUI が動く。&lt;/p&gt;
&lt;p&gt;ただ &lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/1&quot; title=&quot;#1&quot;&gt;#1&lt;/a&gt; の実装は描画処理に問題があったみたいで、極端に遅かった。
10ms 毎の interval で描画を繰り返すと、描画が stuck した。
なるべく CUI で出来てることを GUI でもやりたくて、 Cmdlet の parameter で指定できる &lt;code&gt;Interval&lt;/code&gt; の範囲はなんとか動作保証したかったので、改善に着手した。
&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/pull/2&quot; title=&quot;#2&quot;&gt;#2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(ほぼ AI にぶん投げて)調べたところ高速な描画を実装するのに対して、 2 つ良くない点があった。&lt;/p&gt;
&lt;p&gt;1 つ目は&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/blob/e3db7c59f7fc6154a578b9393dd8a2fc136fbace/src/PSGameOfLife/View.Avalonia.fs#L109-L152&quot; title=&quot;ここ&quot;&gt;ここ&lt;/a&gt;で、 &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/T_Avalonia_Controls_Canvas&quot; title=&quot;&lt;code&gt;Canvas&lt;/code&gt;&quot;&gt;&lt;code&gt;Canvas&lt;/code&gt;&lt;/a&gt; に &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/T_Avalonia_Controls_Shapes_Rectangle&quot; title=&quot;&lt;code&gt;Rectangle&lt;/code&gt;&quot;&gt;&lt;code&gt;Rectangle&lt;/code&gt;&lt;/a&gt; で描画しているので描画が重かった。
cell の数が多くなるととてつもなく重くなるみたいなので game of life には向かないと。そりゃそうか。&lt;/p&gt;
&lt;p&gt;これは単純に高速な画像の描画処理が必要なら &lt;a href=&quot;https://api-docs.avaloniaui.net/docs/T_Avalonia_Media_Imaging_WriteableBitmap&quot; title=&quot;&lt;code&gt;WriteableBitmap&lt;/code&gt;&quot;&gt;&lt;code&gt;WriteableBitmap&lt;/code&gt;&lt;/a&gt; を使えばいいみたい。
手続き的な書き方で埋め尽くされたが、これでかなり速くなって、 interval 1ms くらいならさばけるようになった。&lt;/p&gt;
&lt;p&gt;それでも interval 0ms 、要は待ち時間なしにすると stuck していた。
これが 2 つ目の良くない点で、 &lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife/blob/e3db7c59f7fc6154a578b9393dd8a2fc136fbace/src/PSGameOfLife/View.Avalonia.fs#L154-L162&quot; title=&quot;ここ&quot;&gt;ここ&lt;/a&gt;。
描画処理の完了を待たずに &lt;a href=&quot;https://reference.avaloniaui.net/api/Avalonia.Threading/DispatcherTimer/&quot; title=&quot;&lt;code&gt;DispatcherTimer&lt;/code&gt;&quot;&gt;&lt;code&gt;DispatcherTimer&lt;/code&gt;&lt;/a&gt; が次々と message を送ってくるから処理が追いつかなくなって、 queue が詰まったという感じみたい。&lt;/p&gt;
&lt;p&gt;なので &lt;code&gt;DispatcherTimer&lt;/code&gt; を使うのをやめて、描画が終わったら次の処理のための message を配信するという感じに書き換えた。再帰的になってる感じ。
この書き換えには &lt;code&gt;Cmd.OfAsyncImmediate.either&lt;/code&gt; を使った。
単に Elmish を使いこなせてないだけかも知れないが、最初 &lt;code&gt;Cmd.OfAsyncImmediate.perform&lt;/code&gt; してたら GUI を閉じたときに再帰的な処理が停止できてなかったみたい。
そのせいで 2 回目以降の起動で描画処理にカクつきが見られた。
この解消のために &lt;code&gt;Cmd.OfAsyncImmediate.either&lt;/code&gt; で cancellation token が cancel されたときは何もしないようにしてで呼び出しを止めさせた。
これで待ち時間 0ms(実際は計算時間があるためベストエフォート)の描画ができるようになった。&lt;/p&gt;
&lt;p&gt;よく F# の game programming は最適化のため手続きっぽい書き方が増えるというのをいろんな人の blog で見ていたが、2 つの対応を通して、身にしみてわかった気がする。&lt;/p&gt;
&lt;p&gt;まだ Avalonia や Elmish に慣れてないのもあるが、 Avalonia の v11 を使ってるから AI の suggest も v10 以前の知識で動いたりするのが面倒だった。
過去の Avalonia を知らんので結構混乱する。
また Avalonia.FuncUI.Elmish に関しては情報がそもそも少ない(多分ないよな？)から、 AI が出たらめいってくる。
結局自分で関数の signature や直に実装を見て判断するしかない。
慣れかな。&lt;/p&gt;
&lt;p&gt;これで Windows / Linux でも高速な描画ができるようになった GUI mode の土台が整った。
あとは画面のサイズの指定とか、 CUI モードとなるべくおなじ interface に汎化するとかを進めていければよさそう。
もうちょい週末が穏やかだと嬉しいのだが。続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Mon, 23 Jun 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-06-15-writing-mini-game-in-fsharp-pt3.html</guid><link>https://krymtkts.github.io/posts/2025-06-15-writing-mini-game-in-fsharp-pt3.html</link><title>F# でミニゲームを書いてる Part 3</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife&quot; title=&quot;krymtkts/PSGameOfLife&quot;&gt;krymtkts/PSGameOfLife&lt;/a&gt; の開発。
次は GUI でミニゲームを実行するようにしたいというやつだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/fsharp-cmdlet-sandbox&quot; title=&quot;krymtkts/fsharp-cmdlet-sandbox&quot;&gt;krymtkts/fsharp-cmdlet-sandbox&lt;/a&gt; で &lt;a href=&quot;https://github.com/fsprojects/Avalonia.FuncUI&quot; title=&quot;Avalonia.FuncUI&quot;&gt;Avalonia.FuncUI&lt;/a&gt; の練習をしてみた。
Avalonia.FuncUI 自体を利用するのは難なくできそうだが、 PowerShell Cmdlet 内から呼び出すのが極めて難しいなこれ。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dotnet run ~&lt;/code&gt; のように実行形式で起動すれば Windows でも Linux(Ubuntu on WSL で確認した)でも問題ない。
しかし PowerShell Cmdlet 内から起動すると DLL 等 native library が読み込まれない。&lt;/p&gt;
&lt;p&gt;Windows 側は以下の hack を使うことで、事前に load した assembly がキャッシュされてる状態で GUI を起動できた。
&lt;code&gt;runtimes/*/native/*&lt;/code&gt; を動的に load することで課題に対処した具合だ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/fsharp-cmdlet-sandbox/blob/dbc637c82935da48d14c0affc69d869a5e43751f/src/avalonia-funcui/Library.fs#L99-L149&quot; title=&quot;fsharp-cmdlet-sandbox/src/avalonia-funcui/Library.fs at dbc637c82935da48d14c0affc69d869a5e43751f · krymtkts/fsharp-cmdlet-sandbox&quot;&gt;fsharp-cmdlet-sandbox/src/avalonia-funcui/Library.fs at dbc637c82935da48d14c0affc69d869a5e43751f · krymtkts/fsharp-cmdlet-sandbox&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;検証コードなので汚いが、まんまコピる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;OSArchitecture: &lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.OSArchitecture}&lt;/span&gt; OSDescription: &lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.OSDescription}&lt;/span&gt; FrameworkDescription: &lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.FrameworkDescription}&lt;/span&gt; ProcessArchitecture: &lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.ProcessArchitecture}&lt;/span&gt; RuntimeIdentifier: &lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.RuntimeIdentifier}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;EndProcessing called&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; moduleDir &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Module directory: %s&amp;quot;&lt;/span&gt; moduleDir&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;            [ &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;runtimes/&lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.RuntimeIdentifier}&lt;/span&gt;/native/av_libglesv2.dll&amp;quot;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;runtimes/&lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.RuntimeIdentifier}&lt;/span&gt;/native/libHarfBuzzSharp.dll&amp;quot;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;runtimes/&lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.RuntimeIdentifier}&lt;/span&gt;/native/libSkiaSharp.dll&amp;quot;&lt;/span&gt; ]&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; RuntimeInformation.IsOSPlatform(OSPlatform.OSX) &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;            [ &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;runtimes/&lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.RuntimeIdentifier}&lt;/span&gt;/native/libAvaloniaNative.dylib&amp;quot;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;runtimes/&lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.RuntimeIdentifier}&lt;/span&gt;/native/libHarfBuzzSharp.dylib&amp;quot;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;runtimes/&lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.RuntimeIdentifier}&lt;/span&gt;/native/libSkiaSharp.dylib&amp;quot;&lt;/span&gt; ]&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; RuntimeInformation.IsOSPlatform(OSPlatform.Linux) &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;            [ &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;runtimes/&lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.RuntimeIdentifier}&lt;/span&gt;/native/libHarfBuzzSharp.so&amp;quot;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;runtimes/&lt;span class=&quot;hljs-subst&quot;&gt;{RuntimeInformation.RuntimeIdentifier}&lt;/span&gt;/native/libSkiaSharp.so&amp;quot;&lt;/span&gt; ]&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;            List.empty&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.iter (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; skiaDll &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; skiaPath &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; System.IO.Path.Combine(moduleDir, skiaDll)&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Loading SkiaSharp library from: %s&amp;quot;&lt;/span&gt; skiaPath&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; System.IO.File.Exists(skiaPath) &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;SkiaSharp library found.&amp;quot;&lt;/span&gt;&lt;br /&gt;                    NativeLibrary.Load(skiaPath) &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; e &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Failed to load SkiaSharp library: %s&amp;quot;&lt;/span&gt; e.Message&lt;br /&gt;                ())&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; app &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; lt &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime()&lt;br /&gt;&lt;br /&gt;            AppBuilder&lt;br /&gt;                .Configure&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;App&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;()&lt;br /&gt;                .UsePlatformDetect()&lt;br /&gt;                .UseSkia()&lt;br /&gt;                .LogToTextWriter(Console.Out, LogEventLevel.Verbose)&lt;br /&gt;                .SetupWithLifetime(lt)&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// .SetupWithoutStarting()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Avalonia FuncUI application configured.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        app
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;でも Linux では効果なかったから同じ方法を使えなかった。 library 解決の手法が Windows と違うそうなので、これは別途対応する必要がある。
また Mac での挙動は端末がなくてチェックできない。
cross platform 対応のハードルは実に高いと実感している。&lt;/p&gt;
&lt;p&gt;まるで詳しくないが、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.nativelibrary.setdllimportresolver?view=net-9.0&quot; title=&quot;&lt;code&gt;NativeLibrary.SetDllImportResolver&lt;/code&gt;&quot;&gt;&lt;code&gt;NativeLibrary.SetDllImportResolver&lt;/code&gt;&lt;/a&gt; で native library の読み込み path を調整できるようなので、それを使うのが良さそう。
Linux での native library の読み込み問題さえ解決したら PSGameOfLife に組み込めるなーと思ってる。&lt;/p&gt;
&lt;p&gt;別の課題もある。
PowerShell Cmdlet 内から Avalonia の普通の使い方をすると初回起動しか成功しない。
2 回目以降は &lt;code&gt;Setup was already called on one of AppBuilder instances&lt;/code&gt; になる。
どうも同一 process 内で Avalonia の &lt;a href=&quot;https://reference.avaloniaui.net/api/Avalonia/AppBuilder/&quot; title=&quot;&lt;code&gt;AppBuilder&lt;/code&gt;&quot;&gt;&lt;code&gt;AppBuilder&lt;/code&gt;&lt;/a&gt; の setup は一度限りというのが仕様みたい。
先述の &lt;a href=&quot;https://reference.avaloniaui.net/api/Avalonia.Controls/AppBuilderBase_1/F3B58741&quot; title=&quot;&lt;code&gt;SetupWithLifetime&lt;/code&gt;&quot;&gt;&lt;code&gt;SetupWithLifetime&lt;/code&gt;&lt;/a&gt; もその対象。
また &lt;a href=&quot;https://reference.avaloniaui.net/api/Avalonia.Controls/AppBuilderBase_1/07E2926E&quot; title=&quot;&lt;code&gt;Start&lt;/code&gt;&quot;&gt;&lt;code&gt;Start&lt;/code&gt;&lt;/a&gt; 等も内部的に setup を行うので、 2 回目以降同様のエラーが発生する。
Avalonia の event loop は &lt;a href=&quot;https://reference.avaloniaui.net/api/Avalonia.Threading/Dispatcher/&quot; title=&quot;&lt;code&gt;Avalonia.Threading.Dispatcher&lt;/code&gt;&quot;&gt;&lt;code&gt;Avalonia.Threading.Dispatcher&lt;/code&gt;&lt;/a&gt; が担っているようだが、こいつも process で一度限りしか利用できないみたい。
2 回目以降の実行では &lt;code&gt;Dispatcher&lt;/code&gt; が破棄されて使えなかった。
PowerShell Cmdlet はその session 内であればずっと同じ process なので、大変だこれ。&lt;/p&gt;
&lt;p&gt;たどり着いた回避方法が、 process 内での &lt;code&gt;AppBuilder&lt;/code&gt; の setup を 1 度限りにし、 &lt;a href=&quot;https://reference.avaloniaui.net/api/Avalonia.Controls/Window/&quot; title=&quot;&lt;code&gt;Window&lt;/code&gt;&quot;&gt;&lt;code&gt;Window&lt;/code&gt;&lt;/a&gt; を cmdlet 実行毎に生成することだ。
setup については先述の通りだが、 &lt;code&gt;Window&lt;/code&gt; も同様で一度 &lt;code&gt;Close&lt;/code&gt; すると再利用できなくなる。
だから &lt;code&gt;Window&lt;/code&gt; を毎回使い捨てる必要がある。
いずれも GUI は概ね単一の process で実行されるから、 process 内で使い回せるようにしてないのが仕様なのかな。
何にせよ、これで PowerShell の同一 session 内で何度も GUI を起動できるようになった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/fsharp-cmdlet-sandbox/blob/dbc637c82935da48d14c0affc69d869a5e43751f/src/avalonia-funcui/Library.fs#L53-L178&quot; title=&quot;fsharp-cmdlet-sandbox/src/avalonia-funcui/Library.fs at dbc637c82935da48d14c0affc69d869a5e43751f · krymtkts/fsharp-cmdlet-sandbox&quot;&gt;fsharp-cmdlet-sandbox/src/avalonia-funcui/Library.fs at dbc637c82935da48d14c0affc69d869a5e43751f · krymtkts/fsharp-cmdlet-sandbox&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;既に引用した一部を省略してまま検証コードをコピったのが以下。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;MainWindow&lt;/span&gt;() &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; this &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;inherit&lt;/span&gt; HostWindow()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;base&lt;/span&gt;.Title &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Example&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;base&lt;/span&gt;.Height &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;300.0&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;base&lt;/span&gt;.Width &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;300.0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        Elmish.Program.mkProgram Main.init Main.update Main.view&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Program.withHost this&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Program.run&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; this.OnClosed(e&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; System.EventArgs) &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;base&lt;/span&gt;.OnClosed(e&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; System.EventArgs)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;App&lt;/span&gt;() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;inherit&lt;/span&gt; Application()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; mainWindow&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; MainWindow &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; desktopLifetime&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; IClassicDesktopStyleApplicationLifetime &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.Initialize() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        __.Styles.Add(FluentTheme())&lt;br /&gt;        __.RequestedThemeVariant &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; Styling.ThemeVariant.Dark&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Application initialized with FluentTheme and Dark variant.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.OnFrameworkInitializationCompleted() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; __.ApplicationLifetime &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;:?&lt;/span&gt; IClassicDesktopStyleApplicationLifetime &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; (desktopLifetime&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; IClassicDesktopStyleApplicationLifetime) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            __.desktopLifetime &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; desktopLifetime&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// __.mainWindow &amp;lt;- new MainWindow()&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// desktopLifetime.MainWindow &amp;lt;- __.mainWindow&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// desktopLifetime.ShutdownMode &amp;lt;- ShutdownMode.OnMainWindowClose&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;MainWindow set as the main window.&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; ()&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System.Diagnostics&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Avalonia.Logging&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Cmdlet(VerbsDiagnostic.Test, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;AvaloniaFuncUI&amp;quot;&lt;/span&gt;)&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;OutputType(typeof&amp;lt;PSObject&amp;gt;)&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;SelectPocofCommand&lt;/span&gt;() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;inherit&lt;/span&gt; PSCmdlet()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; app &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// 先述した通り。略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        app&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.BeginProcessing() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;BeginProcessing called.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.ProcessRecord() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Hello from AvaloniaFuncUI&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.EndProcessing() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Starting Avalonia FuncUI application...&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; app &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; (app.Instance &lt;span class=&quot;hljs-operator&quot;&gt;:?&amp;gt;&lt;/span&gt; App)&lt;br /&gt;        app.mainWindow &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; MainWindow()&lt;br /&gt;        app.mainWindow.WindowStartupLocation &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; WindowStartupLocation.CenterScreen&lt;br /&gt;        app.desktopLifetime.MainWindow &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; app.mainWindow&lt;br /&gt;        app.desktopLifetime.ShutdownMode &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; ShutdownMode.OnMainWindowClose&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; cts &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Threading.CancellationTokenSource()&lt;br /&gt;&lt;br /&gt;        app.mainWindow.Closed.Add(&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;MainWindow closed, shutting down application.&amp;quot;&lt;/span&gt;&lt;br /&gt;            cts.Cancel())&lt;br /&gt;&lt;br /&gt;        app.mainWindow.Show()&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; ret &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; app.Run(cts.Token)&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;Avalonia FuncUI application started successfully. &lt;span class=&quot;hljs-subst&quot;&gt;{ret}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        app.mainWindow.Close()&lt;br /&gt;        cts.Cancel()&lt;br /&gt;&lt;br /&gt;        Console.WriteLine(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\n\n\n\n\n\n\n\n\n\n&amp;quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この 2 つの課題は、 Avalonia の基礎を抑えてたら困らないのかも知れないが、文書量も多いし example から体当たりで対処してしまった。
でも issue や discussion でも似たような話題があったから、わかりにくいところなんじゃないかなという気がせんでもない。
もっと良い方法があれば知りたい。
またこの調査をするに当たり、前例として他に PowerShell の中から GUI を起動する狂った事例ないか探してみたら、安定の Ironman Software さんが随分前にやってた。
他にもそこから派生した project もあった。
実現方法は違うが、 PowerShell でもできるということがわかり支えになった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ironmansoftware/psavalonia&quot; title=&quot;ironmansoftware/psavalonia: Avalonia bindings for PowerShell&quot;&gt;ironmansoftware/psavalonia: Avalonia bindings for PowerShell&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/pinuke/PWSH-AGUI&quot; title=&quot;pinuke/PWSH-AGUI: Asynchronous PowerShell GUI tool&quot;&gt;pinuke/PWSH-AGUI: Asynchronous PowerShell GUI tool&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;今回わたしがやろうとしてる F# で PowerShell Cmdlet を書いて Avalonia で GUI を表示するってのも、彼らに続く例がない狂った事例のはずだ。
うまく実現できたらこれは胸を張って良いはだろう。誰も興味ないやろうけど。&lt;/p&gt;
&lt;p&gt;まだ krymtkts/PSGameOfLife に反映してないし、 GUI 版の実装まで随分と時間がかかりそうだ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 15 Jun 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-06-08-writing-mini-game-in-fsharp-pt2.html</guid><link>https://krymtkts.github.io/posts/2025-06-08-writing-mini-game-in-fsharp-pt2.html</link><title>F# でミニゲームを書いてる Part 2</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2025-05-18-i-want-to-write-mini-game-in-fsharp.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;から始めた Game of Life の実装がようやく一歩前進した。
キャプチャは以下の通り。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/krymtkts/PSGameOfLife/0e4d2c04a578572c3e060e3dc93416b31967d9b0/docs/images/psgameoflife.gif&quot; title=&quot;game capture&quot; alt=&quot;game capture&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/&quot; title=&quot;PowerShell Gallery&quot;&gt;PowerShell Gallery&lt;/a&gt; に &lt;a href=&quot;https://www.powershellgallery.com/packages/PSGameOfLife/0.0.1&quot; title=&quot;v0.0.1&quot;&gt;v0.0.1&lt;/a&gt; として publish したので、 &lt;a href=&quot;https://github.com/krymtkts/PSGameOfLife&quot; title=&quot;repository krymtkts/PSGameOfLife&quot;&gt;repository krymtkts/PSGameOfLife&lt;/a&gt; も public にした。&lt;/p&gt;
&lt;p&gt;結局ゲームの提供方法は PowerShell Gallery を利用することにした。
つまり Cmdlet で実行できるゲームということだ。
仕事をサボってプレイする PowerFighter(勝手に作った PowerShell ユーザの呼称) が出てくること間違いなし。
自分の terminal で Game of Life を実行できるのはなんか良い。
まだ単に眺めるだけのゲームだが、気に入っている。&lt;/p&gt;
&lt;p&gt;実装力のショボさに故に CUI 版の実装自体に 1 週間ほどかかった。
その後時間が確保できなくて publish の準備に取りかかれず 2 週間ほど放置、久しぶりに暇を確保したので、今日公開にこぎつけられた。&lt;/p&gt;
&lt;p&gt;開発を通して Game of Life が極めて興味深い題材であり、作っていてのめり込んでしまう、いわば沼であることもわかった。
John Conway のルール以外にも様々なルールが有り、また初期配置もランダム・特定のパターン・アルゴリズムを利用するものがあるのを知った。
&lt;a href=&quot;https://conwaylife.com/wiki/&quot; title=&quot;LifeWiki&quot;&gt;LifeWiki&lt;/a&gt; が極めて勉強になるし、読んでて楽しい。&lt;/p&gt;
&lt;p&gt;今回作ったのはスタンダードな &lt;a href=&quot;https://conwaylife.com/wiki/Conway%27s_Game_of_Life&quot; title=&quot;B3/S23 Conway&amp;#39;s Life&quot;&gt;B3/S23 Conway&amp;#39;s Life&lt;/a&gt; という rule pattern みたい。
rule pattern は指定できるようにしてみたいな。
あと指定のパターンを読み込んで再生できるのが一般的らしい。&lt;/p&gt;
&lt;p&gt;このように、掘り下げていくと永久に GUI へたどり着かなさそうなので、とりあえず簡単に指定できる仕組みだけ作り GUI へ移ることにした。
GUI の実装ができたらまた戻ってくればいい。&lt;/p&gt;
&lt;p&gt;CUI 版の開発は &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; と同じように &lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; スタイルを採用した。
カーソル下に行追加して screen を作り、処理が終わったら掃除をする方法だ。
はじめはゲーム盤のサイズを指定できるようにしていたが処理が面倒すぎるのでコンソール全面を利用するように変えた。
世代交代を直列で計算してるし、描画も全面的な書き直しをするようになってるので、処理効率は良くない。
でも Windows Terminal では全画面にしても比較的 CPU load も低く、快適な動作になってた。
Visual Studio Code の terminal で試すとちょっと描画が重過ぎるみたいで、 Windows Terminal のように CPU load は低くならない既知の制約がある。&lt;/p&gt;
&lt;p&gt;PSGameOfLife は pocof と違って &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/frameworks&quot; title=&quot;&lt;code&gt;TargetFramework&lt;/code&gt;&quot;&gt;&lt;code&gt;TargetFramework&lt;/code&gt;&lt;/a&gt; を &lt;code&gt;net8.0&lt;/code&gt; にしている。
&lt;a href=&quot;https://learn.microsoft.com/ja-jp/powershell/scripting/install/PowerShell-Support-Lifecycle?view=powershell-7.5#powershell-end-of-support-dates&quot; title=&quot;サポート中の PowerShell&quot;&gt;サポート中の PowerShell&lt;/a&gt; を対象にしつつ、この先の GUI 化を見据えると &lt;code&gt;net8.0&lt;/code&gt; を下限にしておくのが無難そうだったからだ。
まだ使うの確定ではないが &lt;a href=&quot;https://github.com/fsprojects/Avalonia.FuncUI&quot; title=&quot;Avalonia.FuncUI&quot;&gt;Avalonia.FuncUI&lt;/a&gt; は &lt;a href=&quot;https://github.com/fsprojects/Avalonia.FuncUI/blob/213d336c0654b66afe4ff430e05f48cd1f667c08/src/Avalonia.FuncUI/Avalonia.FuncUI.fsproj&quot; title=&quot;&lt;code&gt;net8.0&lt;/code&gt; が下限&quot;&gt;&lt;code&gt;net8.0&lt;/code&gt; が下限&lt;/a&gt;みたい。
結果、 Windows PowerShell では使えなくなったので至極残念。なんか回避方法あれば提供できる可能性ある。
PowerShell 7.4 以降に対応していて、一応 Windows と Ubuntu on WSL2 では動作確認できている。&lt;/p&gt;
&lt;p&gt;因みにこの &lt;code&gt;net8.0&lt;/code&gt; に対応するのは思ったより手間取った。
初めはゲーム本体の project だけ &lt;code&gt;TargetFramework&lt;/code&gt; &lt;code&gt;net8.0&lt;/code&gt; にして、 test project は &lt;code&gt;net9.0&lt;/code&gt; にしてた。
これだと何故か &lt;code&gt;System.Runtime&lt;/code&gt; version 9.0.0.0 への参照が残ってしまい、 PowerShell 7.4 で &lt;code&gt;Import-Module&lt;/code&gt; するときエラーになってしまった。
結局どちらも &lt;code&gt;net8.0&lt;/code&gt; にすることで事なきを得たが、 test project の設定が何故影響したのか不明。&lt;/p&gt;
&lt;p&gt;これで遂に GUI programming に着手する準備が整ってしまったワケだ。
やれない理由がなくなってしまったし、そろそろ始めるかーという感じ。
test coverage はゲームのコア機能しかカバーしてなくて UI 部分をやってないので低いし、 UI 部分の interface 整理も含めて GUI 版の実装を進めるイメージでいる。
pocof でもそうだったが &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.console?view=net-9.0&quot; title=&quot;&lt;code&gt;Console&lt;/code&gt;&quot;&gt;&lt;code&gt;Console&lt;/code&gt;&lt;/a&gt; を使う部分をいい感じの testable にするの、未だにいい感じの方法がわかってないから、そこも模索する。
いきなり GUI を PSGameOfLife に組み込み始めるのか、なんか sample 的な repo で練習してみるかは、後で考えよう。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 08 Jun 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-06-01-snapshot-testing-with-playwright-in-fsharp.html</guid><link>https://krymtkts.github.io/posts/2025-06-01-snapshot-testing-with-playwright-in-fsharp.html</link><title>F# で Playwright の Snapshot testing</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; のための snapshot testing を &lt;a href=&quot;https://playwright.dev/dotnet/&quot; title=&quot;Playwright for .NET&quot;&gt;Playwright for .NET&lt;/a&gt; で作った。&lt;/p&gt;
&lt;p&gt;krymtkts/blog-fable は&lt;a href=&quot;https://github.com/krymtkts/krymtkts.github.io&quot; title=&quot;このブログ&quot;&gt;このブログ&lt;/a&gt;の基盤となる repo だ。
最近はブログに機能を足すこともまあないので、もっぱら依存関係の更新が主たる修正となってる。
krymtkts/blog-fable に対して &lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates&quot; title=&quot;Dependabot Version Updates&quot;&gt;Dependabot Version Updates&lt;/a&gt; が作った PR を取り込む。
&lt;a href=&quot;https://github.com/krymtkts/krymtkts.github.io&quot; title=&quot;krymtkts/krymtkts.github.io&quot;&gt;krymtkts/krymtkts.github.io&lt;/a&gt; はその歴史を取り込んで、依存関係が更新される。&lt;/p&gt;
&lt;p&gt;この更新される依存関係は &lt;a href=&quot;https://github.com/fable-compiler/Fable&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; 、 &lt;a href=&quot;https://github.com/fable-hub/Feliz&quot; title=&quot;Feliz&quot;&gt;Feliz&lt;/a&gt; 、 &lt;a href=&quot;https://github.com/markedjs/marked&quot; title=&quot;marked&quot;&gt;marked&lt;/a&gt; 、 &lt;a href=&quot;https://github.com/jgthms/bulma&quot; title=&quot;Bulma&quot;&gt;Bulma&lt;/a&gt; 等。
大きな変更があったら、出力される HTML や style 等の内容が壊れるタイプのものなのだ。
ごく稀に描画の結果が変わったりして(確か過去に)、気づかずそのまま出して慌てて週セ、みたいなのがあった。
それで依存関係の更新時は自動で PR を merge せずに、手動で動かしてみて目視チェックして OK なら merge している。
大した手間ではないが、それが面倒なのでどうにかしたいなと考えていた。&lt;/p&gt;
&lt;p&gt;こういった HTML の出力結果の違いを検知するには Snapshot testing が最適だ。
Playwright は使いやすさがイケてるとずっと聞いてたが触ったことなかったし、いい機会なので実装してみた。
動機が先述の通りなので、今のところ krymtkts.github.io では使わないつもり。日々の booklog や post を作るのが面倒になるだろうし。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/350&quot; title=&quot;Snapshot testing by krymtkts · Pull Request #350 · krymtkts/blog-fable&quot;&gt;Snapshot testing by krymtkts · Pull Request #350 · krymtkts/blog-fable&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;今回は snapshot testing にしたが、スタイルも含めた描画結果を visual comparison をするなら screenshot が一番いいだろう。
GitHub では履歴の画像の比較もできるし、そういう意味でも向いてるなと思った。&lt;/p&gt;
&lt;p&gt;ただ screenshot にすると描画される端末の影響が少なからずある。
これは自分の開発機で出力した結果と GitHub Actions に作った CI で出力した結果は必ずしも完全一致しない可能性があるということだ。
問題が発生したときいちいち調べるのは極めて面倒なので、今回描画された HTML の snapshot を保存し、それで比較することにした。
残念なことに Playwright for .NET の snapshot は style を含まない。
もし Bulma の出力する CSS が変わるような破壊的な変更だと気付けないことになる。
片手落ち感があるが仕方ないと一旦割り切る。&lt;/p&gt;
&lt;p&gt;ちなみに snapshot を取る機能は Playwright for .NET に組み込まれているが、どうも npm の Playwright のように高機能ではないらしい。
&lt;a href=&quot;https://github.com/microsoft/playwright-dotnet/issues/1854&quot; title=&quot;[Question]: Visual comparisons Feature Parity · Issue #1854 · microsoft/playwright-dotnet&quot;&gt;[Question]: Visual comparisons Feature Parity · Issue #1854 · microsoft/playwright-dotnet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ただそれ以前の話 krymtkts/blog-fable では &lt;a href=&quot;https://github.com/haf/expecto&quot; title=&quot;Expecto&quot;&gt;Expecto&lt;/a&gt; と Playwright の組み合わせでやったので、提供されてる unit test の base class がない。
&lt;a href=&quot;https://playwright.dev/dotnet/docs/intro&quot; title=&quot;Installation | Playwright .NET&quot;&gt;Installation | Playwright .NET&lt;/a&gt; に記載があるのは &lt;a href=&quot;https://github.com/microsoft/testfx&quot; title=&quot;MSTest&quot;&gt;MSTest&lt;/a&gt; 、 &lt;a href=&quot;https://github.com/nunit/nunit&quot; title=&quot;NUnit&quot;&gt;NUnit&lt;/a&gt; 、 &lt;a href=&quot;https://github.com/xunit/xunit&quot; title=&quot;xUnit&quot;&gt;xUnit&lt;/a&gt; だけある。
なので &lt;a href=&quot;https://playwright.dev/dotnet/docs/api/class-locatorassertions#locator-assertions-to-match-aria-snapshot&quot; title=&quot;&lt;code&gt;ToMatchAriaSnapshotAsync&lt;/code&gt;&quot;&gt;&lt;code&gt;ToMatchAriaSnapshotAsync&lt;/code&gt;&lt;/a&gt; のような便利な asserter が使えない。
仕方ないので、 snapshot の保存と比較は愚直に自前で実装した。
以下にほぼコピペママのコードを示す。
snapshot 毎に test を分けても良かったがこれも考えることが増えそうなので直列で実行する 1 ケースにした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Tests&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Expecto&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Expecto.Flip&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Microsoft.Playwright&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; DevServer&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Suave&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System.Threading&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;(*&lt;br /&gt;This tests requires the Playwright CLI to be installed.&lt;br /&gt;ex) PS&amp;gt; ./test/bin/Debug/*/playwright.ps1 install&lt;br /&gt;*)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;DevServer&lt;/span&gt;() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; home &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; IO.Path.Join [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-variable constant_&quot;&gt;__SOURCE_DIRECTORY__&lt;/span&gt;; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;..&amp;quot;&lt;/span&gt;; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;docs&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;]&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; port &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; port&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; root &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/blog-fable&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; webServer &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; startWebServerAsync (suaveConfig home) (webpart root) &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;snd&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; cancellationTokenSource &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; CancellationTokenSource()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;        Async.Start(webServer, cancellationTokenSource.Token)&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;Dev server started at http://localhost:%d&lt;span class=&quot;hljs-subst&quot;&gt;{port}&lt;/span&gt;%s&lt;span class=&quot;hljs-subst&quot;&gt;{root}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Port &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; port&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Root &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; root&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; IDisposable &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.Dispose() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Stopping dev server...&amp;quot;&lt;/span&gt;&lt;br /&gt;            cancellationTokenSource.Cancel()&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;IPlaywright&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.NewChromiumPage() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;task&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let!&lt;/span&gt; browser &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; __.Chromium.LaunchAsync()&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return!&lt;/span&gt; browser.NewPageAsync()&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;IPage&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.GotoAndCheck(url&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;task&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let!&lt;/span&gt; response &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; __.GotoAsync(url)&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; response &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Failed to load page: %s{url}&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; r &lt;span class=&quot;hljs-keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;not&lt;/span&gt; r.&lt;span class=&quot;hljs-literal&quot;&gt;Ok&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Failed to load page: %s{url}&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; r &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Ok&lt;/span&gt; r&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; snapshotDir &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; IO.Path.Combine(&lt;span class=&quot;hljs-variable constant_&quot;&gt;__SOURCE_DIRECTORY__&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;snapshots&amp;quot;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; ensureSnapshotDir () &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; snapshotDir &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; IO.Directory.Exists &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;        snapshotDir &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; IO.Directory.CreateDirectory &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; getSnapshotPath (path&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; path.StartsWith &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;failwith&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Path should not start with &amp;#x27;http&amp;#x27;. Use relative paths instead.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; fileName &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; path.Replace(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;_&amp;quot;&lt;/span&gt;)&lt;br /&gt;    IO.Path.Combine(snapshotDir, fileName &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.snapshot&amp;quot;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; saveSnapshot (path&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) (content&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    IO.File.WriteAllTextAsync(path, content, Text.Encoding.UTF8)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; loadSnapshot (path&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;task&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; path &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; IO.File.Exists &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let!&lt;/span&gt; content &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; IO.File.ReadAllTextAsync(path, Text.Encoding.UTF8)&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; content &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Tests&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; tests &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    testList &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;snapshot testing&amp;quot;&lt;/span&gt; [&lt;br /&gt;&lt;br /&gt;        testAsync &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;comparison&amp;quot;&lt;/span&gt; {&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; paths &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                [&lt;br /&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/index.html&amp;quot;&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-comment&quot;&gt;// ...直に URL を羅列している&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                  ]&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;use&lt;/span&gt; server &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; DevServer()&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; baseUrl&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;http://localhost:%d&lt;span class=&quot;hljs-subst&quot;&gt;{server.Port}&lt;/span&gt;%s&lt;span class=&quot;hljs-subst&quot;&gt;{server.Root}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            ensureSnapshotDir ()&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return!&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;TODO:&lt;/span&gt; i want to use testTask here, but i don&amp;#x27;t know how to convert it.&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;task&lt;/span&gt; {&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;use!&lt;/span&gt; playwright &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Playwright.CreateAsync()&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;let!&lt;/span&gt; page &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; playwright.NewChromiumPage()&lt;br /&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; path &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; paths &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; url &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; baseUrl &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; path&lt;br /&gt;                        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; snapshotPath &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; getSnapshotPath path&lt;br /&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Loading %s...&amp;quot;&lt;/span&gt; url&lt;br /&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-keyword&quot;&gt;let!&lt;/span&gt; response &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; url &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; page.GotoAndCheck&lt;br /&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; response &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Error&lt;/span&gt; msg &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;failwithf&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;%s&amp;quot;&lt;/span&gt; msg&lt;br /&gt;                        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Ok&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; ()&lt;br /&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; locator &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;html&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; page.Locator&lt;br /&gt;                        &lt;span class=&quot;hljs-keyword&quot;&gt;let!&lt;/span&gt; content &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; locator.AriaSnapshotAsync()&lt;br /&gt;                        &lt;span class=&quot;hljs-keyword&quot;&gt;let!&lt;/span&gt; expectedContent &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; snapshotPath &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; loadSnapshot&lt;br /&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; expectedContent &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt; expectedContent &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; content &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Expect.equal &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;Content mismatch for &lt;span class=&quot;hljs-subst&quot;&gt;{url}&lt;/span&gt;&amp;quot;&lt;/span&gt; expectedContent&lt;br /&gt;                        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                            &lt;span class=&quot;hljs-keyword&quot;&gt;do!&lt;/span&gt; saveSnapshot snapshotPath content&lt;br /&gt;                            &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;Saved new snapshot for %s&lt;span class=&quot;hljs-subst&quot;&gt;{url}&lt;/span&gt; to %s&lt;span class=&quot;hljs-subst&quot;&gt;{snapshotPath}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                }&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Async.AwaitTask&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Fable によって生成された HTML を &lt;code&gt;file://&lt;/code&gt; scheme で読み込んでも良かったが、 local server 経由にしている。
元々開発用 server も &lt;a href=&quot;https://github.com/SuaveIO/suave&quot; title=&quot;Suave&quot;&gt;Suave&lt;/a&gt; で作ってあるし、それを今回共通化する形で test project に取り入れた。
つまり従来の開発用 server は起動のみを行い、 server の定義本体は test project を参照するようになった。&lt;/p&gt;
&lt;p&gt;この開発用 server の流れで、当初は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/tools/fsharp-interactive/&quot; title=&quot;F# Interactive の script&quot;&gt;F# Interactive の script&lt;/a&gt; で snapshot testing も実装しようとしていた。
しかし Playwright の初期設定に実行する &lt;code&gt;./test/bin/Debug/*/playwright.ps1 install&lt;/code&gt; が &lt;code&gt;dotnet build&lt;/code&gt; されてる前提で、できなかった。
数年前は回避法があった ↓ ようだが、今では配置が変わったようで使えなかった。
ひょっとしたら別の回避方法があるかも知れないが。
&lt;a href=&quot;https://github.com/microsoft/playwright-dotnet/issues/1590&quot; title=&quot;Playwright in F# scripts · Issue #1590 · microsoft/playwright-dotnet&quot;&gt;Playwright in F# scripts · Issue #1590 · microsoft/playwright-dotnet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Playwright for .NET を F# で使うことに関しては、それほど困ることはなかった。
ただ Expecto と Playwright for .NET の組み合わせをあまり御しきれなかった。
Playwright for .NET の機能は概ね &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task?view=net-8.0&quot; title=&quot;&lt;code&gt;Task&lt;/code&gt;&quot;&gt;&lt;code&gt;Task&lt;/code&gt;&lt;/a&gt; を返すので、それをうまく使うには &lt;code&gt;testTask&lt;/code&gt; が良いだろうと思ったのだが、ダメだった。
&lt;code&gt;testTask&lt;/code&gt; は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1?view=net-9.0&quot; title=&quot;&lt;code&gt;ValueTask&lt;/code&gt;&quot;&gt;&lt;code&gt;ValueTask&lt;/code&gt;&lt;/a&gt; を期待してたり &lt;code&gt;use!&lt;/code&gt; で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync&quot; title=&quot;&lt;code&gt;IAsyncDisposable&lt;/code&gt;&quot;&gt;&lt;code&gt;IAsyncDisposable&lt;/code&gt;&lt;/a&gt; を期待してたりで、つなぐための glue code が多くなりもうええか、と。
結局 &lt;code&gt;testAsync&lt;/code&gt; の中で &lt;code&gt;task&lt;/code&gt; CE を &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-control-fsharpasync.html#AwaitTask&quot; title=&quot;&lt;code&gt;Async.AwaitTask&lt;/code&gt;&quot;&gt;&lt;code&gt;Async.AwaitTask&lt;/code&gt;&lt;/a&gt; するというイケてなさそうな書き方が最もシンプルになった。
これももっとうまく取り回せる方法があれば変えたい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;以上で最低限の簡単な snapshot testing 実装を終えた。
今後これを洗練してく動機はあまりないけど、 &lt;code&gt;testTask&lt;/code&gt; と Playwright の協調はもうちょっと頑張りたい気もするな。
snapshot の撮り直しも、今は作成済み snapshot を消して実行、という形だけなのでなんかあってもいいかも。でも今のも十分
簡素でよいが。
続くかも。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 01 Jun 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-05-25-github-streak-1000.html</guid><link>https://krymtkts.github.io/posts/2025-05-25-github-streak-1000.html</link><title>GitHub streak 1000</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;漸く GitHub の Current streak が 1000 を超えたので、それについて書く。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;今日時点で streak は 1008 らしい。
考えてみれば 1000 日以上続けられてるわけなので、コツコツ積み上げてこれた感じする。
でも世の中には 2000 超えや 3000 間近の人がいるのも事実なので、今後もひたすらに積み重ねていくのみやなと思っている。&lt;/p&gt;
&lt;p&gt;この積み重ねに何か意味があるのかという点にはついては、多分持たないと思ってる。
ひょっとしたら今の段階でも commit する所作が磨き抜かれて常人よりも速くなってるかも知れない。
でも 1000 を超えた今すごく変わったような実感はないので、 2000 でも 3000 でも同じ感想だろう。
ひたすら没頭し気付いたら周りとは一線画す何かを習得してた、みたいなことになってたら狂気があって良いな(自覚ないのはメタ認知に問題ありとも言えるが)。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-08-18-github-streak-2-years.html&quot; title=&quot;streak 2 年を達成するときの日記&quot;&gt;streak 2 年を達成するときの日記&lt;/a&gt; を読み返すと streak 自体がヌルゲーになってしまう危惧をしていたようだ。
実際のところ、習慣化した今となってもオートモードでも時間を消費するのは変わらないので、そういう意味だとヌルゲーではないかな。
booklog も習慣化したし、とにかく毎日やらないといけない習慣が決まっているので、その時間の確保をするための行動や計画をしている感じはある。
家族の予定や睡眠の時間を削るわけにはいかないし、如何にも効率厨的な作業ゲーなのかも知れない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/booklogs/hard-to-break.html&quot; title=&quot;習慣と脳の科学&quot;&gt;習慣と脳の科学&lt;/a&gt;を読んだことで、自身の習慣に対する解像度も上がった。
streak や booklog のような記録や行動の計画が継続に役立つという実感が、理論的な裏付けされたのが心強い。
それもあって、大きな環境の変化がない限りは、この習慣が途切れることはないだろうという自信にもつながっている。&lt;/p&gt;
&lt;p&gt;別に毎日続けなくてもいいねんよなというのはあるが、これは自分で決めた曲げられない自分ルールなので、今後も粛々と繰り返し積み重ねていくだけ。
正直なところ次のマイルストーンを設定する必要もないのだけど、とりあえずもうちょっとで満 3 年なので、まずそこ。
その次は毎周年を祝いつつ 2000, 3000 を記念できていけばいいか。
明らかに満 2 年を達成したときより熱量が低くて淡々としており実によろしい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 25 May 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-05-18-i-want-to-write-mini-game-in-fsharp.html</guid><link>https://krymtkts.github.io/posts/2025-05-18-i-want-to-write-mini-game-in-fsharp.html</link><title>F# でミニゲームを書きたい</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2025-05-11-writing-cmdline-predictor-in-fsharp-pt8.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;で &lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; は落ち着いたつもり。
&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; もまだ弄りたいところはあるけどちまちましたもののつもり。
なので今日は今後やりたいなと思ってることをメモしておく。&lt;/p&gt;
&lt;p&gt;なんとなく最近触れてないタイプのテクノロジに触れたいなーと思っており、そういえばここ数年まともに GUI やってないなと気付いた。
ここ数年の仕事では React やら PHP やらもっと前なら Delphi やら Visual Basic やらで GUI 色々やってた。けど趣味ではやったことはない。
そこで、折角なので F# で GUI やれないかなと考えた。ネイティブ寄りの GUI を。
やるならミニゲームやな。ゲーム開発となると全くの未経験なのでちょうどよかろう。&lt;/p&gt;
&lt;p&gt;ひとまず GUI のフレームワークに関して。
まずきょう時点のわたしが知る限りの、 F# の GUI 周りをまとめておく。
とはいうものの、 F# の UI 事情がちょっとややこしくてわかってないので、振り返りも兼ねている。&lt;/p&gt;
&lt;p&gt;最初は &lt;a href=&quot;https://github.com/elmish/elmish&quot; title=&quot;Elmish&quot;&gt;Elmish&lt;/a&gt; について。&lt;/p&gt;
&lt;p&gt;最初 Elmish は &lt;a href=&quot;https://github.com/fable-compiler/Fable&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; のものかと思ってたが、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/desktop/wpf/overview/?view=netdesktop-9.0&quot; title=&quot;WPF&quot;&gt;WPF&lt;/a&gt; や &lt;a href=&quot;https://github.com/AvaloniaUI/Avalonia&quot; title=&quot;Avalonia&quot;&gt;Avalonia&lt;/a&gt; をターゲットにしてもいけるらしい。 Web だけじゃないんか。
要は Elmish 自体はビルド先が何かは関係ない。
Elm-ish な Model-View-Update architecture を導入するメタパッケージ的なやつで、 platform に合わせた実装部分が切り離されてる。
少なくとも 2025-05-17 時点では。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The goal of the architecture is to provide a solid UI-independent core to build the rest of the functionality around. Elm architecture operates using the following concepts, as they translate to Elmish:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Elmish のページにもそんなふうに書いてある。&lt;/p&gt;
&lt;p&gt;次は、先に名前が上がったが、 &lt;a href=&quot;https://github.com/AvaloniaUI/Avalonia&quot; title=&quot;Avalonia&quot;&gt;Avalonia&lt;/a&gt; について。&lt;/p&gt;
&lt;p&gt;Avalonia もよくわからん。
OSS の .NET の coss platform UI framework 。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/desktop/winforms/overview/?view=netdesktop-9.0&quot; title=&quot;Windows Forms&quot;&gt;Windows Forms&lt;/a&gt; 、 WPF や &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/maui/what-is-maui?view=net-maui-9.0&quot; title=&quot;MAUI&quot;&gt;MAUI&lt;/a&gt; といった MS 謹製 UI framework とは別の世界にいるみたい。
F# で Avalonia を使うなら、 &lt;a href=&quot;https://github.com/fsprojects/Avalonia.FuncUI&quot; title=&quot;fsprojects/Avalonia.FuncUI&quot;&gt;fsprojects/Avalonia.FuncUI&lt;/a&gt; があって、 FP らしい宣言的 UI の書き方ができる。
Avalonia.FuncUI はそれ単体で使えるけど、&lt;a href=&quot;https://www.nuget.org/packages/Avalonia.FuncUI.Elmish&quot; title=&quot;Avalonia.FuncUI.Elmish&quot;&gt;Avalonia.FuncUI.Elmish&lt;/a&gt; という package もあって「え... Elmish で使えんの？」というのもわかった。
Avalonia を Elm-ish に使うための package やと &lt;a href=&quot;https://github.com/fsprojects/Avalonia.FuncUI?tab=readme-ov-file#example-using-elmish&quot; title=&quot;Avalonia.FuncUI の &lt;code&gt;README.md&lt;/code&gt;&quot;&gt;Avalonia.FuncUI の &lt;code&gt;README.md&lt;/code&gt;&lt;/a&gt; に sample が載ってる。
登場人物 2 名の時点でややこしくなってきた。&lt;/p&gt;
&lt;p&gt;あと F# には &lt;a href=&quot;https://github.com/fabulous-dev/Fabulous&quot; title=&quot;Fabulous&quot;&gt;Fabulous&lt;/a&gt; もあったわ。&lt;/p&gt;
&lt;p&gt;Fabulous はモダンな宣言的 UI framework で、 Elmish 同様に MVU architecture を導入するためのメタパッケージ。
それ自体は UI control を持たない。
↓ に引用した文が &lt;a href=&quot;https://docs.fabulous.dev/&quot; title=&quot;Fabulous 2.0 | Fabulous&quot;&gt;Fabulous 2.0 | Fabulous&lt;/a&gt; に書いてあった。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that Fabulous itself does not provide UI controls, so you&amp;#39;ll need to combine it with another framework like Xamarin.Forms, .NET MAUI or AvaloniaUI.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最後に Windows Forms や WFP (多少面倒らしい)は F# 直でも使え。 MAUI は無理なんか情報見当たらず。
いったんこれは抜きに考えようか。&lt;/p&gt;
&lt;p&gt;結局のところ以下になるのかな。ややこしすぎる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;何らかの UI のパターンを導入するなら Elmish, Avalonia.FuncUI, Fabulous の 3 つの選択肢&lt;/li&gt;&lt;li&gt;cross platform 抜きに考えたら Windows Forms, WPF, MAUI, Avalonia の 4 つの選択肢&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;もっと踏み込んだ話になると、 UI component 毎に得意な Platform がそれぞれ違うらしいが、もうそこまでは追いきれないからやめ。&lt;/p&gt;
&lt;p&gt;とりあえず GUI 周りはこんな感じか。
でもこれらが pixel 描画に向いてるかどうかは全く知らんのよね。
これらの土俵じゃないんかなー。わからなさすぎて最高。
可能であれば cross platform にいきたいけど、面倒そうなら最初は Windows Forms で始めて...みたいなのもありか。 &lt;code&gt;System.Drawing&lt;/code&gt; を使えばいいのよな。&lt;/p&gt;
&lt;p&gt;題材は、お試しなので Game of Life みたいなよく知られた簡単そうなやつから始められたら良さそう。
ひとまず F# の CUI の Game of Life 実装があったから fork した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/conways-game-of-life-fsharp&quot; title=&quot;krymtkts/conways-game-of-life-fsharp: F# implementation of Conway&amp;#39;s game of life&quot;&gt;krymtkts/conways-game-of-life-fsharp: F# implementation of Conway&amp;#39;s game of life&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;試しに動かしてみたら、わたしの 2017 年の laptop ではパフォーマンスに問題があったので最適化してみた。
そのコードをいじる過程に並行して Wikipedia の Game of Life のページを見たりして理解を深めたつもり。
ゲームのコアの部分と描画部分は切り分け可能なので、こいつで得た知識をもとにコアを実装、 GUI は別途練習して、最後につなげるみたいな流れでできたらいいのかな。&lt;/p&gt;
&lt;p&gt;日記に書く暇あったら sample だけでもはよ作れよという感じではあるが。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 18 May 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-05-11-writing-cmdline-predictor-in-fsharp-pt8.html</guid><link>https://krymtkts.github.io/posts/2025-05-11-writing-cmdline-predictor-in-fsharp-pt8.html</link><title>F# で command-line predictor を書いてる Part 8 - 0.4.0</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; の &lt;a href=&quot;https://www.powershellgallery.com/packages/SnippetPredictor/0.4.0&quot; title=&quot;v0.4.0&quot;&gt;v0.4.0&lt;/a&gt; をリリースした。&lt;/p&gt;
&lt;p&gt;v0.4.0 は主に &lt;a href=&quot;https://github.com/ionide/FSharp.Analyzers.SDK&quot; title=&quot;FSharp.Analyzer.SDK&quot;&gt;FSharp.Analyzer.SDK&lt;/a&gt; とか &lt;a href=&quot;https://github.blog/changelog/2025-04-29-dependabot-reviewers-configuration-option-being-replaced-by-code-owners/&quot; title=&quot;Dependabot の &lt;code&gt;reviewers&lt;/code&gt; の置き換え&quot;&gt;Dependabot の &lt;code&gt;reviewers&lt;/code&gt; の置き換え&lt;/a&gt;ととか、内部的なリソース管理の更新とか、機能に関係ない更新が多かった。
その中で唯一 snippet に設定した group を部分一致で suggestion に表示する機能を追加した。
この機能は、例えば個人の環境と仕事の環境で snippet が違うことはよくあって、その場合に何の group があるかインタラクティブに一覧できるといいかなという動機でつけた。
自分が実際そういう使い方なので、あると記憶を引き出すのが楽かな的な。
仮に利用者が自分でつけた group を覚えてたら使う機会もないだろう。&lt;/p&gt;
&lt;p&gt;元々は &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/register-argumentcompleter?view=powershell-7.5&quot; title=&quot;&lt;code&gt;Register-ArgumentCompleter&lt;/code&gt;&quot;&gt;&lt;code&gt;Register-ArgumentCompleter&lt;/code&gt;&lt;/a&gt; みたいな補完候補を出してもらえると良いのではないかと考えた。
でもその場合 &lt;code&gt;:&lt;/code&gt; を擬似的な native command にして、そこから &lt;code&gt;commandAst&lt;/code&gt; を分解して～みたいな手順になり、なんか違うなと。コマンドじゃないし。
なので落とし所としては command-line predictor の仕組みに閉じるのが良いかなと判断した。&lt;/p&gt;
&lt;p&gt;現状は入力似合わせて &lt;code&gt;:group&lt;/code&gt; が suggestion に表示されるのみなので、もうちょっとリッチな表現にできんかな―という気もする。
が、その場合 &lt;code&gt;.snippet-predictor.json&lt;/code&gt; に group に関する付加情報を足すことになりそうだし、一旦やめた。
snippet の先頭数文字を切り出して tooltip に足してもいいかな。幅が全然足りなそうだけど。
さらに言えば suggestion の表示優先順位を設定したいが、 command-line predictor にその仕組みがないから現状できない。
そこはキーワード入力して絞り込んでいくことで代替するイメージ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2025-03-23-writing-cmdline-predictor-in-fsharp-pt5.html&quot; title=&quot;v0.2.0 を出したとき&quot;&gt;v0.2.0 を出したとき&lt;/a&gt;に SnippetPredictor の開発は一段落したかといってそうならなかったが、今回で流石に一段落しただろう。
またなんか新しいアイデア探すか、いま &lt;code&gt;README.md&lt;/code&gt; が質素なのでその辺を AI に拡充させるとか、そんな感じかな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 11 May 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-05-04-writing-cmdlet-in-fsharp-pt67.html</guid><link>https://krymtkts.github.io/posts/2025-05-04-writing-cmdlet-in-fsharp-pt67.html</link><title>F# で Cmdlet を書いてる pt.67 - Completed migration from FsUnit.xUnit to Expecto</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/FsUnit.Xunit/&quot; title=&quot;FsUnit.xUnit v6.x&quot;&gt;FsUnit.xUnit v6.x&lt;/a&gt; を &lt;a href=&quot;https://github.com/haf/expecto&quot; title=&quot;Expecto&quot;&gt;Expecto&lt;/a&gt; へ置き換えた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/343&quot; title=&quot;#343&quot;&gt;#343&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;多くは単純な書き換え作業だったし、書き換え方を決めたりサンプル実装を示せば、あとは GitHub Copilot Agent にほぼ作業を任せられたのは楽だったと言えるか。
ただしうまく働かせるにはそれなりの工夫が必要だった。&lt;/p&gt;
&lt;p&gt;Copilot Agent にとって初めてのファイルので作業は、プロンプト等の参考になる情報を渡してもうまく作れなかった。
代替手段として、同じファイル内にサンプル実装を足してやれば、自分で修正できるみたい。
知名度的に学習ソースにないからか、 &lt;a href=&quot;https://github.com/haf/expecto&quot; title=&quot;Expecto&quot;&gt;Expecto&lt;/a&gt; で利用可能な assertion が何か知らなくてその辺もサポートしてやる必要があった。&lt;/p&gt;
&lt;p&gt;あと 1000 行超えるような長いファイルになると途端に処理が遅くなってダメだった。
CPU が天井に張り付いてたし、開発 PC の laptop が 2017 モノでしょぼいからだと思われる。
Agent 自体は local の性能そんなに必要としないと思ってたが違うようだ。
でも &lt;code&gt;module&lt;/code&gt; や &lt;code&gt;type&lt;/code&gt; で小分けに作業を頼むと、遅いがなんとか少しずつ進められるようだった。 80 点くらいのコードは出せる感じなところも優秀な新人ぽい感触。
なので頼んでは別のことをして、回答が揃ったら手直ししてやるみたいな進め方が一番良い。&lt;/p&gt;
&lt;p&gt;ただこの方法でも、スコープ内のテストケースが多いとテストケースを削った結果を出力してきて困った。
テストケースの数が減ってるから全ケースを書き直して出力して、と指示しても頑なに守れなかったので手で直して。この場合は回避手段あるのか怪しい。 Agent でも読み解けるような量のコードにする必要があるのかもな。&lt;/p&gt;
&lt;p&gt;単純な書き換えのあとは、 xUnit と FsCheck の統合 &lt;a href=&quot;https://fscheck.github.io/FsCheck/RunningTests.html#Using-FsCheck-Xunit&quot; title=&quot;&lt;code&gt;PropertyAttribute&lt;/code&gt;&quot;&gt;&lt;code&gt;PropertyAttribute&lt;/code&gt;&lt;/a&gt; を Expecto 形式に書き換えた。
FsUnit.xUnit 用の PropertyAttribute を使ってるのもあって、ちょっと書き換え面倒なのではと思ったが、 config に書き換えるだけだったのでさっくりいった。
以下のように書き換えた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// FsUnit&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Property(Arbitrary = [| typeof&amp;lt;UnknownAction&amp;gt; |])&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``should return unknown action error.``&lt;/span&gt; (data&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        data&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Action.fromString&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; shouldEqual (&lt;span class=&quot;hljs-literal&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;Unknown Action &amp;#x27;&lt;span class=&quot;hljs-subst&quot;&gt;{data}&lt;/span&gt;&amp;#x27;.&amp;quot;&lt;/span&gt;)&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Prop.collect data&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// Expecto&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Tests&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; tests_unknownAction &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; configUnknown &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            { FsCheckConfig.defaultConfig &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                arbitrary &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; [ &lt;span class=&quot;hljs-built_in&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;UnknownAction&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; ] }&lt;br /&gt;&lt;br /&gt;        testList&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Action.fromString (unknown)&amp;quot;&lt;/span&gt;&lt;br /&gt;            [&lt;br /&gt;&lt;br /&gt;              testPropertyWithConfig configUnknown &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;When unknown action, should return error&amp;quot;&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; (data&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                  data&lt;br /&gt;                  &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Action.fromString&lt;br /&gt;                  &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Expect.equal &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;should return unknown action error&amp;quot;&lt;/span&gt; (&lt;span class=&quot;hljs-literal&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;Unknown Action &amp;#x27;&lt;span class=&quot;hljs-subst&quot;&gt;{data}&lt;/span&gt;&amp;#x27;.&amp;quot;&lt;/span&gt;)&lt;br /&gt;                  &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Prop.collect data&lt;br /&gt;&lt;br /&gt;              ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コード量増えとるがな！というのは置いといて、依存関係の競合を解消するためには乗り換えるのが最善手だったので良いのだ。&lt;/p&gt;
&lt;p&gt;これで終わりだと思っていたが、 &lt;a href=&quot;https://github.com/dotnet/BenchmarkDotNet&quot; title=&quot;BenchmarkDotnet&quot;&gt;BenchmarkDotnet&lt;/a&gt; を使っている benchmark の project で &lt;code&gt;dotnet build&lt;/code&gt; 時にエラーが出るようになった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. &amp;#x27;namespace SomeNamespace.SubNamespace&amp;#x27; or &amp;#x27;module SomeNamespace.SomeModule&amp;#x27;. Only the last source file of an application may omit such a declaration.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;どういうわけか BenchmarkDotnet を呼び出すための &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/entry-point#explicit-entry-point&quot; title=&quot;&lt;code&gt;EntryPoint&lt;/code&gt;&quot;&gt;&lt;code&gt;EntryPoint&lt;/code&gt;&lt;/a&gt; 付き &lt;code&gt;main&lt;/code&gt; 関数が競合しているという。
始めよくわからなかったが、コード上には競合がないし、自動生成される entry point なんやろなということろでピンときた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;benchmark の project は test 用の UI の mock を project reference で借りてきてる&lt;/li&gt;&lt;li&gt;test project は Expecto を利用するようになったので &lt;a href=&quot;https://github.com/YoloDev/YoloDev.Expecto.TestSdk&quot; title=&quot;YoloDev.Expecto.TestSdk&quot;&gt;YoloDev.Expecto.TestSdk&lt;/a&gt; を使っている&lt;/li&gt;&lt;li&gt;YoloDev.Expecto.TestSdk は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/testing/microsoft-testing-platform-intro?tabs=dotnetcli&quot; title=&quot;Microsoft.Testing.Platform&quot;&gt;Microsoft.Testing.Platform&lt;/a&gt; に対応しており実行ファイルが生成される&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;つまりこいつが entry point を生成してるみたい。
今考えたらそらそうかという感じなのだけど。&lt;/p&gt;
&lt;p&gt;以下のように project の asset から除外するものを指定したらエラーを解消できた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/344&quot; title=&quot;#344&quot;&gt;#344&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;ProjectReference&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Include&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;..\pocof.Test\pocof.Test.fsproj&amp;quot;&lt;/span&gt; &amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;ExcludeAssets&lt;/span&gt;&amp;gt;&lt;/span&gt;build; analyzers; buildtransitive&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;ExcludeAssets&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;ProjectReference&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;結構作業は多かったが乗り換え完了。念願果たせた。
前回も触れたが testing framework の乗り換えってあまり人生でも起こらない(面倒でやらない)から、いい経験になった。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 04 May 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-04-27-writing-cmdlet-in-fsharp-pt66.html</guid><link>https://krymtkts.github.io/posts/2025-04-27-writing-cmdlet-in-fsharp-pt66.html</link><title>F# で Cmdlet を書いてる pt.66 - from FsUnit.xUnit to Expecto</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。
&lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; の開発で得た知識を展開している。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fsprojects/FSharpLint&quot; title=&quot;FSharpLint&quot;&gt;FSharpLint&lt;/a&gt; に代わる &lt;a href=&quot;https://github.com/ionide/FSharp.Analyzers.SDK/&quot; title=&quot;FSharp.Analyzer.SDK&quot;&gt;FSharp.Analyzer.SDK&lt;/a&gt; &lt;a href=&quot;https://github.com/ionide/ionide-analyzers/&quot; title=&quot;Ionide.Analyzers&quot;&gt;Ionide.Analyzers&lt;/a&gt; の導入は簡単に済んだ。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/340&quot; title=&quot;#340&quot;&gt;#340&lt;/a&gt;
良い。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/active-patterns#return-type-for-partial-active-patterns&quot; title=&quot;bool Partial active Pattern&quot;&gt;bool Partial active Pattern&lt;/a&gt; のような F# 9 で増えた feature はチェックできてないみたい？なのでそこは追って調べていくつもり。&lt;/p&gt;
&lt;p&gt;次に念願であり一番の大物である &lt;a href=&quot;https://www.nuget.org/packages/FsUnit.Xunit/&quot; title=&quot;FsUnit.xUnit v6.x&quot;&gt;FsUnit.xUnit v6.x&lt;/a&gt; の &lt;a href=&quot;https://github.com/haf/expecto&quot; title=&quot;Expecto&quot;&gt;Expecto&lt;/a&gt; へ置き換えを始めた。
これはちょっと時間がかかりそうだ。
&lt;a href=&quot;/posts/2025-01-05-writing-cmdlet-in-fsharp-pt60.html&quot; title=&quot;前にも触れた&quot;&gt;前にも触れた&lt;/a&gt;が、 FsUnit.xUnit v7 は xUnit v3 に依存してるが &lt;a href=&quot;https://github.com/fscheck/FsCheck&quot; title=&quot;FsCheck&quot;&gt;FsCheck&lt;/a&gt; は現状 v2 に依存している。
これによって依存関係が塩漬けされているので、この際乗り換えようという算段だ。&lt;/p&gt;
&lt;p&gt;まずひとつ学んだのは、 FsUnit.xUnit(というか xUnit v2) と Expecto は共存できるということ。
ただし Expecto は &lt;a href=&quot;https://github.com/YoloDev/YoloDev.Expecto.TestSdk&quot; title=&quot;YoloDev.Expecto.TestSdk&quot;&gt;YoloDev.Expecto.TestSdk&lt;/a&gt; を導入して &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/testing/microsoft-testing-platform-intro?tabs=dotnetcli&quot; title=&quot;Microsoft Testing Platform&quot;&gt;Microsoft Testing Platform&lt;/a&gt; で動かす前提だ。 Expecto のテスト実行を以下のように &lt;code&gt;EntryPoint&lt;/code&gt; に含めてもだめだった。
ちゃんと調べてないが xUnit v2 のテスト検出の仕組みでは &lt;code&gt;EntryPoint&lt;/code&gt; はただの compile を通すだけのハリボテて対象に含まれないのだと思われる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Program&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Expecto&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;EntryPoint&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; main argv &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    runTestsInAssemblyWithCLIArgs [] argv &lt;span class=&quot;hljs-comment&quot;&gt;// こうしても Expecto のテストが検出されない&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;先述の通り YoloDev.Expecto.TestSdk を使い以下の構成してみたらうまく両方のテストが実行されて素晴らしかった。
testing framework の共存・乗り換えってあまり人生でも起こらないし、いい経験になった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- 略 --&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;ItemGroup&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- ここから--&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PackageReference&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Include&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Expecto&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Version&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;10.2.3&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PackageReference&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Include&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;YoloDev.Expecto.TestSdk&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Version&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;0.15.3&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- ここまでが増えた--&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; FsCheck.Xunit does not support xUnit.v3 yet. --&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PackageReference&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Include&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;FsCheck.Xunit&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Version&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;3.2.0&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PackageReference&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Include&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;FsUnit.xUnit&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Version&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;6.0.1&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PackageReference&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Include&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Microsoft.NET.Test.Sdk&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Version&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;17.13.0&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Replace xunit with xunit.v3 from FsUnit.xUnit 7. --&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PackageReference&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Include&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;xunit&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Version&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;2.9.3&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PackageReference&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Include&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;xunit.runner.visualstudio&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Version&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;3.0.2&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;IncludeAssets&lt;/span&gt;&amp;gt;&lt;/span&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;IncludeAssets&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PrivateAssets&lt;/span&gt;&amp;gt;&lt;/span&gt;all&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;PrivateAssets&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;PackageReference&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- 略 --&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;ItemGroup&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- 略 --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この辺なんでうまくいったのか理解できるような Microsoft Testing Platform の解像度を持ち得ていないので、そこを掘り下げるのは今後の宿題としたい。&lt;/p&gt;
&lt;p&gt;これで FsUnit.xUnit 形式のテストを Expecto で書き換え始めたわけで、 test case の書き換えを始めた。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/343&quot; title=&quot;#343&quot;&gt;#343&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;変更に関しては、これまで以下の前者の形式だったやつを、後者の通りにするだけ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// FsUnit.xUnit&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Option &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Fact&amp;gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``shouldn&amp;#x27;t call Dispose if Some.``&lt;/span&gt; () &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// Expecto&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Tests&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; tests_Option &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        testList&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Option&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// このカッコの書き方は行を余計に確保するが、この方がテストケースを足すとか先頭末尾のカッコの重なりを回避できてよろしい&lt;/span&gt;&lt;br /&gt;            [&lt;br /&gt;&lt;br /&gt;              test &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;When Some.&amp;quot;&lt;/span&gt; {&lt;br /&gt;                  &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;                  mock.disposed &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Expect.isTrue &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;should call Dispose&amp;quot;&lt;/span&gt;&lt;br /&gt;              }&lt;br /&gt;&lt;br /&gt;              ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;だがご覧の通り、 FsUnit.xUnit では module name と let で記述していたテストの内容を Expecto では &lt;code&gt;name&lt;/code&gt; なり &lt;code&gt;message&lt;/code&gt; に分割して記述する必要がある。
これまでデタラメ English で書いてた test case の説明を校正するような感じ。&lt;/p&gt;
&lt;p&gt;人力でやるの辛いなと思い GitHub Copilot に託してみた。
最初 GitHub Copilot は Chat も Agent mode でもイマイチだったが、一度お手本を書いてやると良い感じに動き出した。恐ろしい学習力やな。
Copilot Agent はこの説明を校正するのを初手ではうまくやれなくて重複した文章を取り除いたりできなかったが、 session 中で回を重ねるとどんどん良くなる。恐ろしい子。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[&amp;lt;Fact&amp;gt;]&lt;/code&gt; → &lt;code&gt;[&amp;lt;Test&amp;gt;]&lt;/code&gt; の書き換えは簡単にできるとわかったから、ざーっと全体を直してしまえそう。
その後は FsUnit.xUnit の FsCheck 統合 &lt;code&gt;[&amp;lt;Property&amp;gt;]&lt;/code&gt; を Expecto 形式に直すイメージで進める。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 27 Apr 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-04-20-writing-cmdline-predictor-in-fsharp-pt7.html</guid><link>https://krymtkts.github.io/posts/2025-04-20-writing-cmdline-predictor-in-fsharp-pt7.html</link><title>F# で command-line predictor を書いてる Part 7 - GitHub Code Scanning</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ionide/FSharp.Analyzers.SDK/&quot; title=&quot;Fsharp.Analyzers.SDK&quot;&gt;Fsharp.Analyzers.SDK&lt;/a&gt; で作成した Code Scanning Alerts の解消をした。 &lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor/pull/48&quot; title=&quot;#48&quot;&gt;#48&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ただ Code Scanning Alerts が解消されたにも関わらず Open なままだった。
よくわからんなーと思っていたのだが、途中で Code Scanning の configuration を変えたらそうなるという仕様のようだった。なんてこったい。
解消するには以下の通り、古いのと新しい configuration とが競合してることによるようなので、古い方を消したら良いようだ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/community/discussions/23403&quot; title=&quot;Fixed code scanning alerts still show up as open · community · Discussion #23403&quot;&gt;Fixed code scanning alerts still show up as open · community · Discussion #23403&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.blog/changelog/2023-03-10-delete-stale-code-scanning-configurations-to-close-outdated-alerts/&quot; title=&quot;Delete stale code scanning configurations to close outdated alerts - GitHub Changelog&quot;&gt;Delete stale code scanning configurations to close outdated alerts - GitHub Changelog&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;消してみたら全部の alerts が解消されてスッキリした。&lt;/p&gt;
&lt;p&gt;因みに alert の内容は妥当な感じのやつだったが 1 つ困ったのがあった。
このルール。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ionide.io/ionide-analyzers/suggestion/012.html&quot; title=&quot;StructDiscriminatedUnionAnalyzer | ionide-analyzers&quot;&gt;StructDiscriminatedUnionAnalyzer | ionide-analyzers&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;RequireQualifiedAccess&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;NoEquality&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;NoComparison&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;SearchCaseSensitive&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; CaseSensitive&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; CaseInsensitive
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こういう DU を作って、それに &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.threading.interlocked?view=net-9.0&quot; title=&quot;&lt;code&gt;Interlocked&lt;/code&gt;&quot;&gt;&lt;code&gt;Interlocked&lt;/code&gt;&lt;/a&gt; を使って atomic な操作をしてるところがあった。
この DU を &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions#struct-discriminated-unions&quot; title=&quot;Struct Discriminated Unions&quot;&gt;Struct Discriminated Unions&lt;/a&gt; にしてもいいよというヒント。
メモリが無駄なのでって文脈だろう。
構造体にすると &lt;code&gt;Interlocked&lt;/code&gt; を使えなくなるし(参照型で wrap してもまじで意味ない)、どうしたもんかと。
個別の alert を無効化する方法がわからなかったし、ヒントなので対応しなくても良いのだけど、 alert は 0 の方が安心感ある。
この際なので &lt;code&gt;Interlocked&lt;/code&gt; で DU を扱うのをやめて &lt;code&gt;int&lt;/code&gt; に変換する形で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/values/#mutable-variables&quot; title=&quot;&lt;code&gt;mutable&lt;/code&gt; な変数&quot;&gt;&lt;code&gt;mutable&lt;/code&gt; な変数&lt;/a&gt;に格納するように変えた。
こんなんを使う。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;   &lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; CaseSensitivity &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Literal&amp;gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; sensitive &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Literal&amp;gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; insensitive &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; SearchCaseSensitivity &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; ofBool &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; CaseSensitivity.sensitive&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; CaseSensitivity.insensitive&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; stringComparison &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; CaseSensitivity.sensitive &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; StringComparison.Ordinal&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; StringComparison.OrdinalIgnoreCase
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;因みにずっと知らずに生きてきたのだが、変数名が upper case で始まる場合 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/match-expressions&quot; title=&quot;&lt;code&gt;match&lt;/code&gt; expression&quot;&gt;&lt;code&gt;match&lt;/code&gt; expression&lt;/a&gt; の pattern に使えるみたい。
そうなんや...よく今まで生きてこれたな。
でも F# like な命名に即すると Upper camel case は違和感ある。
この場合上記のように module で修飾すれば良い。&lt;/p&gt;
&lt;p&gt;やっぱこういう気付きがあることからも、 F# のような強力な言語でも linter の類はあった方がいいよな。
&lt;a href=&quot;https://github.com/fsprojects/FSharpLint&quot; title=&quot;FSharpLint&quot;&gt;FSharpLint&lt;/a&gt; を使いこなせなくなって久しかったので助かった。&lt;/p&gt;
&lt;p&gt;FSharpLint のメンテに関しては、 2 週間ほど前に追加のメンテナをコミュニティで募集しよか？と Don さんが issue 立ててた。なんか変化起こるかなー。
&lt;a href=&quot;https://github.com/fsprojects/FSharpLint/issues/721&quot; title=&quot;Checking on on maintainers status · Issue #721 · fsprojects/FSharpLint&quot;&gt;Checking on on maintainers status · Issue #721 · fsprojects/FSharpLint&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 20 Apr 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-04-13-writing-cmdline-predictor-in-fsharp-pt6.html</guid><link>https://krymtkts.github.io/posts/2025-04-13-writing-cmdline-predictor-in-fsharp-pt6.html</link><title>F# で command-line predictor を書いてる Part 6 - FSharp.Analyzer.SDK</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; の &lt;a href=&quot;https://www.powershellgallery.com/packages/SnippetPredictor/0.3.0&quot; title=&quot;v0.3.0&quot;&gt;v0.3.0&lt;/a&gt; をリリースした。&lt;/p&gt;
&lt;p&gt;v0.3.0 の新しい機能は、&lt;a href=&quot;/posts/2025-03-23-writing-cmdline-predictor-in-fsharp-pt5.html&quot; title=&quot;前&quot;&gt;前&lt;/a&gt;に触れていた snippet の検索の case-sensitivity を指定する option の追加だ。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ただこれは &lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; の挙動的には &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/psreadline/set-psreadlineoption?view=powershell-7.5#-historysearchcasesensitive&quot; title=&quot;&lt;code&gt;HistorySearchCaseSensitive&lt;/code&gt;&quot;&gt;&lt;code&gt;HistorySearchCaseSensitive&lt;/code&gt;&lt;/a&gt; で制御可能なので、設定ファイルに持たせた方がいいかも。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;今度こそ一通りの機能が揃ったか。
あと使い出して感じてるのが、よく使う snippet の表示順位を上げられたらいいなというところだが、この場合 snippet を選んだ履歴を記録する必要があるからなんともなという感じ。
&lt;code&gt;.snippet-predictor.json&lt;/code&gt; とは別に二重で記録するわけになるからなんともな。これは本当に必要か検討を要する。&lt;/p&gt;
&lt;p&gt;あと、 SnippetPredictor は長らく linter の類を CI に組み込んでなかったのだけど、追加したのでそれを記録しておく。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;SnippetPredictor は &lt;a href=&quot;/posts/2024-11-24-writing-cmdlet-in-fsharp-pt54.html&quot; title=&quot;pocof での経験から FSharpLint をうまく使えてない&quot;&gt;pocof での経験から FSharpLint をうまく使えてない&lt;/a&gt;のもあって、 linter の類を CI に組み込んでなかった。
しかし最近 &lt;a href=&quot;https://github.com/ionide/FSharp.Analyzers.SDK/&quot; title=&quot;Fsharp.Analyzers.SDK&quot;&gt;Fsharp.Analyzers.SDK&lt;/a&gt; で解析できるのを知ったので、これを導入してコード解析する。
知ったきっかけは &lt;a href=&quot;https://github.com/fsprojects/fantomas&quot; title=&quot;Fantomas&quot;&gt;Fantomas&lt;/a&gt; で使われてるのを見つけたから。
スキャン結果の SARIF report を生成して GitHub の Code Scanning にアップロードしてた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fsprojects/fantomas/blob/938160e6c9660af5bda33e4d20c7b522b8359789/.github/workflows/main.yml&quot; title=&quot;fantomas/.github/workflows/main.yml at 938160e6c9660af5bda33e4d20c7b522b8359789 · fsprojects/fantomas&quot;&gt;fantomas/.github/workflows/main.yml at 938160e6c9660af5bda33e4d20c7b522b8359789 · fsprojects/fantomas&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;数ヶ月 FSharpLint が使えなくなって無防備になってるわたしにとっては、こりゃ良さそうだと考えた。&lt;/p&gt;
&lt;p&gt;導入の手順は &lt;a href=&quot;https://ionide.io/FSharp.Analyzers.SDK/content/getting-started/Installing%20Analyzers.html&quot; title=&quot;Installation | FSharp.Analyzers.SDK&quot;&gt;Installation | FSharp.Analyzers.SDK&lt;/a&gt; と &lt;a href=&quot;https://ionide.io/ionide-analyzers/&quot; title=&quot;Ionide.Analyzers | ionide-analyzers&quot;&gt;Ionide.Analyzers | ionide-analyzers&lt;/a&gt; を参考にした。&lt;/p&gt;
&lt;p&gt;はじめに tool を導入する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet tool install fsharp&lt;span class=&quot;hljs-literal&quot;&gt;-analyzers&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;次に解析対象の project に &lt;code&gt;Ionide.Analyzers&lt;/code&gt; を追加する。
初めてなので、単純化のため &lt;a href=&quot;https://github.com/G-Research/fsharp-analyzers/&quot; title=&quot;G-Research.FSharp.Analyzers&quot;&gt;G-Research.FSharp.Analyzers&lt;/a&gt; の導入はしてない。
最新 version がわからなかったので、 &lt;code&gt;dotnet add ~&lt;/code&gt; で追加してから &lt;code&gt;IncludeAssets&lt;/code&gt; を編集した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet add ./src/SnippetPredictor package Ionide.Analyzers
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- Analyzer configurations. --&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PackageReference&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Include&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Ionide.Analyzers&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Version&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;0.14.4&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;IncludeAssets&lt;/span&gt;&amp;gt;&lt;/span&gt;runtime; build; native; contentfiles; analyzers&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;IncludeAssets&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PrivateAssets&lt;/span&gt;&amp;gt;&lt;/span&gt;all&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;PrivateAssets&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;PackageReference&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/fsprojects/Paket&quot; title=&quot;Paket&quot;&gt;Paket&lt;/a&gt; を使ってない場合、実行するには analyzer の path を &lt;code&gt;--analyzers-path&lt;/code&gt; に指定する必要がある。
FSharp.Analyzers.SDK にはその path を知る方法が書いてない(熟練の .NET ユーザにならよく知られたものかも知れないが)。
Ionide.Analyzers の方はその点わかりやすく、具体的に NuGet で install された analyzer の配置先を取得するための手順が記載されている。
これを使って以下のようにコマンドを構築でき、実行できるようになった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$analyzerPath&lt;/span&gt; = dotnet build ./src/SnippetPredictor  &lt;span class=&quot;hljs-literal&quot;&gt;--getProperty&lt;/span&gt;:PkgIonide_Analyzers&lt;br /&gt;dotnet fsharp&lt;span class=&quot;hljs-literal&quot;&gt;-analyzers&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--project&lt;/span&gt; ./src/SnippetPredictor/SnippetPredictor.fsproj &lt;span class=&quot;hljs-literal&quot;&gt;--analyzers-path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$analyzerPath&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Snippet.fs(163,4): Hint IONIDE-012 : Consider adding [&amp;lt;Struct&amp;gt;] to Discriminated Union&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Snippet.fs(314,28): Hint IONIDE-010 : Seq.filter |&amp;gt; Seq.map can be combined into Seq.choose&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Snippet.fs(89,16): Info IONIDE-002 : Prefer postfix syntax for arrays.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Snippet.fs(144,15): Warning IONIDE-005 : Test for empty strings should use the String.Length property or the String.IsNullOrEmpty method.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Snippet.fs(319,18): Warning IONIDE-005 : Test for empty strings should use the String.Length property or the String.IsNullOrEmpty method.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# C:\Users\takatoshi\dev\github.com\krymtkts\SnippetPredictor\src\SnippetPredictor\Library.fs(65,20): Info IONIDE-002 : Prefer postfix syntax for arrays.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コマンドのオプションは文書に載ってなかったので、 &lt;code&gt;--help&lt;/code&gt; で確認した。
&lt;a href=&quot;https://sarifweb.azurewebsites.net/&quot; title=&quot;SARIF&quot;&gt;SARIF&lt;/a&gt; report を出力するには &lt;code&gt;--report&lt;/code&gt; に file path を指定するだけで良い。&lt;/p&gt;
&lt;p&gt;とりあえずコード解析はうまくできるのがわかったので SnippetPredictor の CI に組み込んだ。 &lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor/pull/45&quot; title=&quot;#45&quot;&gt;#45&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;CI 的には warn は error にして task をこかせたいところだが、今のところ &lt;code&gt;--treat_as_error&lt;/code&gt; で個別の識別子を指定するしかないっぽい。どうしたもんかな。
他にも、今は test の project を解析対象にしてないのもあるし、 &lt;a href=&quot;https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory?view=vs-2022#directorybuildprops-and-directorybuildtargets&quot; title=&quot;&lt;code&gt;Directory.Build.props&lt;/code&gt;&quot;&gt;&lt;code&gt;Directory.Build.props&lt;/code&gt;&lt;/a&gt; で全体に反映するのがいいかな。
Fantomas では tool の &lt;code&gt;fsharp-analyzers&lt;/code&gt; は使ってなくて MSBuild でやってるのだけど、同じ方法を採用するかはちょっと検討。&lt;/p&gt;
&lt;p&gt;もうちょっと使ってみて、いい感じの設定ができたら &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; にも反映させよう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 13 Apr 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-04-06-fix-dependabot-nuget-project-not-found.html</guid><link>https://krymtkts.github.io/posts/2025-04-06-fix-dependabot-nuget-project-not-found.html</link><title>NuGet の Dependabot で project が見つからないエラーを直した</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;2025-02E 頃から .Net (NuGet) の &lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates&quot; title=&quot;Dependabot version updates&quot;&gt;Dependabot version updates&lt;/a&gt; が失敗するようになって、なんでかわからんしそのうち直るかなと放置していた。
ただ全然直らないし、 &lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; でもエラーになってるので、最近になってようやく重い腰を上げて調べてみたところ、以下のようなエラーが出いていた。例は &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; のもの。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/actions/runs/14252933221/job/39949755290&quot; title=&quot;nuget in /. - Update #992720506 · krymtkts/pocof@29eff1c&quot;&gt;nuget in /. - Update #992720506 · krymtkts/pocof@29eff1c&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;2025/04/03 21:16:53 INFO Temporarily removing `global.json` from `/home/dependabot/dependabot-updater/repo`.&lt;br /&gt;2025/04/03 21:16:53 INFO Restoring `global.json` to `/home/dependabot/dependabot-updater/repo`.&lt;br /&gt;2025/04/03 21:16:53 INFO Discovering build files in workspace [/home/dependabot/dependabot-updater/repo].&lt;br /&gt;2025/04/03 21:16:53 INFO   Discovered [.config/dotnet-tools.json] file.&lt;br /&gt;2025/04/03 21:16:53 INFO   Discovered [global.json] file.&lt;br /&gt;2025/04/03 21:16:53 INFO   Discovering projects beneath [.].&lt;br /&gt;2025/04/03 21:16:53 INFO   No project files found.&lt;br /&gt;2025/04/03 21:16:53 INFO Discovery complete.&lt;br /&gt;updater | 2025/04/03 21:16:53 INFO &amp;lt;job_992720506&amp;gt; Discovery JSON content: {&lt;br /&gt;  ... 長いので省略 ...&lt;br /&gt;}&lt;br /&gt;updater | 2025/04/03 21:16:53 INFO &amp;lt;job_992720506&amp;gt; Discovery JSON path for workspace path [/] found in file [/home/dependabot/.dependabot/discovery_map.json] at location [/home/dependabot/.dependabot/discovery.1.json]&lt;br /&gt;updater | 2025/04/03 21:16:53 INFO &amp;lt;job_992720506&amp;gt; Discovery JSON path for workspace path [/] found in file [/home/dependabot/.dependabot/discovery_map.json] at location [/home/dependabot/.dependabot/discovery.1.json]&lt;br /&gt;updater | 2025/04/03 21:16:53 ERROR &amp;lt;job_992720506&amp;gt; Error during file fetching; aborting: Repo must contain .(cs|vb|fs)proj file.&lt;br /&gt;  proxy | 2025/04/03 21:16:53 [024] POST /update_jobs/992720506/record_update_job_error&lt;br /&gt;  proxy | 2025/04/03 21:16:53 [024] 204 /update_jobs/992720506/record_update_job_error&lt;br /&gt;  proxy | 2025/04/03 21:16:53 [026] PATCH /update_jobs/992720506/mark_as_processed&lt;br /&gt;  proxy | 2025/04/03 21:16:54 [026] 204 /update_jobs/992720506/mark_as_processed&lt;br /&gt;updater | 2025/04/03 21:16:54 INFO &amp;lt;job_992720506&amp;gt; Finished job processing&lt;br /&gt;updater | 2025/04/03 21:16:54 INFO Results:&lt;br /&gt;Dependabot encountered &amp;#x27;1&amp;#x27; error(s) during execution, please check the logs for more details.&lt;br /&gt;+---------------------------+&lt;br /&gt;|          Errors           |&lt;br /&gt;+---------------------------+&lt;br /&gt;| dependency_file_not_found |&lt;br /&gt;+---------------------------+&lt;br /&gt;Failure running container 8fc2652dfc6bfe10bbe91cc64e0fa63347c0031374edc8419b45c3ce073dcff5&lt;br /&gt;Cleaned up container 8fc2652dfc6bfe10bbe91cc64e0fa63347c0031374edc8419b45c3ce073dcff5&lt;br /&gt;  proxy | 2025/04/03 21:16:55 3/13 calls cached (23%)&lt;br /&gt;  proxy | 2025/04/03 21:16:55 Posting metrics to remote API endpoint&lt;br /&gt;Error: Dependabot encountered an error performing the update&lt;br /&gt;&lt;br /&gt;Error: The updater encountered one or more errors.&lt;br /&gt;&lt;br /&gt;For more information see: https://github.com/krymtkts/pocof/network/updates/992720506 (write access to the repository is required to view the log)&lt;br /&gt;🤖 ~ finished: error reported to Dependabot ~
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;No project files found.&lt;/code&gt; というログやら &lt;code&gt;dependency_file_not_found&lt;/code&gt; というエラーがでて &lt;code&gt;fsproj&lt;/code&gt; が見つからなくなってる。
このとき &lt;code&gt;dependabot.yml&lt;/code&gt; はこうしていた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Maintain dependencies for NuGet&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;package-ecosystem:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;nuget&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;directory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;エラー発生以前は、この設定で指定した &lt;code&gt;directory&lt;/code&gt; 配下に対して再帰的に &lt;code&gt;fsproj&lt;/code&gt; を検索できていたという認識だが。
ただ Copilot や ChatGPT に聞いてもそんなことはできないという。
そこで Dependabot の文書をあたってみたところ、今回初めて知ったのだが、 &lt;code&gt;directory&lt;/code&gt; は project などの依存関係を管理するファイルが直に配置されてないといけないようだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#directories-or-directory--&quot; title=&quot;Dependabot options reference - GitHub Docs&quot;&gt;Dependabot options reference - GitHub Docs&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use to define the location of the package manifests for each package manager (for example, the package.json or Gemfile).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;エラー発生以前の、 &lt;code&gt;directory&lt;/code&gt; 配下に対して再帰的に &lt;code&gt;fsproj&lt;/code&gt; を検索できていたのが、むしろ間違っていたと。
なんてこったい。&lt;/p&gt;
&lt;p&gt;krymtkts/pocof のように複数のディレクトリに依存関係を管理するファイルが配置されている場合は、複数指定できる &lt;code&gt;directories&lt;/code&gt; を使うと良いそうだ。
また、 &lt;code&gt;directories&lt;/code&gt; では &lt;a href=&quot;https://en.wikipedia.org/wiki/Glob_(programming)&quot; title=&quot;glob pattern&quot;&gt;glob pattern&lt;/a&gt; が使える。
それにより pocof では結果的に以下のように 1 要素だけの定義で済んだ。
krymtkts/SnippetPredictor も同様に対処した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Maintain dependencies for NuGet&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;package-ecosystem:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;nuget&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; dependabot raises dependency_file_not_found error with root directory.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; directories can use glob patterns.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;directories:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/src/pocof*&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最後に、これはこの先絶対忘れそうだなということで、備忘のための note も残した。&lt;/p&gt;
&lt;p&gt;再帰的に検索するほうが便利よなと考えるが、仕様に準拠してないとなればまあ直すよなという感じ。
他の package manager 用の Dependabot と挙動が違うようでは尚更。
何にせよ、自身の間違いに気づき、エラーが解決できてよかった。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 06 Apr 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-03-30-global-jsonc.html</guid><link>https://krymtkts.github.io/posts/2025-03-30-global-jsonc.html</link><title>global.json は JSONC</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;旅行中のため小ネタ。
個人的な無知ゆえに知らなかったものだが、備忘のため記しておく。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/tools/global-json&quot; title=&quot;global.json overview - .NET CLI | Microsoft Learn&quot;&gt;global.json overview - .NET CLI | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Comments in global.json files are supported using JavaScript or C# style comments. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;// This is a comment.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;sdk&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;8.0.300&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;/* This is comment 2*/&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;/* This is a&lt;br /&gt;  multiline comment.*/&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;まじか。
&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; において &lt;a href=&quot;https://github.com/dotnet/sdk/issues/46857&quot; title=&quot;macOS の GitHub Actions workflow でのみ &lt;code&gt;dotnet tool restore&lt;/code&gt; がエラーになる問題&quot;&gt;macOS の GitHub Actions workflow でのみ &lt;code&gt;dotnet tool restore&lt;/code&gt; がエラーになる問題&lt;/a&gt;があったとき、 .NET SDK を version 固定しないといけなかったので&lt;a href=&quot;https://github.com/krymtkts/pocof/commit/d4ff96628ce470a52e74b29fdd0b67f44161e6e0&quot; title=&quot;そのメモを残す&quot;&gt;そのメモを残す&lt;/a&gt;のに使った。&lt;/p&gt;
&lt;p&gt;因みにもしやと思って他に思いつく .NET 系の設定ファイルで試したところ、 &lt;code&gt;dotnet-tools.json&lt;/code&gt; はダメだった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; dotnet tool restore&lt;br /&gt;Json parsing error &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; file C:\Users\takatoshi\dev\github.com\krymtkts\pocof\.config\dotnet&lt;span class=&quot;hljs-literal&quot;&gt;-tools&lt;/span&gt;.json : &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;/&amp;#x27;&lt;/span&gt; is invalid after a value. Expected either &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;,&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;}&amp;#x27;&lt;/span&gt;, or &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;]&amp;#x27;&lt;/span&gt;. LineNumber: &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; | BytePositionInLine: &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;dotnet-tools.json&lt;/code&gt; で jspnc をサポートしたいという提案は過去にもあったらしいが、頓挫したようだ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/runtime/issues/30316&quot; title=&quot;Support of comments in jsondocument · Issue #30316 · dotnet/runtime&quot;&gt;Support of comments in jsondocument · Issue #30316 · dotnet/runtime&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/sdk/issues/10384&quot; title=&quot;Enable comments for tool manifest json · Issue #10384 · dotnet/sdk&quot;&gt;Enable comments for tool manifest json · Issue #10384 · dotnet/sdk&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/sdk/issues/16043&quot; title=&quot;[Feature Request] Support jsonc for dotnet tools manifest · Issue #16043 · dotnet/sdk&quot;&gt;[Feature Request] Support jsonc for dotnet tools manifest · Issue #16043 · dotnet/sdk&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;JSON のコメントと空白をどう扱うべきかに関してふにゃふにゃだったので XML に軍配が上がったて流れぽい。議論も止まった様子。&lt;/p&gt;
&lt;p&gt;とりあえず &lt;code&gt;global.json&lt;/code&gt; だけでも JSONC が使えるということやが、この流れが他にも派生していくかというと、&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/introducing-slnx-support-dotnet-cli/&quot; title=&quot;最近 sln が slnx になった&quot;&gt;最近 sln が slnx になった&lt;/a&gt;流れを見てても XML 優勢なんかなと思えてくるな。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;2025-04-01 追記。&lt;/p&gt;
&lt;p&gt;このネタ普通に&lt;a href=&quot;/posts/2025-03-02-writing-cmdlet-in-fsharp-pt65.html&quot; title=&quot;前の日記&quot;&gt;前の日記&lt;/a&gt;で書いてたわｗ
ネタ帳から削り忘れてたか...&lt;/p&gt;
&lt;p&gt;まあ slnx とも繋げたので全く同じではないか...ということでご愛嬌。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Tue, 01 Apr 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-03-23-writing-cmdline-predictor-in-fsharp-pt5.html</guid><link>https://krymtkts.github.io/posts/2025-03-23-writing-cmdline-predictor-in-fsharp-pt5.html</link><title>F# で command-line predictor を書いてる Part 5 - coverage 100% にする</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; の &lt;a href=&quot;https://www.powershellgallery.com/packages/SnippetPredictor/0.2.0&quot; title=&quot;v0.2.0&quot;&gt;v0.2.0&lt;/a&gt; をリリースした。&lt;/p&gt;
&lt;p&gt;v0.2.0 の新しい機能は、&lt;a href=&quot;/posts/2025-03-16-writing-cmdline-predictor-in-fsharp-pt4.html&quot; title=&quot;前回触れた tooltip や snippet に付与した group での絞り込み&quot;&gt;前回触れた tooltip や snippet に付与した group での絞り込み&lt;/a&gt; や、他にも &lt;code&gt;:snp&lt;/code&gt; 等の symbol 指定で絞り込む際に case-insensitive にしてみた。
ただこれは &lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; の挙動的には &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/psreadline/set-psreadlineoption?view=powershell-7.5#-historysearchcasesensitive&quot; title=&quot;&lt;code&gt;HistorySearchCaseSensitive&lt;/code&gt;&quot;&gt;&lt;code&gt;HistorySearchCaseSensitive&lt;/code&gt;&lt;/a&gt; で制御可能なので、設定ファイルに持たせた方がいいかも。&lt;/p&gt;
&lt;p&gt;あと今回の version から coverage 100% にしてみた。
やはり 100% となると、 GitHub Actions で cross platform な test してるのもあって利用可能な全ての platform で一度はコードが実行されてエラーにならないのを保証できるので、安心感が違うなと感じる。
今回 100% にするために、半ば無理やり全部通すような test を書いた。
unit test に適さない環境変数周りの処理や、 &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.management.automation.subsystem.icommandpredictor?view=powershellsdk-7.2.0&quot; title=&quot;&lt;code&gt;ICommandPredictor&lt;/code&gt;&quot;&gt;&lt;code&gt;ICommandPredictor&lt;/code&gt;&lt;/a&gt; の使わない method のような通常利用で到達不能な部分もだ。&lt;/p&gt;
&lt;p&gt;例えば以下の &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonignorecondition?view=net-9.0&quot; title=&quot;&lt;code&gt;JsonIgnoreCondition.WhenWritingNull&lt;/code&gt;&quot;&gt;&lt;code&gt;JsonIgnoreCondition.WhenWritingNull&lt;/code&gt;&lt;/a&gt; と &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverter-1?view=net-9.0&quot; title=&quot;&lt;code&gt;JsonConverter&lt;/code&gt;&quot;&gt;&lt;code&gt;JsonConverter&lt;/code&gt;&lt;/a&gt; 実装の組み合わせだと、 &lt;code&gt;reader.GetString&lt;/code&gt; が &lt;code&gt;null&lt;/code&gt; を返す場面がない。
&lt;code&gt;null&lt;/code&gt; の処理が skip されることによるみたい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;GroupJsonConverter&lt;/span&gt;() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;inherit&lt;/span&gt; JsonConverter&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Literal&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; pattern &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;^[A-Za-z0-9]+$&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; regex &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Regex(pattern)&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; _.Read(reader&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;byref&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;Utf8JsonReader&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;, _typeToConvert&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Type, options&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; JsonSerializerOptions) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        reader.GetString()&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; value &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; value &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; unreachable when JsonIgnoreCondition.WhenWritingNull is used.&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; value &lt;span class=&quot;hljs-keyword&quot;&gt;when&lt;/span&gt; regex.IsMatch(value) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; value&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; value &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; JsonException(&lt;span class=&quot;hljs-built_in&quot;&gt;sprintf&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Invalid characters in group: %s&amp;quot;&lt;/span&gt; value) &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;raise&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; _.Write(writer&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Utf8JsonWriter, value&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;, options&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; JsonSerializerOptions) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        value &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; writer.WriteStringValue&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;SnippetEntry&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    { Snippet&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;      Tooltip&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;JsonConverter(typeof&amp;lt;GroupJsonConverter&amp;gt;)&amp;gt;]&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)&amp;gt;]&lt;/span&gt;&lt;br /&gt;      Group&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;しかも &lt;code&gt;GroupJsonConverter&lt;/code&gt; を直接テストしようにも、シグネチャファイルに記載してなかったのでそのままだとテストできない。
公開するつもりもない型なので足す気もないし。
結果的に &lt;code&gt;DEBUG&lt;/code&gt; 条件付きでシグネチャファイルに含めるようにして直接テストするようにした。&lt;/p&gt;
&lt;p&gt;シグネチャファイルがこう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#if&lt;/span&gt; DEBUG&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;GroupJsonConverter&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;inherit&lt;/span&gt; System.Text.Json.Serialization.JsonConverter&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; GroupJsonConverter&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; Read&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        reader&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;byref&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;System.Text.Json.Utf8JsonReader&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt;&lt;br /&gt;        _typeToConvert&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; System.Type &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt;&lt;br /&gt;        options&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; System.Text.Json.JsonSerializerOptions &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            string&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; Write&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        writer&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; System.Text.Json.Utf8JsonWriter &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; value&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; options&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; System.Text.Json.JsonSerializerOptions &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            unit&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;テストコードはこう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#if&lt;/span&gt; DEBUG&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; GroupJsonConverter &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System.Text.Json&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Tests&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; test_GroupJsonConverter &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        testList&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;GroupJsonConverter&amp;quot;&lt;/span&gt;&lt;br /&gt;            [&lt;br /&gt;&lt;br /&gt;              test &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;when the value is null &amp;quot;&lt;/span&gt; {&lt;br /&gt;                  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; json &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&amp;quot;{&amp;quot;key&amp;quot;: null}&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;mutable&lt;/span&gt; reader &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Utf8JsonReader(System.Text.Encoding.UTF8.GetBytes(json))&lt;br /&gt;&lt;br /&gt;                  reader.Read() &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// {&lt;/span&gt;&lt;br /&gt;                  reader.Read() &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// &amp;quot;key&amp;quot;&lt;/span&gt;&lt;br /&gt;                  reader.Read() &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// null&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; result&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                      GroupJsonConverter().Read(&lt;span class=&quot;hljs-operator&quot;&gt;&amp;amp;&lt;/span&gt;reader, &lt;span class=&quot;hljs-built_in&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;, JsonSerializerOptions())&lt;br /&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; result &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; ()&lt;br /&gt;                  &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; failtest &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Expected null but got a different value&amp;quot;&lt;/span&gt;&lt;br /&gt;              }&lt;br /&gt;&lt;br /&gt;              ]&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あと F# ならではの coverage 100% の難しさとして、 &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/standard/glossary#il&quot; title=&quot;IL(中間言語)&quot;&gt;IL(中間言語)&lt;/a&gt; に到達不可能な pass が生成されるケースがある。
既知のものでいうと例えば &lt;a href=&quot;https://krymtkts.github.io/posts/2024-04-14-how-to-check-coverage-for-inline-functions.html&quot; title=&quot;string の slicing&quot;&gt;string の slicing&lt;/a&gt; 。
今回は新たに &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/members/let-bindings-in-classes&quot; title=&quot;&lt;code&gt;static let&lt;/code&gt;&quot;&gt;&lt;code&gt;static let&lt;/code&gt;&lt;/a&gt; でも到達不能な pass が生成されるのを確認した。&lt;/p&gt;
&lt;p&gt;例えば以下、 &lt;code&gt;static let&lt;/code&gt; によって &lt;code&gt;internal static int init@47&lt;/code&gt; が生成され、 &lt;code&gt;Read&lt;/code&gt; method に分岐が生えてしまう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;GroupJsonConverter&lt;/span&gt;() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;inherit&lt;/span&gt; JsonConverter&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Literal&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; pattern &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;^[A-Za-z0-9]+$&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; regex &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Regex(pattern)&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; _.Read(reader&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;byref&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;Utf8JsonReader&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;, _typeToConvert&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Type, options&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; JsonSerializerOptions) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        reader.GetString()&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; value &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; value &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; unreachable when JsonIgnoreCondition.WhenWritingNull is used.&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; value &lt;span class=&quot;hljs-keyword&quot;&gt;when&lt;/span&gt; regex.IsMatch(value) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; value&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; value &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; JsonException(&lt;span class=&quot;hljs-built_in&quot;&gt;sprintf&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Invalid characters in group: %s&amp;quot;&lt;/span&gt; value) &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;raise&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上記コードは &lt;a href=&quot;https://github.com/icsharpcode/ILSpy&quot; title=&quot;ILSpy&quot;&gt;ILSpy&lt;/a&gt; で decompile して C# 表示したらこうなる。 &lt;code&gt;int@47&lt;/code&gt; という属性の分岐が確認できる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;[&lt;span class=&quot;hljs-meta&quot;&gt;Serializable&lt;/span&gt;]&lt;br /&gt;[&lt;span class=&quot;hljs-meta&quot;&gt;CompilationMapping(/*Could not decode attribute arguments.*/)&lt;/span&gt;]&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;GroupJsonConverter&lt;/span&gt; : &lt;span class=&quot;hljs-title&quot;&gt;JsonConverter&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-title&quot;&gt;string&lt;/span&gt;&amp;gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; Regex regex;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;init&lt;/span&gt;@&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;? Read(&lt;span class=&quot;hljs-keyword&quot;&gt;ref&lt;/span&gt; Utf8JsonReader reader, Type _typeToConvert, JsonSerializerOptions options)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; @string = reader.GetString();&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; text = @string;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; text2 = text;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (text2 != &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;value&lt;/span&gt; = text2;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;init&lt;/span&gt;@&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt; &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                IntrinsicFunctions.FailStaticInit();&lt;br /&gt;            }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;初期化済みか判断する用途くさいが具体的に値が設定される箇所とかがわからなかった。
取り敢えず &lt;code&gt;static let&lt;/code&gt; を使うと期待しない分岐が発生するのはわかったので、別 module に切り出すことで分岐をなくした。&lt;/p&gt;
&lt;p&gt;ややこしい気もするが 100% を目指すと汚れ仕事も必要なのだ。&lt;/p&gt;
&lt;p&gt;SnippetPredictor の開発は機能的にはこれで一段落かな。
あとは日常利用で、先述の case-insensitive にするやつとか細々とした気になる点に手をいれるくらいの予想。
またなんか新しいアイデア探すか。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 23 Mar 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-03-16-writing-cmdline-predictor-in-fsharp-pt4.html</guid><link>https://krymtkts.github.io/posts/2025-03-16-writing-cmdline-predictor-in-fsharp-pt4.html</link><title>F# で command-line predictor を書いてる Part 4 - v0.2.0 むけの新機能</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;新しい機能として、 tooltip での絞り込みと、 snippet に付与した group での絞り込みを追加した。
&lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor/pull/22&quot; title=&quot;#22&quot;&gt;#22&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor/pull/23&quot; title=&quot;#23&quot;&gt;#23&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これによって以下の絞り込みのバリエーションが増えた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:snp&lt;/code&gt; で snippet の絞り込み&lt;/li&gt;&lt;li&gt;&lt;code&gt;:tip&lt;/code&gt; で tooltip の絞り込み&lt;/li&gt;&lt;li&gt;&lt;code&gt;:{group}&lt;/code&gt; で指定した識別子の group で snippet の絞り込み&lt;/li&gt;&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Snippets&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Snippet&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet new classlib --name project --language F# --output ./src/project&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Tooltip&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Create a new F# class library project&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Group&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;fsharp&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Snippet&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet tool install fantomas --prerelease&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Tooltip&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Install or update Fantomas&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Group&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;fsharp&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Snippet&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet new sln&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Tooltip&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Create a new solution file&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;Group&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;project&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;みたいなんがあったとして、 &lt;code&gt;:fsharp&lt;/code&gt; で絞れる。
この例のように、 F# 関連でまとめておきたい snippet があって snippet や tooltip に &lt;code&gt;F#&lt;/code&gt; を含まないような場合に &lt;code&gt;&amp;quot;Group&amp;quot;: &amp;quot;fsharp&amp;quot;&lt;/code&gt; でまとめておけるというメリットがあるはず。
group のこの用途だと実は tooltip の記述を工夫すれば代用できるが、 &lt;code&gt;Get-Snippet&lt;/code&gt; で取得した snippet を &lt;code&gt;Where-Object&lt;/code&gt; で楽に絞り込むには、やはり別の field を持っているのが最適だと考えた。&lt;/p&gt;
&lt;p&gt;今のところ、この group の絞り込みを使うことで絞り込み対象の母数が減って速くなるということはない。愚直に snippet の sequence を絞り込むのに group の条件がついただけになってる。
snippet の登録件数がそんなに多くならないだろうし、空間計算量に寄せるほどでもないかなという直感だ。
もし今後件数が増えまくったりして、 &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-cmdline-predictor?view=powershell-7.5#creating-the-code&quot; title=&quot;command-line predictor の 20ms の制限&quot;&gt;command-line predictor の 20ms の制限&lt;/a&gt;に触れてくるようなら再検討する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Group&lt;/code&gt; field に設定する値に長さの制限はないが、文字種は &lt;code&gt;[a-zA-Z0-9]&lt;/code&gt; しか使えなくしている。
&lt;code&gt;Add-Snippet&lt;/code&gt; でも制限されているし、 &lt;code&gt;.snippet-predictor.json&lt;/code&gt; 読み込み時にも制限されてる。
また &lt;code&gt;Group&lt;/code&gt; field は省略可能なので、従来(というほど古くもないけど)の &lt;code&gt;.snippet-predictor&lt;/code&gt; の記述通り &lt;code&gt;Group&lt;/code&gt; なしの snippet も読める。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Group&lt;/code&gt; field の制限は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.text.json?view=net-9.0&quot; title=&quot;System.Text.Json Namespace&quot;&gt;System.Text.Json Namespace&lt;/a&gt; を使ってこんなコードでできた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;GroupJsonConverter&lt;/span&gt;() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;inherit&lt;/span&gt; JsonConverter&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Literal&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; pattern &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;^[A-Za-z0-9]+$&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; regex &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Regex(pattern)&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; _.Read(reader&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;byref&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;Utf8JsonReader&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;, _typeToConvert&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Type, options&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; JsonSerializerOptions) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        reader.GetString()&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; value &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; value &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; unreachable when JsonIgnoreCondition.WhenWritingNull is used.&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; value &lt;span class=&quot;hljs-keyword&quot;&gt;when&lt;/span&gt; regex.IsMatch(value) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; value&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; value &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; JsonException(&lt;span class=&quot;hljs-built_in&quot;&gt;sprintf&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Invalid characters in group: %s&amp;quot;&lt;/span&gt; value) &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;raise&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; _.Write(writer&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Utf8JsonWriter, value&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;, options&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; JsonSerializerOptions) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        value &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; writer.WriteStringValue&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;SnippetEntry&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    { Snippet&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;      Tooltip&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;JsonConverter(typeof&amp;lt;GroupJsonConverter&amp;gt;)&amp;gt;]&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)&amp;gt;]&lt;/span&gt;&lt;br /&gt;      Group&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt; }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;F# 的には group には &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/options&quot; title=&quot;&lt;code&gt;option&lt;/code&gt;&quot;&gt;&lt;code&gt;option&lt;/code&gt;&lt;/a&gt; を使うべきだろうけど、 .NET と直にやり取りしてるし変換コストを考えたらそのままがいいかなと。
F# 9 で &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/nullable-reference-types-in-fsharp-9/&quot; title=&quot;Nullable Reference Type&quot;&gt;Nullable Reference Type&lt;/a&gt; ができたことで、 &lt;code&gt;null&lt;/code&gt; を取り扱わないといけないケースも &lt;code&gt;option&lt;/code&gt; と遜色なく書けるようになった気がする。
代わりに到達不能な branch ができたり coverage 的には頭を悩ますことが多いが。&lt;/p&gt;
&lt;p&gt;group には &lt;code&gt;:snp&lt;/code&gt; や &lt;code&gt;:tip&lt;/code&gt; との一体感やタイプ回数を考えたら小文字英数 3 文字くらいの識別子が良かろうが、分かりやすさ的に英単語を使うのもありかな。
いま個人的には英単語の方を、個別の識別子考えて覚える必要ないから使ってる。&lt;/p&gt;
&lt;p&gt;いま &lt;code&gt;if&lt;/code&gt; 連発で愚直に書いただけのロジックになってるのをリファクタリングしたら、 v0.2.0 としてリリースしたい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 16 Mar 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-03-09-writing-cmdline-predictor-in-fsharp-pt3.html</guid><link>https://krymtkts.github.io/posts/2025-03-09-writing-cmdline-predictor-in-fsharp-pt3.html</link><title>F# で command-line predictor を書いてる Part 3 - Expecto</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;主に &lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; の開発をした。
2 ~ 3 月は公私ともに忙しくあまり進捗はないが、テスト周りを整備し始めた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2025-02-23-writing-cmdline-predictor-in-fsharp-pt2.html&quot; title=&quot;以前触れた&quot;&gt;以前触れた&lt;/a&gt;ように、 test framework には &lt;a href=&quot;https://github.com/haf/expecto&quot; title=&quot;Expecto&quot;&gt;Expecto&lt;/a&gt; をしてみた。
&lt;a href=&quot;/posts/2025-01-05-writing-cmdlet-in-fsharp-pt60.html&quot; title=&quot;年末年始に調べた&quot;&gt;年末年始に調べた&lt;/a&gt; &lt;a href=&quot;https://github.com/fsprojects/FsUnit&quot; title=&quot;FsUnit&quot;&gt;FsUnit&lt;/a&gt; と &lt;a href=&quot;https://github.com/fscheck/FsCheck&quot; title=&quot;FsCheck&quot;&gt;FsCheck&lt;/a&gt; を組み合わせた場合の &lt;a href=&quot;https://github.com/xunit/xunit&quot; title=&quot;xUnit&quot;&gt;xUnit&lt;/a&gt; version 固定のことを考えたら、より依存関係の少ない Expecto の方が制御可能だろうという見立て。&lt;/p&gt;
&lt;p&gt;少し前に、 Microsoft の blog で主要な test framework が &lt;a href=&quot;https://github.com/microsoft/testfx&quot; title=&quot;Microsoft.Testing.Platform&quot;&gt;Microsoft.Testing.Platform&lt;/a&gt; に対応したという記事が流れてたが、その中に Expecto も含まれてる。
因みに主要な、とあるようにこれは xUnit も v3 から対応してる。 FsCheck と共に使ってると v2 荷据え置きなので使えないけど。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/mtp-adoption-frameworks/&quot; title=&quot;Microsoft.Testing.Platform: Now Supported by All Major .NET Test Frameworks - .NET Blog&quot;&gt;Microsoft.Testing.Platform: Now Supported by All Major .NET Test Frameworks - .NET Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;わたしは hobby F# Ninja で .NET のテスト事情門外漢のため、この対応によって安定性だとか移植性だとかが向上しているようだが、具体的に何が変わったのかというのは説明が難しい。
たった 1 つ明確に言えることといえば、 Expecto も xUnit も test project の &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/entry-point#explicit-entry-point&quot; title=&quot;EntryPoint&quot;&gt;EntryPoint&lt;/a&gt; が不要になったところか。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Program&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;EntryPoint&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; main _ &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;従来は明示的に &lt;code&gt;[&amp;lt;EntryPoint&amp;gt;]&lt;/code&gt; を作っておかないとテスト実行できなかった。
pocof は今も xUnit を使っているので、 &lt;a href=&quot;https://github.com/krymtkts/pocof/blob/v0.18.1/src/pocof.Test/Program.fs&quot; title=&quot;/src/pocof.Test/Program.fs&quot;&gt;/src/pocof.Test/Program.fs&lt;/a&gt; がそうなってる。
こういうおまじないがなくなっただけでも、割と十分かなと思っている。&lt;/p&gt;
&lt;p&gt;Expecto を初めて使ってみた感触は、Expecto 基本的には関数でモリモリ書くような感じの使い心地。 repo にも書いてあったが使ってみた感じは framework というより library だ。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/attributes&quot; title=&quot;Attribute&quot;&gt;Attribute&lt;/a&gt; も少なく、今のところテスト対象を指定する &lt;code&gt;[&amp;lt;Tests&amp;gt;]&lt;/code&gt; しか使ってない。&lt;/p&gt;
&lt;p&gt;また &lt;code&gt;Expecto.Flip&lt;/code&gt; を使いさえすれば pipe operator で流れるように test code を書けるので、 FsUnit 同等に使えるなという感触だ。事前にこのことを把握してなかったら移行してないくらい重要なこと。
この &lt;code&gt;Expecto.Flip&lt;/code&gt; については FsUnit の Issue も触れられてる。 &lt;a href=&quot;https://github.com/fsprojects/FsUnit/issues/120#issuecomment-537664863&quot; title=&quot;FsUnit.Expecto · Issue #120 · fsprojects/FsUnit&quot;&gt;FsUnit.Expecto · Issue #120 · fsprojects/FsUnit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;いまは example-based test を Expecto で書いているが、 &lt;a href=&quot;https://github.com/haf/expecto?tab=readme-ov-file#property-based-tests&quot; title=&quot;Expecto は FsCheck との統合も自然な感じ&quot;&gt;Expecto は FsCheck との統合も自然な感じ&lt;/a&gt;なので、 PBT も早く試してみたいと考えている。
pocof でも少し PBT を書いているが未熟なので、初っ端から書くというのができてない状態だ。
まずは Expecto の練習に努める。&lt;/p&gt;
&lt;p&gt;Expecto 自体の話はここまで。
次は SnippetPredictor のテストのし難さについてメモしておく。&lt;/p&gt;
&lt;p&gt;まず snippet を保存する先がファイルなのもあって .NET の I/O 関連をよく使うのだけど、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/values/null-values#null-values-starting-with-f-9&quot; title=&quot;Nullable reference type&quot;&gt;Nullable reference type&lt;/a&gt; を有効にしてるので、 .NET 由来の library には頻繁に &lt;code&gt;null&lt;/code&gt; の取り扱いを示さないといけない。
これ自体は安全性のために良いのだけど、 SnippetPredictor で到達不能な pass に於いて発生するもんだから coverage に悪影響及ぼす。
仕方ないこととはいえ可能な限り経路をチェックしたいので頭を悩ますポイントだ。&lt;/p&gt;
&lt;p&gt;次にこれは一般論でもあるが I/O そのもののテストでの取り扱いも難しい。
0.1.0 は機能をリリースするために testability 考えず作ったので、 I/O 抜きでテストが難しい点がある。
pocof でも似たような課題があり、 unit test ではシンプルな currying ベースの injection を使って処理を差し替えることでテスト可能な範囲を広げたので、 SnippetPredictor でも I/O や環境変数へのアクセスで同様の方針で再構築を考えている。&lt;/p&gt;
&lt;p&gt;ただこれの良くない点は実際のコードの一部がテストを通さない点で、即ち coverage に悪影響する。
Pester でのテストで確認できるのであれば不要とも考えることができるが、やはり個人開発で 1 週間とかの比較的長い繰り返し周期で開発するのであれば、 coverage はガチガチにチェックしてた方が安心なのでなんとかしたい。どうせすぐ実装忘れるし。
今 I/O に関しては、環境変数で snippet のファイルを配置する directory を指定できる機能を設けてあるので、当面はそれで以てカバーするかも。&lt;/p&gt;
&lt;p&gt;ただ Expecto はデフォで並列・非同期に動くらしいから、それを考慮した実装になってないと上記の手段で実装したテストは flaky になるだろう。
なので SnippetPredictor 内部の snippet を保持する実装も module ベタに書くんじゃなくて同時実行性を考慮して改修する必要がある。&lt;/p&gt;
&lt;p&gt;追加したい機能の案も浮かんでおり、やることは沢山ありそうやけど、そのへんとテストとをいい塩梅に進めていく。
続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 09 Mar 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-03-02-writing-cmdlet-in-fsharp-pt65.html</guid><link>https://krymtkts.github.io/posts/2025-03-02-writing-cmdlet-in-fsharp-pt65.html</link><title>F# で Cmdlet を書いてる pt.65 - .NET SDK のエラーに引っかかった</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;多分次の release で解消されるであろう .NET SDK の issue を備忘のため記録しておく。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/329&quot; title=&quot;#329&quot;&gt;#329&lt;/a&gt; の過程で発見した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; の開発を始めて &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発は鈍化してるが、依存関係の更新は &lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates&quot; title=&quot;Dependabot version updates&quot;&gt;Dependabot version updates&lt;/a&gt; を使ってるのもあって、大体毎週何かしらの更新があるから追随している。
ただ &lt;a href=&quot;https://www.nuget.org/packages/FsUnit.xUnit/&quot; title=&quot;FsUnit.xUnit&quot;&gt;FsUnit.xUnit&lt;/a&gt; が v7 で &lt;a href=&quot;https://www.nuget.org/packages/xunit.v3/&quot; title=&quot;xunit.v3&quot;&gt;xunit.v3&lt;/a&gt; を使う様になり、 pocof で合わせて利用している &lt;a href=&quot;https://www.nuget.org/packages/FsCheck.Xunit/&quot; title=&quot;FsCheck.XUnit&quot;&gt;FsCheck.XUnit&lt;/a&gt; が未だ xUnit.v3 に対応してないため、更新は据え置きの状態になってる。
その結果 Dependabot の pull request をそのまま受け入れられない状態が続いたので、昨日そのへんの調整を施した。
ただ、その施しはうまくいってるはずなのだけど &lt;a href=&quot;https://docs.github.com/en/actions&quot; title=&quot;GitHub Actions&quot;&gt;GitHub Actions&lt;/a&gt; の macOS の job だけ絶対に成功しなくなった。&lt;/p&gt;
&lt;p&gt;こういうとき、 GitHub Actions の失敗した job の log の末尾だけを見がちなのだけど、それだけだと何が原因かわからなかった。
気を取り直して log 全体を見渡すと、先頭の方で他の platform と macOS で出力の違いを見つけた。&lt;/p&gt;
&lt;p&gt;Windows と Ubuntu ではこう ↓。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;psake version 4.9.1&lt;br /&gt;Copyright (c) 2010-2018 James Kovacs &amp;amp; Contributors&lt;br /&gt;&lt;br /&gt;Module: pocof ver0.19.0 root=/home/runner/work/pocof/pocof/src/pocof/ publish=/home/runner/work/pocof/pocof/publish/pocof/&lt;br /&gt;Executing Init&lt;br /&gt;Init is running!&lt;br /&gt;Tool &amp;#x27;dotnet-fsharplint&amp;#x27; (version &amp;#x27;0.21.2&amp;#x27;) was restored. Available commands: dotnet-fsharplint&lt;br /&gt;Tool &amp;#x27;fantomas&amp;#x27; (version &amp;#x27;7.0.1&amp;#x27;) was restored. Available commands: fantomas
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;macOS ではこう ↓。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;psake version 4.9.1&lt;br /&gt;Copyright (c) 2010-2018 James Kovacs &amp;amp; Contributors&lt;br /&gt;&lt;br /&gt;Module: pocof ver0.19.0 root=/Users/runner/work/pocof/pocof/src/pocof/ publish=/Users/runner/work/pocof/pocof/publish/pocof/&lt;br /&gt;Executing Init&lt;br /&gt;Init is running!&lt;br /&gt;&lt;br /&gt;Welcome to .NET 9.0!&lt;br /&gt;---------------------&lt;br /&gt;SDK Version: 9.0.200&lt;br /&gt;&lt;br /&gt;Telemetry&lt;br /&gt;---------&lt;br /&gt;The .NET tools collect usage data in order to help us improve your experience. It is collected by Microsoft and shared with the community. You can opt-out of telemetry by setting the DOTNET_CLI_TELEMETRY_OPTOUT environment variable to &amp;#x27;1&amp;#x27; or &amp;#x27;true&amp;#x27; using your favorite shell.&lt;br /&gt;&lt;br /&gt;Read more about .NET CLI Tools telemetry: https://aka.ms/dotnet-cli-telemetry&lt;br /&gt;&lt;br /&gt;----------------&lt;br /&gt;Installed an ASP.NET Core HTTPS development certificate.&lt;br /&gt;To trust the certificate, run &amp;#x27;dotnet dev-certs https --trust&amp;#x27;&lt;br /&gt;Learn about HTTPS: https://aka.ms/dotnet-https&lt;br /&gt;&lt;br /&gt;----------------&lt;br /&gt;Write your first app: https://aka.ms/dotnet-hello-world&lt;br /&gt;Find out what&amp;#x27;s new: https://aka.ms/dotnet-whats-new&lt;br /&gt;Explore documentation: https://aka.ms/dotnet-docs&lt;br /&gt;Report issues and find source on GitHub: https://github.com/dotnet/core&lt;br /&gt;Use &amp;#x27;dotnet --help&amp;#x27; to see available commands or visit: https://aka.ms/dotnet-cli&lt;br /&gt;--------------------------------------------------------------------------------------&lt;br /&gt;Failed to validate package signing.&lt;br /&gt;&lt;br /&gt;Verifying dotnet-fsharplint.0.21.2&lt;br /&gt;&lt;br /&gt;Signature type: Repository&lt;br /&gt;  Subject Name: CN=NuGet.org Repository by Microsoft, O=NuGet.org Repository by Microsoft, L=Redmond, S=Washington, C=US&lt;br /&gt;  SHA256 hash: 5A2901D6ADA3D18260B9C6DFE2133C95D74B9EEF6AE0E5DC334C8454D1477DF4&lt;br /&gt;  Valid from: 2/16/2021 12:00:00 AM to 5/15/2024 11:59:59 PM&lt;br /&gt;&lt;br /&gt;warn : NU3018: The repository primary signature found a chain building issue: RevocationStatusUnknown: An incomplete certificate revocation check occurred.&lt;br /&gt;error: NU3037: The repository primary signature validity period has expired.&lt;br /&gt;error: NU3028: The repository primary signature&amp;#x27;s timestamp found a chain building issue: ExplicitDistrust: The trust setting for this policy was set to Deny.&lt;br /&gt;&lt;br /&gt;Package signature validation failed.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;まず Windows &amp;amp; Ubuntu と macOS では dotnet CLI の version が 9.0.101 と 9.0.200 で違ってる。
ただし当時の &lt;code&gt;global.json&lt;/code&gt; が以下なので、この dotnet CLI の version の差異は想定内。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;sdk&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;rollForward&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;latestMinor&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;9.0.101&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;次に macOS では &lt;code&gt;NU3018&lt;/code&gt; &lt;code&gt;NU3037&lt;/code&gt; &lt;code&gt;NU3028&lt;/code&gt; が発生しているのがわかるので、こいつで調べると以下にたどり着いた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dotnet/sdk/issues/46857&quot; title=&quot;dotnet tool restore started failing on macOS with NU3037 and NU3028 errors after 11th February · Issue #46857 · dotnet/sdk&quot;&gt;dotnet tool restore started failing on macOS with NU3037 and NU3028 errors after 11th February · Issue #46857 · dotnet/sdk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dotnet/sdk/issues/46857#issuecomment-2683545963&quot; title=&quot;これ&quot;&gt;これ&lt;/a&gt; と &lt;a href=&quot;https://github.com/dotnet/sdk/issues/46857#issuecomment-2683556715&quot; title=&quot;これ&quot;&gt;これ&lt;/a&gt; を見ればわかるが、 macOS では NuGet package の署名検証がコケるから default で無効らしい。
公式の文書は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/tools/nuget-signed-package-verification#macos&quot; title=&quot;NuGet signed-package verification - .NET CLI | Microsoft Learn&quot;&gt;NuGet signed-package verification - .NET CLI | Microsoft Learn&lt;/a&gt; か。&lt;/p&gt;
&lt;p&gt;でも 9.0.200 でデフォルト有効になってしまう変更があったらしい。これは &lt;a href=&quot;https://github.com/dotnet/sdk/issues/46857#issuecomment-2683555678&quot; title=&quot;&lt;code&gt;DOTNET_NUGET_SIGNATURE_VERIFICATION = false&lt;/code&gt; でも回避できない&quot;&gt;&lt;code&gt;DOTNET_NUGET_SIGNATURE_VERIFICATION = false&lt;/code&gt; でも回避できない&lt;/a&gt;とか。
issue の Milestone は 9.0.3xx なのですぐには直って落ちてこないかな。&lt;/p&gt;
&lt;p&gt;まとめると、 9.0.3xx で直す予定みたいだが、現状の 9.0.200 だと回避できない。
つまり workaround として有効な方法は、 &lt;code&gt;9.0.103&lt;/code&gt; に固定することのみと思われるので、今回はそのようにして回避した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;TODO:&lt;/span&gt; pin sdk version to 9.0.103 to prevent `dotnet tool restore` failure on MacOS due to `NU3018`, `NU3037` and `NU3028`.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;sdk&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;rollForward&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;disable&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;9.0.103&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こういうトラシューは AI さんにも未だ解けないっぽいので当てにならん。
AI さんにこれをとかそうとしたらどこをどう調べるべきかをレクチュアせねばならず、自分でやるのより面倒だった。&lt;/p&gt;
&lt;p&gt;とりあえず、その場しのぎだが CI を動かせるように直せた。
調べてみて、現象の報告から 2 週間程度仕方ってないというのもあるかも知れないが、大して知られてない？ような感じ。
これは macOS で dotnet 使う人がめちゃくちゃ少ないってことなのでは...&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;因みに、この過程で &lt;code&gt;global.json&lt;/code&gt; に comment を書けることを初めて知った。要は JSON with Comments 。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/tools/global-json#comments-in-globaljson&quot; title=&quot;global.json overview - .NET CLI | Microsoft Learn&quot;&gt;global.json overview - .NET CLI | Microsoft Learn&lt;/a&gt;
多分時代の流れで &lt;code&gt;System.Text.Json&lt;/code&gt; を使ってるので deserialize のときは comment が skip されてる。
なので serialize するのは()&lt;code&gt;dotnet new globaljson&lt;/code&gt; のときくらいしかないと思うが)消えるだろう。&lt;/p&gt;
&lt;p&gt;tool manifest &lt;code&gt;dotnet-tools.json&lt;/code&gt; でも同様かと思ったが、こちらはこちらで理由があって対応してないみたい。
JSON はコメントの振る舞いに関して定義がないからやらないって感じか。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/sdk/issues/10384&quot; title=&quot;Enable comments for tool manifest json · Issue #10384 · dotnet/sdk&quot;&gt;Enable comments for tool manifest json · Issue #10384 · dotnet/sdk&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/runtime/issues/30316&quot; title=&quot;Support of comments in jsondocument · Issue #30316 · dotnet/runtime&quot;&gt;Support of comments in jsondocument · Issue #30316 · dotnet/runtime&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/sdk/issues/16043&quot; title=&quot;[Feature Request] Support jsonc for dotnet tools manifest · Issue #16043 · dotnet/sdk&quot;&gt;[Feature Request] Support jsonc for dotnet tools manifest · Issue #16043 · dotnet/sdk&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;</description><pubDate>Sun, 02 Mar 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-02-23-writing-cmdline-predictor-in-fsharp-pt2.html</guid><link>https://krymtkts.github.io/posts/2025-02-23-writing-cmdline-predictor-in-fsharp-pt2.html</link><title>F# で command-line predictor を書いてる Part 2 - SnippetPredictor 公開</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://krymtkts.github.io/posts/2024-11-10-writing-cmdline-predictor-in-fsharp-pt1.html&quot; title=&quot;前&quot;&gt;前&lt;/a&gt;は sample を作っただけだが、最近 F# で command-line predictor を書くのを本格化した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/SnippetPredictor&quot; title=&quot;krymtkts/SnippetPredictor&quot;&gt;krymtkts/SnippetPredictor&lt;/a&gt; という。
まだ prerelease だが PowerShell Gallery に &lt;a href=&quot;https://www.powershellgallery.com/packages/SnippetPredictor&quot; title=&quot;SnippetPredictor&quot;&gt;SnippetPredictor&lt;/a&gt; で公開してある。
事前に用意しておいた snippet を入力内容に応じて suggestion に表示するという単純な command-line predictor だ。
snippet を表示・追加・削除するための Cmdlet も一緒のバイナリで提供している。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2025-02-23-capture/snippet-predictor.gif&quot; title=&quot;SnippetPredictor のキャプチャ&quot; alt=&quot;SnippetPredictor のキャプチャ&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;因みに PowerShell の command-line predictor は &lt;a href=&quot;https://github.com/PowerShell/PowerShell&quot; title=&quot;PowerShell&quot;&gt;PowerShell&lt;/a&gt; 7.2 ＆ &lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; 2.2.2 以降に導入された plugin 機能の 1 つだ。以下の Microsoft の記事が詳しい(当たり前だが)。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-cmdline-predictor?view=powershell-7.4&quot; title=&quot;How to create a command-line predictor - PowerShell | Microsoft Learn&quot;&gt;How to create a command-line predictor - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PSReadLine の experimental feature の &lt;code&gt;PSSubsystemPluginModel&lt;/code&gt; を手動で有効化すると使えるようになる。
また PSReadLine の option で &lt;code&gt;PredictionSource=HistoryAndPlugin&lt;/code&gt; &lt;code&gt;PredictionViewStyle=ListView&lt;/code&gt; の設定をする必要がある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/learn/experimental-features?view=powershell-7.5#pssubsystempluginmodel&quot; title=&quot;PSSubsystemPluginModel Using Experimental Features in PowerShell - PowerShell | Microsoft Learn&quot;&gt;PSSubsystemPluginModel Using Experimental Features in PowerShell - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;前にも触れたが command-line predictor の作り方は先に挙げた &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-cmdline-predictor?view=powershell-7.4&quot; title=&quot;How to create a command-line predictor - PowerShell | Microsoft Learn&quot;&gt;How to create a command-line predictor - PowerShell | Microsoft Learn&lt;/a&gt; を参照している。&lt;/p&gt;
&lt;p&gt;多分このドキュメントと PowerShell team 謹製の &lt;a href=&quot;https://github.com/PowerShell/CompletionPredictor&quot; title=&quot;PowerShell/CompletionPredictor&quot;&gt;PowerShell/CompletionPredictor&lt;/a&gt; とか、個人が作ってるようなのしか参考がないのが現状だろう。
今回作ったやつが「個人が作ってるようなの」に仲間入りすることになれば最高やな。&lt;/p&gt;
&lt;p&gt;今のところ command-line predictor の一部の機能しか使ってないので、大して困ったことは発生していない。
ただいくつか気になる・工夫すべき点があるのは事実で、いかにそのいくつかを記す。&lt;/p&gt;
&lt;p&gt;まず、実装して使ってみないと気付けなかった点として、 &lt;code&gt;Name&lt;/code&gt; 属性の指定がある。
&lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.management.automation.subsystem.icommandpredictor?view=powershellsdk-7.2.0&quot; title=&quot;&lt;code&gt;ICommandPredictor&lt;/code&gt;&quot;&gt;&lt;code&gt;ICommandPredictor&lt;/code&gt;&lt;/a&gt; 実装 class に &lt;code&gt;Name&lt;/code&gt; 属性で subsystem 実装の名前を定義するのだけど、これが suggestion 右端に &lt;code&gt;[subsystem name]&lt;/code&gt; という感じで表示される。
なので多少長い名前をつけているだけで幅の制限に引っかかって省略表記になってしまう。
実際 &lt;code&gt;SnippetPredictor&lt;/code&gt; だと長過ぎて省略されてしまったので &lt;code&gt;Snippet&lt;/code&gt; に短縮した。
PowerShell が流行ることはないと思うが、万が一 subsystem が沢山増えた場合、名前の奪い合いみたいになってしまうであろうこと必至。&lt;/p&gt;
&lt;p&gt;そして command-line predictor の実装の制約として、① suggestion を 1 行を収める必要があるのと、② 20ms 以内に表示する必要がある。これらは先述の作り方の記事にも書いてある。&lt;/p&gt;
&lt;p&gt;① に違反すると PSReadLine が suggestion の ListView 用に確保しているスペースの再描画が崩れる。早い話が suggestion が消費する行の高さまで PSReadLine が計算してないためそうなってる。今のところはそれだけっぽいので気合で使おうと思えばどうにかなるが、見た目にもきれいじゃなく見にくくなるだけなので、やらないのが無難だろう。これが原因でエラーになるとかではないので、比較的ゆるい制約と言える。
② に違反すると、 suggestion 荷表示されない。これは command-line predictor として役に立たないので非常に気に掛ける必要がある。&lt;/p&gt;
&lt;p&gt;SnippetPredictor の場合、 snippet は JSON ファイルに保持している&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;ので、読み込みに時間がかかるようなことを避けるべく SnippetPredictor の import 後にファイルの snippet をメモリ上に読み込んで suggestion の絞り込みに利用している。
また、ファイルの変更を監視して変更があったら比較的リアルタイムに反映できるようにした。
① に関しては今のところ機能的に制限していないので、 JSON ファイルに改行文字 &lt;code&gt;\n&lt;/code&gt; が含まれたらダメな感じ。なので登録時か出力時に &lt;code&gt;\n&lt;/code&gt; を読み替える必要があるかも。検討中だ。&lt;/p&gt;
&lt;p&gt;最後に PowerShell で対話型のインタフェースを作ったときに困るのがエラーの表示だ。 &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; でも散々苦労したが、 command-line predictor も例に漏れず、専用のエラー表示 UI は持ってなさそうだ。
現状 command-line predictor 自体は suggestion でユーザと対話するしかないので、仮にエラーがあればそこに表示するようにした。
SnippetPredictor の場合は snippet を出せない理由、例えば JSON ファイルのフォーマットが壊れてるとかが表示されることになる。&lt;/p&gt;
&lt;p&gt;とりあえず PowerShell module として必要な最低限の要素(機能と help くらい)をざーっと作ったのみなので発見してない bug などあろうが、今のところ気に入っている。
テストを全然書いてなかったり、開発を継続するのを楽にする CI とか作ってないので、今後充実していけたら良いなと思う。&lt;/p&gt;
&lt;p&gt;他にも pocof で変えたいと思っている点も、 SnippetPredictor のようなまだ出来上がってない project だと導入しやすい。
pocof ではちょうど &lt;a href=&quot;https://github.com/xunit/xunit&quot; title=&quot;xUnit&quot;&gt;xUnit&lt;/a&gt; をやめて &lt;a href=&quot;https://github.com/haf/expecto&quot; title=&quot;expecto&quot;&gt;expecto&lt;/a&gt; に移行したい気持ちがあるので、 SnippetPredictor では先行して expecto をセットアップしてみたい。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;.NET で依存関係なしで楽に実装できてユーザも比較的楽に編集できるのがこれくらいしかなかった。より良い方法は模索中。 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 23 Feb 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-02-16-from-chocolatey-to-winget-openssh-2025.html</guid><link>https://krymtkts.github.io/posts/2025-02-16-from-chocolatey-to-winget-openssh-2025.html</link><title>Chocolatey の OpenSSH をやめて WinGet の OpenSSH にする 2025</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;最近の活動は、 pocof の benchmark に基づいた細かい改善とか、 Command-line predictor を作り始めたのとか。
でも今日は最早わたしの中で恒例となった &lt;a href=&quot;https://github.com/chocolatey/choco&quot; title=&quot;Chocolatey&quot;&gt;Chocolatey&lt;/a&gt; での OpenSSH 話を記す。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;随分長い間気づいてなかったのだけど OpenSSH の Chocolatey の 最新 prerelease 壊れとるね。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gitlab.com/DarwinJS/ChocoPackages/-/issues/105&quot; title=&quot;openssh 9.5.0-beta20240403 seems to contain OpenSSH_for_Windows_8.6p1, (#105) · Issues · DarwinJS / ChocoPackages · GitLab&quot;&gt;openssh 9.5.0-beta20240403 seems to contain OpenSSH_for_Windows_8.6p1, (#105) · Issues · DarwinJS / ChocoPackages · GitLab&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;気づかず使ってた。
repo 見ても最新は上記のママだし、変なバイナリ使ってたんかと思ってゾッとしたわ...
一応以下のコマンドで 1 つ前の正しいやつに戻せる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;choco install openssh &lt;span class=&quot;hljs-literal&quot;&gt;--version&lt;/span&gt;=&lt;span class=&quot;hljs-number&quot;&gt;9.5&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-beta1&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-params&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;quot;/SSHAgentFeature&amp;quot;&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-pre&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--force&lt;/span&gt;&lt;br /&gt;choco pin add &lt;span class=&quot;hljs-literal&quot;&gt;--name&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;openssh&amp;#x27;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;念の為 9.5.0-beta1 に固定したけどこれからどうしよかね。
Windows 11 の標準の SSH が更新によって 9.5.2.1 になってる&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;ので、 Chocolatey のやつを使う意味がないという。&lt;/p&gt;
&lt;p&gt;Windows の OpenSSH の install に Universal Installer を使うのはもう長らく deprecated で、ただ chocolatey で管理するの楽なので依存し続けてた。
&lt;a href=&quot;https://github.com/PowerShell/Win32-OpenSSH/wiki/%5BDeprecated%5D-Win32-OpenSSH-Automated-Install-and-Upgrade-using-Chocolatey&quot; title=&quot;[Deprecated] Win32 OpenSSH Automated Install and Upgrade using Chocolatey · PowerShell/Win32-OpenSSH Wiki&quot;&gt;[Deprecated] Win32 OpenSSH Automated Install and Upgrade using Chocolatey · PowerShell/Win32-OpenSSH Wiki&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今の公式な install 手段としては &lt;a href=&quot;https://github.com/PowerShell/Win32-OpenSSH/wiki/Install-Win32-OpenSSH-Using-MSI&quot; title=&quot;MSI 直&quot;&gt;MSI 直&lt;/a&gt;か &lt;a href=&quot;https://github.com/PowerShell/Win32-OpenSSH/wiki/Install-Win32-OpenSSH&quot; title=&quot;WinGet&quot;&gt;WinGet&lt;/a&gt; な感じはする。
この手段でなら最新の beta も取れるし。
&lt;a href=&quot;https://github.com/microsoft/winget-cli&quot; title=&quot;WinGet&quot;&gt;WinGet&lt;/a&gt; にはまだあんま踏み込んでないけど、この機会に始めるべきかな～ そんで &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/dsc/overview?view=dsc-3.0&quot; title=&quot;DSC&quot;&gt;DSC&lt;/a&gt; も嗜む？みたいな。&lt;/p&gt;
&lt;p&gt;何度か WinGet への移行は考えてたけど、ビミョーに痒いところに手が届かないのよな。 &lt;a href=&quot;https://maven.apache.org/&quot; title=&quot;Maven&quot;&gt;Maven&lt;/a&gt; がないとか(&lt;code&gt;mvn&lt;/code&gt; はもう殆ど使わないのだけど &lt;a href=&quot;https://github.com/krymtkts/MavenAutoCompletion&quot; title=&quot;krymtkts/MavenAutoCompletion&quot;&gt;krymtkts/MavenAutoCompletion&lt;/a&gt; がある関係で一応必要)。
Maven がないのは &lt;a href=&quot;https://github.com/microsoft/winget-pkgs/labels/Scripted-Application&quot; title=&quot;&lt;code&gt;Scripted-Application&lt;/code&gt;&quot;&gt;&lt;code&gt;Scripted-Application&lt;/code&gt;&lt;/a&gt; って label が付いてる &lt;code&gt;*.bat&lt;/code&gt; とか &lt;code&gt;*.cmd&lt;/code&gt; とかの script として提供されてる application の install を WinGet の security policy で禁じてるからなので...どうしようもない。&lt;/p&gt;
&lt;p&gt;でもずっと許可しないとか有り得んよな～と思って調べたら、やっぱ issue に挙がってきてた(それにしては随分最近でびっくりした)。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/microsoft/winget-cli/issues/5083&quot; title=&quot;Support other portable application formats · Issue #5083 · microsoft/winget-cli&quot;&gt;Support other portable application formats · Issue #5083 · microsoft/winget-cli&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;というわけで WinGet の今後に期待し、とりあえず新しいのを使いたいから一旦 OpenSSH だけ winget に移行した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;winget install &lt;span class=&quot;hljs-literal&quot;&gt;--id&lt;/span&gt; Microsoft.OpenSSH.Preview &lt;span class=&quot;hljs-literal&quot;&gt;--scope&lt;/span&gt; machine &lt;span class=&quot;hljs-literal&quot;&gt;--override&lt;/span&gt; ADDLOCAL=Client
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Chocolatey から WinGet へのスムースな移行とかもできるかわからんので当面は二刀流か。
続く。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;多分これか → &lt;a href=&quot;https://jpwinsup.github.io/blog/2024/11/12/OpenSSH/OpenSSH_update_oct_2024/&quot; title=&quot;OpenSSH for Windows の 2024 年 10 月の更新について | Microsoft Japan Windows Technology Support Blog&quot;&gt;OpenSSH for Windows の 2024 年 10 月の更新について | Microsoft Japan Windows Technology Support Blog&lt;/a&gt; &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 16 Feb 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-02-09-github-notification-tips.html</guid><link>https://krymtkts.github.io/posts/2025-02-09-github-notification-tips.html</link><title>GitHub 通知設定の Tips</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;わざわざ書き残すようなものでもないかと思ったが、全然知らなかったので残しておく。&lt;/p&gt;
&lt;p&gt;GitHub の repo の Watch とか、 Issue や Pull Request の subscription の設定。
アレをいちいちいつどこで何の理由で設定したとか覚えてなくて、たまに何ぞ？と思うような通知が来ることがある。&lt;/p&gt;
&lt;p&gt;一括管理できないのかなと ChatGPT に聞いたところ、なんと &lt;a href=&quot;https://github.com/watching&quot; title=&quot;undefined&quot;&gt;https://github.com/watching&lt;/a&gt; と &lt;a href=&quot;https://github.com/notifications/subscriptions&quot; title=&quot;undefined&quot;&gt;https://github.com/notifications/subscriptions&lt;/a&gt; で見れるらしい。
初めて知った...
これどこから辿れるんやと思って Notifications 画面を見てみたら、左下に確かにあった...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications&quot; title=&quot;Configuring notifications - GitHub Docs&quot;&gt;Configuring notifications - GitHub Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;公式文書にも思いっきり書いてあった...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/25438721/how-can-i-see-all-the-issues-im-watching-on-github&quot; title=&quot;How can I see all the issues I&amp;#39;m watching on Github? - Stack Overflow&quot;&gt;How can I see all the issues I&amp;#39;m watching on Github? - Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;みんな結構知らないんやな。
とても便利な機能でありがたい。&lt;/p&gt;
&lt;p&gt;手動で Issue とか Pull Request の subscription をしたやつを一覧するには、 Reason を Manual で絞れば良いっぽい。
&lt;a href=&quot;https://github.com/notifications/subscriptions?reason=manual&quot; title=&quot;undefined&quot;&gt;https://github.com/notifications/subscriptions?reason=manual&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;watch している repo 一覧は &lt;a href=&quot;https://cli.github.com/&quot; title=&quot;Github CLI&quot;&gt;Github CLI&lt;/a&gt; でも取れるっぽい。
&lt;a href=&quot;https://github.com/microsoft/PowerShellForGitHub&quot; title=&quot;PowerShellForGitHub&quot;&gt;PowerShellForGitHub&lt;/a&gt; にはなさそう？&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;gh api user/subscriptions &lt;span class=&quot;hljs-literal&quot;&gt;--paginate&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--jq&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;.[].full_name&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# fsprojects/fantomas&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# fscheck/FsCheck&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# fsprojects/FSharpLint&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PowerShell/platyPS&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PowerShell/PowerShell-RFC&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最近自分で使ってる F# とか PowerShell の repo の activity が全部飛ぶように watch 設定してるから、今何が watch になってるか一覧できるのはとても助かる。&lt;/p&gt;
&lt;p&gt;Issue や Pull Request のうち手動で subscribe したものは CLI でどうすれば一覧できるかわからなかった。
subscribe してる Issue や Pull Request は、大体何らかの bug を踏んだり気になる機能追加を追いたい場合に使ってるので、こっちも一覧したかったが...
一覧したところで何に使うねんというのはあるけどな。対応が終わった Issue や Pull Request から通知が飛ぶことはないから棚卸しして購読を外すなんてこともやらなくていいし。
まあでも振り返ってみるときに一覧したいかも...&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 09 Feb 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-02-02-writing-cmdlet-in-fsharp-pt64.html</guid><link>https://krymtkts.github.io/posts/2025-02-02-writing-cmdlet-in-fsharp-pt64.html</link><title>F# で Cmdlet を書いてる pt.64 - UnixStats がエラーになる</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;昨日 &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.19.0&quot; title=&quot;0.19.0&quot;&gt;0.19.0&lt;/a&gt; をリリースをした。
1 月中にリリースしたかったが、 Linux で予期せぬエラーが発生する修正をしてしまってたので、リリースが遅れた。&lt;/p&gt;
&lt;p&gt;ずっと気づいてなかったが、 Linux 端末上で例えば &lt;code&gt;UnixStats&lt;/code&gt;&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; のような platform 依存の property にアクセスすると以下のエラーが発生する。
以下の例では &lt;code&gt;Size&lt;/code&gt; だが &lt;code&gt;User&lt;/code&gt; とか &lt;code&gt;Mode&lt;/code&gt; とか &lt;code&gt;UnixStats&lt;/code&gt; に属するもの全てエラーになる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;PS /mnt/c/Users/takatoshi&amp;gt; $ErrorView = &amp;#x27;DetailedView&amp;#x27;&lt;br /&gt;PS /mnt/c/Users/takatoshi&amp;gt; get-ChildItem | pocof -Layout TopDownHalf &amp;#x27;:Size 1&amp;#x27;&lt;br /&gt;query&amp;gt;:Size 1                                                                                                                                                                                                                                                  match and [0]&lt;br /&gt;Exception             :&lt;br /&gt;    Type            : System.AggregateException&lt;br /&gt;    InnerExceptions :&lt;br /&gt;        Type           : System.Management.Automation.GetValueInvocationException&lt;br /&gt;        ErrorRecord    :&lt;br /&gt;            Exception             :&lt;br /&gt;                Type    : System.Management.Automation.ParentContainsErrorRecordException&lt;br /&gt;                Message : Exception getting &amp;quot;Size&amp;quot;: &amp;quot;There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: $this.UnixStat.Size&amp;quot;&lt;br /&gt;                HResult : -2146233087&lt;br /&gt;            CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException&lt;br /&gt;            FullyQualifiedErrorId : ScriptgetValueInvalidOperationException&lt;br /&gt;        TargetSite     :&lt;br /&gt;            Name          : InvokeGetter&lt;br /&gt;            DeclaringType : psscriptproperty&lt;br /&gt;            MemberType    : Method&lt;br /&gt;            Module        : System.Management.Automation.dll&lt;br /&gt;        Message        : Exception getting &amp;quot;Size&amp;quot;: &amp;quot;There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: $this.UnixStat.Size&amp;quot;&lt;br /&gt;        InnerException :&lt;br /&gt;            Type        : System.Management.Automation.PSInvalidOperationException&lt;br /&gt;            ErrorRecord :&lt;br /&gt;                Exception             :&lt;br /&gt;                    Type    : System.Management.Automation.ParentContainsErrorRecordException&lt;br /&gt;                    Message : There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: $this.UnixStat.Size&lt;br /&gt;                    HResult : -2146233087&lt;br /&gt;                CategoryInfo          : InvalidOperation: (:) [], ParentContainsErrorRecordException&lt;br /&gt;                FullyQualifiedErrorId : ScriptBlockDelegateInvokedFromWrongThread&lt;br /&gt;            TargetSite  :&lt;br /&gt;                Name          : GetContextFromTLS&lt;br /&gt;                DeclaringType : scriptblock&lt;br /&gt;                MemberType    : Method&lt;br /&gt;                Module        : System.Management.Automation.dll&lt;br /&gt;            Message     : There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: $this.UnixStat.Size&lt;br /&gt;            Source      : System.Management.Automation&lt;br /&gt;            HResult     : -2146233079&lt;br /&gt;            StackTrace  :&lt;br /&gt;   at System.Management.Automation.ScriptBlock.GetContextFromTLS()&lt;br /&gt;   at System.Management.Automation.ScriptBlock.InvokeWithPipe(Boolean useLocalScope, ErrorHandlingBehavior errorHandlingBehavior, Object dollarUnder, Object input, Object scriptThis, Pipe outputPipe, InvocationInfo invocationInfo, Boolean propagateAllExceptionsToTop, List`1 variablesToDefine, Dictionary`2 functionsToDefine, Object[] args)&lt;br /&gt;   at System.Management.Automation.PSScriptProperty.InvokeGetter(Object scriptThis)&lt;br /&gt;        Source         : System.Management.Automation&lt;br /&gt;        HResult        : -2146233087&lt;br /&gt;        StackTrace     :&lt;br /&gt;   at System.Management.Automation.PSScriptProperty.InvokeGetter(Object scriptThis)&lt;br /&gt;   at Pocof.Query.x@162.Invoke(Entry entry)&lt;br /&gt;   at lambda_method453(Closure, Entry)&lt;br /&gt;   at System.Linq.Parallel.OrderPreservingPipeliningSpoolingTask`2.SpoolingWork()&lt;br /&gt;   at System.Linq.Parallel.SpoolingTaskBase.Work()&lt;br /&gt;   at System.Linq.Parallel.QueryTask.BaseWork(Object unused)&lt;br /&gt;   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)&lt;br /&gt;...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;RunSpace&lt;/code&gt; 割あたってると思ってたけどなんか違うらしい。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.commandinvocationintrinsics.invokescript?view=powershellsdk-7.4.0#system-management-automation-commandinvocationintrinsics-invokescript(system-management-automation-sessionstate-system-management-automation-scriptblock-system-object())&quot; title=&quot;&lt;code&gt;PSCmdlet.InvokeCommand.InvokeScript&lt;/code&gt;&quot;&gt;&lt;code&gt;PSCmdlet.InvokeCommand.InvokeScript&lt;/code&gt;&lt;/a&gt; を main thread で実行してるだけなので、変なことなさそうなんやが。&lt;/p&gt;
&lt;p&gt;実は &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.18.1&quot; title=&quot;0.18.1&quot;&gt;0.18.1&lt;/a&gt; 以前からのエラーは出てて、単に &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/exception-handling/the-try-with-expression&quot; title=&quot;&lt;code&gt;try ... with ...&lt;/code&gt;&quot;&gt;&lt;code&gt;try ... with ...&lt;/code&gt;&lt;/a&gt; でエラーを捕捉した場合に property の値が取れなかったとして &lt;code&gt;None&lt;/code&gt; を返す仕様にしてたので気づいてないだけだった。
このエラー措置は元々 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.nullreferenceexception?view=net-9.0&quot; title=&quot;&lt;code&gt;NullReferenceException&lt;/code&gt;&quot;&gt;&lt;code&gt;NullReferenceException&lt;/code&gt;&lt;/a&gt; 用に作ってた気がしたけど、結果的に他のエラーも救ってたことになる。
0.19.0 に含まれる修正で &lt;code&gt;NullReferenceException&lt;/code&gt; の恐れがないとみなしこのエラー救護措置を取り除いたところ、ひょっこり現れたという形だ。&lt;/p&gt;
&lt;p&gt;ひとまず従来の挙動とリリース優先を優先して &lt;code&gt;try ... with ...&lt;/code&gt; でエラーを潰しただけなので、できればちゃんと対応したいところ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/319&quot; title=&quot;Resolve errors when accessing Unix-dependent properties such as &lt;code&gt;User&lt;/code&gt;, &lt;code&gt;Group&lt;/code&gt;, &lt;code&gt;UnixMode&lt;/code&gt;, &lt;code&gt;Size&lt;/code&gt;, etc. · Issue #319 · krymtkts/pocof&quot;&gt;Resolve errors when accessing Unix-dependent properties such as &lt;code&gt;User&lt;/code&gt;, &lt;code&gt;Group&lt;/code&gt;, &lt;code&gt;UnixMode&lt;/code&gt;, &lt;code&gt;Size&lt;/code&gt;, etc. · Issue #319 · krymtkts/pocof&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;あとの修正は、依存関係を更新したり、 benchmark とって改善したりだけだ。
改善といっても大きくロジックを書き換えたのはなくて不要な list 変換を避けるとかそういうちまちましたものばかり。
この過程で &lt;a href=&quot;https://github.com/icsharpcode/ILSpy&quot; title=&quot;ILSpy&quot;&gt;ILSpy&lt;/a&gt; で面白いことに気付いたので書き残しておく。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;もし速さを追求して IL の命令数まで意識する必要がある場合、 F# っぽい書き方は C# っぽい書き方より overhead があって使いにくいかも知れないという話。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; dotnet &lt;span class=&quot;hljs-literal&quot;&gt;--version&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;9.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;102&lt;/span&gt;&lt;br /&gt;&amp;gt; dotnet fsi &lt;span class=&quot;hljs-literal&quot;&gt;--version&lt;/span&gt;&lt;br /&gt;Microsoft (&lt;span class=&quot;hljs-built_in&quot;&gt;R&lt;/span&gt;) F&lt;span class=&quot;hljs-comment&quot;&gt;# Interactive version 12.9.101.0 for F# 9.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;でビルドして、 ILSpy で C# 12 と一部 IL で見た。
また pocof の &lt;code&gt;TargetFramework&lt;/code&gt; は &lt;code&gt;netstandard2.0&lt;/code&gt; だ。
F# が吐く IL は version up で改善が続いてるし、この見解は今だけの話かもしれないことに留意すること。&lt;/p&gt;
&lt;p&gt;こういうコードがあるとして、 &lt;code&gt;toString __ |&amp;gt; String.lower&lt;/code&gt; の部分の書き方で生成される IL の違いを見た。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;RequireQualifiedAccess&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;NoComparison&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Struct&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Matcher&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Eq&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Like&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Match&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.ToString() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;  toString __ &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; String.lower
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// toString __ |&amp;gt; String.lower&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ToString&lt;/span&gt;()&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; s = toString(&lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;);&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; LanguageExtension.String.lower(s);&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// _.Property shorthand&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ToString&lt;/span&gt;()&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; text = toString(&lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;);&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; text2 = text;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; text2.ToLower();&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;.method public hidebysig virtual&lt;br /&gt;    instance string ToString () cil managed&lt;br /&gt;{&lt;br /&gt;    .param [0]&lt;br /&gt;        .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (&lt;br /&gt;            01 00 00 00 00&lt;br /&gt;        )&lt;br /&gt;    // Method begins at RVA 0x9238&lt;br /&gt;    // Header size: 12&lt;br /&gt;    // Code size: 21 (0x15)&lt;br /&gt;    .maxstack 3&lt;br /&gt;    .locals init (&lt;br /&gt;        [0] string &amp;#x27;Pipe #1 input at line 235&amp;#x27;,&lt;br /&gt;        [1] string&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;    IL_0000: ldarg.0&lt;br /&gt;    IL_0001: ldobj Pocof.Data/Matcher&lt;br /&gt;    IL_0006: call string Pocof.Data::toString&amp;lt;valuetype Pocof.Data/Matcher&amp;gt;(!!0)&lt;br /&gt;    IL_000b: stloc.0&lt;br /&gt;    IL_000c: ldloc.0&lt;br /&gt;    IL_000d: stloc.1&lt;br /&gt;    IL_000e: ldloc.1&lt;br /&gt;    IL_000f: callvirt instance string [netstandard]System.String::ToLower()&lt;br /&gt;    IL_0014: ret&lt;br /&gt;} // end of method Matcher::ToString
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;inline expansion と _.Property shorthand は同じ IL になる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// inline&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ToString&lt;/span&gt;()&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; text = toString(&lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;);&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; text2 = text;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; text2.ToLower();&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;C# ライクに書くのが最も命令数が少ない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// (toString __).ToLower()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ToString&lt;/span&gt;()&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; toString(&lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;).ToLower();&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;.method public hidebysig virtual&lt;br /&gt;    instance string ToString () cil managed&lt;br /&gt;{&lt;br /&gt;    .param [0]&lt;br /&gt;        .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (&lt;br /&gt;            01 00 00 00 00&lt;br /&gt;        )&lt;br /&gt;    // Method begins at RVA 0x9238&lt;br /&gt;    // Header size: 1&lt;br /&gt;    // Code size: 17 (0x11)&lt;br /&gt;    .maxstack 8&lt;br /&gt;&lt;br /&gt;    IL_0000: ldarg.0&lt;br /&gt;    IL_0001: ldobj Pocof.Data/Matcher&lt;br /&gt;    IL_0006: call string Pocof.Data::toString&amp;lt;valuetype Pocof.Data/Matcher&amp;gt;(!!0)&lt;br /&gt;    IL_000b: callvirt instance string [netstandard]System.String::ToLower()&lt;br /&gt;    IL_0010: ret&lt;br /&gt;} // end of method Matcher::ToString
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以下の &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; と &lt;code&gt;|&amp;gt;&lt;/code&gt; の結果から、関数合成は遅いという話は本当なんだ。
また、 pipeline 演算するだけで余計にコピーしてるのはちょっとショック。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// &amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ToString&lt;/span&gt;()&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    Matcher matcher = &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;;&lt;br /&gt;    FSharpFunc&amp;lt;Matcher, &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;&amp;gt; @_instance;&lt;br /&gt;    @_instance = ToString@&lt;span class=&quot;hljs-number&quot;&gt;235.&lt;/span&gt;@_instance;&lt;br /&gt;    FSharpFunc&amp;lt;&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;&amp;gt; @_instance2;&lt;br /&gt;    @_instance2 = ToString@&lt;span class=&quot;hljs-number&quot;&gt;235&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-1.&lt;/span&gt;@_instance;&lt;br /&gt;    Matcher matcher2 = matcher;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; @_instance2.Invoke(@_instance.Invoke(matcher2));&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// |&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ToString&lt;/span&gt;()&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    Matcher x = &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; text = toString(x);&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; text2 = text;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; text2.ToLower();&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;.method public hidebysig virtual&lt;br /&gt;    instance string ToString () cil managed&lt;br /&gt;{&lt;br /&gt;    .param [0]&lt;br /&gt;        .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (&lt;br /&gt;            01 00 00 00 00&lt;br /&gt;        )&lt;br /&gt;    // Method begins at RVA 0x9238&lt;br /&gt;    // Header size: 12&lt;br /&gt;    // Code size: 23 (0x17)&lt;br /&gt;    .maxstack 3&lt;br /&gt;    .locals init (&lt;br /&gt;        [0] valuetype Pocof.Data/Matcher &amp;#x27;Pipe #1 input at line 235&amp;#x27;,&lt;br /&gt;        [1] string &amp;#x27;Pipe #1 stage #1 at line 235&amp;#x27;,&lt;br /&gt;        [2] string&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;    IL_0000: ldarg.0&lt;br /&gt;    IL_0001: ldobj Pocof.Data/Matcher&lt;br /&gt;    IL_0006: stloc.0&lt;br /&gt;    IL_0007: ldloc.0&lt;br /&gt;    IL_0008: call string Pocof.Data::toString&amp;lt;valuetype Pocof.Data/Matcher&amp;gt;(!!0)&lt;br /&gt;    IL_000d: stloc.1&lt;br /&gt;    IL_000e: ldloc.1&lt;br /&gt;    IL_000f: stloc.2&lt;br /&gt;    IL_0010: ldloc.2&lt;br /&gt;    IL_0011: callvirt instance string [netstandard]System.String::ToLower()&lt;br /&gt;    IL_0016: ret&lt;br /&gt;} // end of method Matcher::ToString
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;IL の命令数を極限まで減らしていこうと pocof はしてないのだけど、 _.Property shorthand は気軽に使える高速な方法ってことで良さそう(実際そうした)。
逆にこれの結果に従うと C# like に書ける箇所は &lt;code&gt;.&lt;/code&gt; で引きずり回す方が効率が良いのでそうしようとなってしまうが、 pipeline の方が好きなので当面は採用しないでおく。
極限まで削らないといけないところが出たら局所的に採用するかも知れんけど。&lt;/p&gt;
&lt;p&gt;最近 &lt;a href=&quot;/booklogs/what-a-programmer-should-know-about-the-cpu.html&quot; title=&quot;プログラマーのための CPU 入門 CPU は如何にしてソフトウェアを高速に実行するか&quot;&gt;プログラマーのための CPU 入門 CPU は如何にしてソフトウェアを高速に実行するか&lt;/a&gt; を読んでるのもあって命令数に敏感になってるから気になってるだけって感じではある。
もっと全体的に見直す価値ある箇所あるのではよそっちやれ、という自戒。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;&lt;code&gt;UnixStat&lt;/code&gt; のことはよく知らないが、&lt;a href=&quot;https://github.com/PowerShell/PowerShell/blob/ed982b43384baf4e1f782f11b6cf558aa424ea1c/src/System.Management.Automation/namespaces/ProviderBase.cs#L1833&quot; title=&quot;PowerShell のコードにちらっと現れる&quot;&gt;PowerShell のコードにちらっと現れる&lt;/a&gt;。こいつを掘り下げて理解するのが今後の宿題かな &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 02 Feb 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-01-26-writing-cmdlet-in-fsharp-pt63.html</guid><link>https://krymtkts.github.io/posts/2025-01-26-writing-cmdlet-in-fsharp-pt63.html</link><title>F# で Cmdlet を書いてる pt.63</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;修正したい箇所の benchmark がなかったら作って、直して、修正後にまた benchmark を取って最適化の効果が出ているかを実践してみた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/315&quot; title=&quot;#315&quot;&gt;#315&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今回は単純に &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-array-1.html&quot; title=&quot;&lt;code&gt;array&lt;/code&gt;&quot;&gt;&lt;code&gt;array&lt;/code&gt;&lt;/a&gt; に対して &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-seqmodule.html&quot; title=&quot;&lt;code&gt;Seq&lt;/code&gt; module&quot;&gt;&lt;code&gt;Seq&lt;/code&gt; module&lt;/a&gt; を使ってた箇所を &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-arraymodule.html&quot; title=&quot;&lt;code&gt;Array&lt;/code&gt; module&quot;&gt;&lt;code&gt;Array&lt;/code&gt; module&lt;/a&gt; を使うようにしてみたのだが、要素数が少なく遅延評価が必要ない箇所ばかりでやはり &lt;code&gt;array&lt;/code&gt; のまま扱った方が処理速度が良い。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-seqmodule.html#filter&quot; title=&quot;&lt;code&gt;Seq.filter&lt;/code&gt;&quot;&gt;&lt;code&gt;Seq.filter&lt;/code&gt;&lt;/a&gt; を &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-arraymodule.html#filter&quot; title=&quot;&lt;code&gt;Array.filter&lt;/code&gt;&quot;&gt;&lt;code&gt;Array.filter&lt;/code&gt;&lt;/a&gt; にする前。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;| Method              |      Mean |     Error |    StdDev |    Median |    Gen0 |   Gen1 | Allocated |&lt;br /&gt;| ------------------- | --------: | --------: | --------: | --------: | ------: | -----: | --------: |&lt;br /&gt;| Action_fromString   | 642.77 us | 12.622 us | 27.171 us | 635.54 us | 89.8438 | 1.9531 | 369.12 KB |&lt;br /&gt;| Operator_fromString |  12.78 us |  0.430 us |  1.241 us |  13.18 us |  0.9766 |      - |   4.11 KB |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;修正後の方が良い。 &lt;code&gt;Operator_fromString&lt;/code&gt; の方は共通化の影響で使わない &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-arraymodule.html#filter&quot; title=&quot;&lt;code&gt;Array.filter&lt;/code&gt;&quot;&gt;&lt;code&gt;Array.filter&lt;/code&gt;&lt;/a&gt; が 1 箇所噛んでるから余計に &lt;code&gt;array&lt;/code&gt; を作ってしまったのかメモリ増えたけど。
こういうのも今後は削って切り詰めていくのがやっぱ妥当かな。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;| Method              |      Mean |     Error |    StdDev |    Gen0 | Allocated |&lt;br /&gt;| ------------------- | --------: | --------: | --------: | ------: | --------: |&lt;br /&gt;| Action_fromString   | 635.84 us | 12.393 us | 15.220 us | 89.8438 | 368.22 KB |&lt;br /&gt;| Operator_fromString |  12.10 us |  0.215 us |  0.328 us |  1.0986 |   4.56 KB |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あとこれは元のコードが拙かっただけだが、不必要に &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-seq-1.html&quot; title=&quot;&lt;code&gt;seq&lt;/code&gt;&quot;&gt;&lt;code&gt;seq&lt;/code&gt;&lt;/a&gt; を &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-list-1.html&quot; title=&quot;&lt;code&gt;list&lt;/code&gt;&quot;&gt;&lt;code&gt;list&lt;/code&gt;&lt;/a&gt; にしてたところを &lt;code&gt;seq&lt;/code&gt; のママ取り扱ったり、 &lt;code&gt;seq&lt;/code&gt; に index access してたところを infinite sequence を実装して次の要素を取るだけにしてみたり。&lt;/p&gt;
&lt;p&gt;修正前。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;| Method                                 |       Mean |    Error |    StdDev |     Median |   Gen0 | Allocated |&lt;br /&gt;| -------------------------------------- | ---------: | -------: | --------: | ---------: | -----: | --------: |&lt;br /&gt;| invokeAction_CompleteProperty_NoSearch |   131.2 ns |  2.64 ns |   2.82 ns |   130.8 ns | 0.0286 |     120 B |&lt;br /&gt;| invokeAction_CompleteProperty_Search   | 1,173.7 ns | 51.83 ns | 152.82 ns | 1,099.7 ns | 0.3319 |    1392 B |&lt;br /&gt;| invokeAction_CompleteProperty_Rotate   |   535.5 ns | 10.69 ns |  15.68 ns |   534.7 ns | 0.1869 |     784 B |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-listmodule.html#ofSeq&quot; title=&quot;&lt;code&gt;List.ofSeq&lt;/code&gt;&quot;&gt;&lt;code&gt;List.ofSeq&lt;/code&gt;&lt;/a&gt; 取り除きで高速化＆メモリ減。
(&lt;code&gt;invokeAction_CompleteProperty_NoSearch&lt;/code&gt; は影響受けないはずだが何でかメモリ消費が減ってる)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;| Method                                 |     Mean |    Error |   StdDev |   Median |   Gen0 | Allocated |&lt;br /&gt;| -------------------------------------- | -------: | -------: | -------: | -------: | -----: | --------: |&lt;br /&gt;| invokeAction_CompleteProperty_NoSearch | 131.5 ns |  2.53 ns |  3.63 ns | 130.2 ns | 0.0229 |      96 B |&lt;br /&gt;| invokeAction_CompleteProperty_Search   | 714.5 ns | 28.08 ns | 82.79 ns | 684.4 ns | 0.2041 |     856 B |&lt;br /&gt;| invokeAction_CompleteProperty_Rotate   | 476.3 ns |  9.31 ns | 13.05 ns | 470.9 ns | 0.1564 |     656 B |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;infinite sequence にした版。 &lt;a href=&quot;https://github.com/krymtkts/pocof/blob/2764077e96ad8b4a9e0a12daa79ce5d28325a151/src/pocof/Data.fs#L73-L79&quot; title=&quot;infinite sequence の実装&quot;&gt;infinite sequence の実装&lt;/a&gt;自体は再帰的な &lt;code&gt;seq&lt;/code&gt; 。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Seq &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;rec&lt;/span&gt; cycle source &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;seq&lt;/span&gt; {&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;yield!&lt;/span&gt; source&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;yield!&lt;/span&gt; cycle source&lt;br /&gt;            }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;PropertySearch.Rotate&lt;/code&gt; という DU が元々 &lt;code&gt;Rotate of keyword: string * candidates: string seq&lt;/code&gt; だったのが &lt;code&gt;Rotate of keyword: string * candidates: string seq&lt;/code&gt; になって tuple が 4 byte 縮んでると思うのだけどそれよりも infinite sequence によるオーバヘッドの方がメモリに乗ってるのか？
処理速度もメモリもパフォは良くないけど、次の index を算出するあたりが煩雑だったしわかりやすさとのトレードオフということで。
再帰的な &lt;code&gt;seq&lt;/code&gt; を作る際に &lt;code&gt;Seq.cache&lt;/code&gt; で計算済みにしたら速くなるかなと思ったけどむしろ遅くメモリ使用量も多くなったのでやめた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;| Method                                 |     Mean |    Error |   StdDev |   Median |   Gen0 | Allocated |&lt;br /&gt;| -------------------------------------- | -------: | -------: | -------: | -------: | -----: | --------: |&lt;br /&gt;| invokeAction_CompleteProperty_NoSearch | 124.0 ns |  2.57 ns |  3.77 ns | 123.1 ns | 0.0210 |      88 B |&lt;br /&gt;| invokeAction_CompleteProperty_Search   | 717.5 ns | 26.57 ns | 77.50 ns | 749.7 ns | 0.2232 |     936 B |&lt;br /&gt;| invokeAction_CompleteProperty_Rotate   | 534.7 ns | 10.66 ns | 17.21 ns | 529.6 ns | 0.2060 |     864 B |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こうやって、速くなっているのかメモリ消費が減っているのか、特に速度に関しては実行事のブレが大きいのもあれど、定量的に測れるというのは良い。
この手でダメなら次の手で、の試行錯誤をするのに明確な理由付けができる。
今は開発時に local で走らせてるだけだが、理想は CI で benchmark testing して時間・空間計算量が悪化してたら job をこけさせれたら良いけど、 GitHub Actions だと中々ブレが大きいようなので当面は様子見か。&lt;/p&gt;
&lt;p&gt;良いな～と思っているけど良くないところも当然ある。いちいち benchmark を取るから開発に時間がかかる。
今はまだ慣れてないから枝葉の部分でうまく使えるか練習してるような状態だが、ほんとはもっと中核の部分だけ開発時に benchmark を組み込むとかにした方が作業効率はいいんやろな。&lt;/p&gt;
&lt;p&gt;今月ちまちまいじった分をそろそろリリースするか。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;おまけで、 benchmark の改善とは関係ないけど &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-seqmodule.html#last&quot; title=&quot;&lt;code&gt;Seq.last&lt;/code&gt;&quot;&gt;&lt;code&gt;Seq.last&lt;/code&gt;&lt;/a&gt; を &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-arraymodule.html#last&quot; title=&quot;&lt;code&gt;Array.last&lt;/code&gt;&quot;&gt;&lt;code&gt;Array.last&lt;/code&gt;&lt;/a&gt; に変えた箇所の coverage が悪化することがあった。
理由は &lt;a href=&quot;https://github.com/dotnet/fsharp/blob/c4d36d699c52121cf2933314dac02b84a1a5a87a/src/FSharp.Core/array.fs#L33-L40&quot; title=&quot;&lt;code&gt;Array.last&lt;/code&gt; が inline 展開されると要素数 0 の場合にエラーを発生させる分岐が埋め込まれる&quot;&gt;&lt;code&gt;Array.last&lt;/code&gt; が inline 展開されると要素数 0 の場合にエラーを発生させる分岐が埋め込まれる&lt;/a&gt;から(&lt;a href=&quot;https://github.com/dotnet/fsharp/blob/c4d36d699c52121cf2933314dac02b84a1a5a87a/src/FSharp.Core/seq.fs#L1714-L1720&quot; title=&quot;&lt;code&gt;Seq.last&lt;/code&gt; は inline じゃない&quot;&gt;&lt;code&gt;Seq.last&lt;/code&gt; は inline じゃない&lt;/a&gt;)。
要素数が 1 以上であることを保証できるケースであれば単純に &lt;code&gt;array[array.Length - 1]&lt;/code&gt; して不要な分岐の発生を回避するしかない感じ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 26 Jan 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-01-19-writing-cmdlet-in-fsharp-pt62.html</guid><link>https://krymtkts.github.io/posts/2025-01-19-writing-cmdlet-in-fsharp-pt62.html</link><title>F# で Cmdlet を書いてる pt.62 - BenchmarkDotnet と ObjectLayoutInspector</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dotnet/BenchmarkDotNet&quot; title=&quot;BenchmarkDotnet&quot;&gt;BenchmarkDotnet&lt;/a&gt; や &lt;a href=&quot;https://github.com/SergeyTeplyakov/ObjectLayoutInspector&quot; title=&quot;ObjectLayoutInspector&quot;&gt;ObjectLayoutInspector&lt;/a&gt; で pocof の benchmark や memory layout を可視化できるようになったので、局所的ではあるが定量化された改善をはじめた。
何故局所的かというと、結局一部の module で改善されたとて全体的に見れば負荷を他所に避けているだけのこともあり、そういう意味で局所的だからだ。&lt;/p&gt;
&lt;p&gt;ひとまず着手したのは内部状態を管理する型 &lt;code&gt;InternalState&lt;/code&gt; のダイエットだ。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/305&quot; title=&quot;#305&quot;&gt;#305&lt;/a&gt;
元々可変状態のみを保存していくつもりの型だったが、幾度の機能開発を経て起動後変わらんだろうという field まで含まれるようになっていた。
理想的には更新頻度も高めで取り回されることも多いし GC を避ける目的で struct にしたいのだが、サイズが大きくなり struct にしようものなら爆発的にコピーコストが嵩むという状態だった。
本当に struct にするかは benchmark との相談だが、やるやらない関係なくとも fat なので、ひとまず減量する必要があるなと考えた。&lt;/p&gt;
&lt;p&gt;まず &lt;code&gt;InternalState&lt;/code&gt; でプログラム実行中に変わらない fields を整理して半分ほど取り除いたりしてみた。
結果 memory layout は以下のようになった。
削られた fields はカリー化された関数の引数だったりの起動時以降変更されない値に移行した。&lt;/p&gt;
&lt;p&gt;減量前 (&lt;a href=&quot;https://github.com/krymtkts/pocof/commit/15b6fe40738a7c1a72e4125cb87137e945d04c3f&quot; title=&quot;15b6fe4&quot;&gt;15b6fe4&lt;/a&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Type layout for &amp;#x27;InternalState&amp;#x27;&lt;br /&gt;Size: 88 bytes. Paddings: 7 bytes (%7 of empty space)&lt;br /&gt;|=====================================================|&lt;br /&gt;| Object Header (8 bytes)                             |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| Method Table Ptr (8 bytes)                          |&lt;br /&gt;|=====================================================|&lt;br /&gt;|   0-7: QueryState QueryState@ (8 bytes)             |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;|  8-15: QueryCondition QueryCondition@ (8 bytes)     |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 16-23: PropertySearch PropertySearch@ (8 bytes)     |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 24-31: FSharpOption`1 Notification@ (8 bytes)       |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 32-39: IReadOnlyCollection`1 Properties@ (8 bytes)  |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 40-47: IReadOnlyDictionary`2 PropertyMap@ (8 bytes) |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 48-55: String Prompt@ (8 bytes)                     |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 56-63: String WordDelimiters@ (8 bytes)             |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 64-71: Refresh Refresh@ (8 bytes)                   |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 72-75: Int32 PromptLength@ (4 bytes)                |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 76-79: Int32 ConsoleWidth@ (4 bytes)                |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;|    80: Boolean SuppressProperties@ (1 byte)         |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 81-87: padding (7 bytes)                            |&lt;br /&gt;|=====================================================|
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;減量後 (&lt;a href=&quot;https://github.com/krymtkts/pocof/commit/9ab37b0460a7473955b9b61b44ac34f3fd77008c&quot; title=&quot;9ab37b0&quot;&gt;9ab37b0&lt;/a&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Type layout for &amp;#x27;InternalState&amp;#x27;&lt;br /&gt;Size: 40 bytes. Paddings: 7 bytes (%17 of empty space)&lt;br /&gt;|=================================================|&lt;br /&gt;| Object Header (8 bytes)                         |&lt;br /&gt;|-------------------------------------------------|&lt;br /&gt;| Method Table Ptr (8 bytes)                      |&lt;br /&gt;|=================================================|&lt;br /&gt;|   0-7: QueryState QueryState@ (8 bytes)         |&lt;br /&gt;|-------------------------------------------------|&lt;br /&gt;|  8-15: QueryCondition QueryCondition@ (8 bytes) |&lt;br /&gt;|-------------------------------------------------|&lt;br /&gt;| 16-23: PropertySearch PropertySearch@ (8 bytes) |&lt;br /&gt;|-------------------------------------------------|&lt;br /&gt;| 24-31: Refresh Refresh@ (8 bytes)               |&lt;br /&gt;|-------------------------------------------------|&lt;br /&gt;|    32: Boolean SuppressProperties@ (1 byte)     |&lt;br /&gt;|-------------------------------------------------|&lt;br /&gt;| 33-39: padding (7 bytes)                        |&lt;br /&gt;|=================================================|
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これにより、キー入力で内部状態を書き換える処理の benchmark は良い方向に差分が出た。そこそこ速くメモリも軽くなった。
多分取り除いた fields より、それらを更新する関数が取り除かれたことによる影響が大きそう。&lt;/p&gt;
&lt;p&gt;減量前 (&lt;a href=&quot;https://github.com/krymtkts/pocof/commit/15b6fe40738a7c1a72e4125cb87137e945d04c3f&quot; title=&quot;15b6fe4&quot;&gt;15b6fe4&lt;/a&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;| Method                          | Mean       | Error    | StdDev   | Gen0   | Allocated |&lt;br /&gt;|-------------------------------- |-----------:|---------:|---------:|-------:|----------:|&lt;br /&gt;| invokeAction_Noop               |   131.6 ns |  2.39 ns |  2.35 ns | 0.0401 |     168 B |&lt;br /&gt;| invokeAction_AddQuery           | 1,690.6 ns | 32.05 ns | 63.26 ns | 0.8106 |    3392 B |&lt;br /&gt;| invokeAction_BackwardChar       |   530.5 ns | 10.64 ns | 19.98 ns | 0.1030 |     432 B |&lt;br /&gt;| invokeAction_DeleteBackwardChar |   220.1 ns |  4.31 ns |  3.36 ns | 0.0401 |     168 B |&lt;br /&gt;| invokeAction_SelectBackwardChar |   444.8 ns |  8.78 ns | 13.41 ns | 0.1183 |     496 B |&lt;br /&gt;| invokeAction_RotateMatcher      |   202.4 ns |  4.44 ns | 11.86 ns | 0.1070 |     448 B |&lt;br /&gt;| invokeAction_CompleteProperty   |   249.8 ns | 21.63 ns | 63.77 ns | 0.0496 |     208 B |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;減量後 (&lt;a href=&quot;https://github.com/krymtkts/pocof/commit/9ab37b0460a7473955b9b61b44ac34f3fd77008c&quot; title=&quot;9ab37b0&quot;&gt;9ab37b0&lt;/a&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;| Method                          | Mean     | Error    | StdDev   | Gen0   | Allocated |&lt;br /&gt;|-------------------------------- |---------:|---------:|---------:|-------:|----------:|&lt;br /&gt;| invokeAction_Noop               | 113.9 ns |  2.29 ns |  3.90 ns | 0.0210 |      88 B |&lt;br /&gt;| invokeAction_AddQuery           | 964.6 ns | 19.28 ns | 20.63 ns | 0.4406 |    1848 B |&lt;br /&gt;| invokeAction_BackwardChar       | 285.4 ns |  5.79 ns | 10.58 ns | 0.0591 |     248 B |&lt;br /&gt;| invokeAction_DeleteBackwardChar | 125.3 ns |  2.58 ns |  3.70 ns | 0.0210 |      88 B |&lt;br /&gt;| invokeAction_SelectBackwardChar | 308.2 ns |  6.22 ns | 11.06 ns | 0.0744 |     312 B |&lt;br /&gt;| invokeAction_RotateMatcher      | 131.5 ns |  2.67 ns |  2.74 ns | 0.0381 |     160 B |&lt;br /&gt;| invokeAction_CompleteProperty   | 125.3 ns |  2.57 ns |  3.43 ns | 0.0286 |     120 B |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;が、これは局所最適なだけで、全体的に見れば他所に寄せられた負荷(特に正規表現パターンのエラー表示)があるので、全体で見てどこまで効果があるかはちょっと微妙。
そんで全体的な benchmark を取る術がないのが現状。
pocof は event loop を末尾再帰で実装してて、そこで &lt;code&gt;InternalState&lt;/code&gt; の受け渡しが延々と発生してるので、そのへんの benchmark も見ておきたいのだけどまだ作れてない。&lt;/p&gt;
&lt;p&gt;とりあえず &lt;code&gt;InternalState&lt;/code&gt; の減量の第 1 ステップは完了、次のステップを進めるのに先述の通り今の benchmark では心許ないなと感じている。
たまにメチャクチャ簡単に部分的な高速化が全体に好影響をもたらすケースもあるが、他に影響ないのを確認するにはやはり全体を見るものがないと確証を得にくい。
必要は感じているが全体を見る benchmark 作るのちょっとしんどいな...と思ってしまいまだ着手できておらず、結果的に局所的な改善な改善からちまちまやってしまっているのは essential ではないなーと感じる。
はよ autopilot のアイデアを実現しろという自身からの圧。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 19 Jan 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-01-12-writing-cmdlet-in-fsharp-pt61.html</guid><link>https://krymtkts.github.io/posts/2025-01-12-writing-cmdlet-in-fsharp-pt61.html</link><title>F# で Cmdlet を書いてる pt.61 - ObjectLayoutInspector</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dotnet/BenchmarkDotNet&quot; title=&quot;BenchmarkDotnet&quot;&gt;BenchmarkDotnet&lt;/a&gt; に続き &lt;a href=&quot;https://github.com/SergeyTeplyakov/ObjectLayoutInspector&quot; title=&quot;ObjectLayoutInspector&quot;&gt;ObjectLayoutInspector&lt;/a&gt; で pocof の &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/records&quot; title=&quot;record&quot;&gt;record&lt;/a&gt; とか &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions&quot; title=&quot;DU&quot;&gt;DU&lt;/a&gt; の memory layout を可視化し始めた。&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/300&quot; title=&quot;#300&quot;&gt;#300&lt;/a&gt;
benchmark とるのや memory layout の考え方は以下の blog が詳しく、参考にさせてもらっている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bartoszsypytkowski.com/writing-high-performance-f-code/&quot; title=&quot;Writing high performance F# code&quot;&gt;Writing high performance F# code&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-08-04-writing-cmdlet-in-fsharp-pt46.html&quot; title=&quot;半年ほど前&quot;&gt;半年ほど前&lt;/a&gt;にもこの blog を見てたのだけど、 .NET 力と F# 力が低かったから手を付けれずにいた。
今もレベル低いが前よりは高まったので、ようやく手を動かす気になったので試しているところだ。
pocof に取り込むに当たり練習しておくための repo &lt;a href=&quot;https://github.com/krymtkts/fsharp-bench&quot; title=&quot;krymtkts/fsharp-bench&quot;&gt;krymtkts/fsharp-bench&lt;/a&gt; も作った。
以下は pocof の型を分析した例で、 record と DU の memory layout を印刷できて便利。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Type layout for &amp;#x27;Refresh&amp;#x27;&lt;br /&gt;Size: 8 bytes. Paddings: 4 bytes (%50 of empty space)&lt;br /&gt;|=============================|&lt;br /&gt;| Object Header (8 bytes)     |&lt;br /&gt;|-----------------------------|&lt;br /&gt;| Method Table Ptr (8 bytes)  |&lt;br /&gt;|=============================|&lt;br /&gt;|   0-3: Int32 _tag (4 bytes) |&lt;br /&gt;|-----------------------------|&lt;br /&gt;|   4-7: padding (4 bytes)    |&lt;br /&gt;|=============================|
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この &lt;code&gt;Refresh&lt;/code&gt; DU は独自の field を持たず、 tag (DU のケース分け)しかないのでこういうのは&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/structs&quot; title=&quot;構造体&quot;&gt;構造体&lt;/a&gt;とすることで、Object header と vtable(method table) pointer を削減できる分パフォ改善できるケースが多い。
tag だけなら &lt;code&gt;int32 _tag&lt;/code&gt; の 4 bytes しか使わないから、参照ポインタの 8 bytes の半分になる。
コピーコスト以外にも利用する側でも padding が発生しなければ効率が良くなる。&lt;/p&gt;
&lt;p&gt;ただ DU を構造体として扱うときの難しいところは、各 tag の filed 全ての memory を確保するところ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Type layout for &amp;#x27;Key&amp;#x27;&lt;br /&gt;Size: 32 bytes. Paddings: 10 bytes (%31 of empty space)&lt;br /&gt;|====================================|&lt;br /&gt;|   0-3: ConsoleKey _key (4 bytes)   |&lt;br /&gt;| |================================| |&lt;br /&gt;| |   0-3: Int32 value__ (4 bytes) | |&lt;br /&gt;| |================================| |&lt;br /&gt;|------------------------------------|&lt;br /&gt;|   4-7: Int32 _tag (4 bytes)        |&lt;br /&gt;|------------------------------------|&lt;br /&gt;|   8-9: Char _c (2 bytes)           |&lt;br /&gt;|------------------------------------|&lt;br /&gt;| 10-15: padding (6 bytes)           |&lt;br /&gt;|------------------------------------|&lt;br /&gt;| 16-31: Action _action (16 bytes)   |&lt;br /&gt;| |================================| |&lt;br /&gt;| |   0-7: String _query (8 bytes) | |&lt;br /&gt;| |--------------------------------| |&lt;br /&gt;| |  8-11: Int32 _tag (4 bytes)    | |&lt;br /&gt;| |--------------------------------| |&lt;br /&gt;| | 12-15: padding (4 bytes)       | |&lt;br /&gt;| |================================| |&lt;br /&gt;|====================================|
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この &lt;code&gt;Key&lt;/code&gt; DU は &lt;code&gt;StructAttribute&lt;/code&gt; 付与してて、 内包する &lt;code&gt;Action&lt;/code&gt; も構造体なので、以下のように大きめになる。
&lt;code&gt;Key&lt;/code&gt; DU に限れば、 内包する &lt;code&gt;Action&lt;/code&gt; DU を使ってる箇所で &lt;code&gt;String query&lt;/code&gt; を使うケースは除外されてるので、別の Struct DU を作って置き換えるべきだろう。
前に軽率に &lt;code&gt;Struct&lt;/code&gt; を付与したのが裏目に出てる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Type layout for &amp;#x27;InternalState&amp;#x27;&lt;br /&gt;Size: 88 bytes. Paddings: 7 bytes (%7 of empty space)&lt;br /&gt;|=====================================================|&lt;br /&gt;| Object Header (8 bytes)                             |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| Method Table Ptr (8 bytes)                          |&lt;br /&gt;|=====================================================|&lt;br /&gt;|   0-7: QueryState QueryState@ (8 bytes)             |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;|  8-15: QueryCondition QueryCondition@ (8 bytes)     |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 16-23: PropertySearch PropertySearch@ (8 bytes)     |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 24-31: FSharpOption`1 Notification@ (8 bytes)       |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 32-39: IReadOnlyCollection`1 Properties@ (8 bytes)  |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 40-47: IReadOnlyDictionary`2 PropertyMap@ (8 bytes) |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 48-55: String Prompt@ (8 bytes)                     |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 56-63: String WordDelimiters@ (8 bytes)             |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 64-71: Refresh Refresh@ (8 bytes)                   |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 72-75: Int32 PromptLength@ (4 bytes)                |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 76-79: Int32 ConsoleWidth@ (4 bytes)                |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;|    80: Boolean SuppressProperties@ (1 byte)         |&lt;br /&gt;|-----------------------------------------------------|&lt;br /&gt;| 81-87: padding (7 bytes)                            |&lt;br /&gt;|=====================================================|
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こちらはデカすぎる &lt;code&gt;InternalState&lt;/code&gt; record。こういうのは構造体にするとコピーコストかさむため重くなる。
先に挙げたような単純な DU を構造体にすれば参照ポインタよりサイズを小さくできるのでメモリを節約できるか。
他にも最近の改善で &lt;code&gt;Prompt&lt;/code&gt; は切り分けられるようになったし、改善できるかな。
benchmark 調べた感じだとデカい record 一発で取り回すより細かい record に分けて取り回した方が速いから、分けるべきなのかも。&lt;/p&gt;
&lt;p&gt;ちなみに、 ObjectLayoutInspector の &lt;code&gt;fsproj&lt;/code&gt; は実行形式(&lt;code&gt;OutputType&lt;/code&gt; &lt;code&gt;Exe&lt;/code&gt;) にしておかないと標準出力できないので、 &lt;code&gt;TargetFramework&lt;/code&gt; は &lt;code&gt;net9&lt;/code&gt; にしている。
pocof は PowerShell の各 version との互換性のために &lt;code&gt;netstandard2.0&lt;/code&gt; を対象にしてて、 &lt;code&gt;ProjectReference&lt;/code&gt; で &lt;code&gt;pocof.fsproj&lt;/code&gt; を参照してるから、 pocof 側の record や DU は &lt;code&gt;netstandard2.0&lt;/code&gt; 準拠で compile され、実際に利用されるときと同じ memory layout が出力される(はず)。&lt;/p&gt;
&lt;p&gt;一通り record や DU の memory layout は見れるようにしたのだけど、 benchmark は簡単なのだけがある状態なので、 pocof のパフォで気になる部分の benchmark を作って計測してみないことには最適化に着手できない。
これ、どういう風に実際と同じような benchmark を作るか考えるのも中々難しいよな。
pocof は module 毎に公開されてる関数が概ねその module の entrypoint になってて、そこは benchmark を作りやすい。
けど組み合わせたパターンになると、 PowerShell の E2E testing 改善の文脈と同じような autopilot mode みたいなの作り込むってところにつながってく気がするな。
いま unit test でやってる &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.management.automation.icommandruntime?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;ICommandRuntime&lt;/code&gt;&quot;&gt;&lt;code&gt;ICommandRuntime&lt;/code&gt;&lt;/a&gt; のテスト用実装で &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.management.automation.host.pshostuserinterface?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;PSHostUserInterface&lt;/code&gt;&quot;&gt;&lt;code&gt;PSHostUserInterface&lt;/code&gt;&lt;/a&gt; テスト用派生クラスをもう少し作れたらかのうせいがあるのかも(今は空っぽ)。
キー入力と仮想スクリーンをうまく作れるか次第よな～。&lt;/p&gt;
&lt;p&gt;まあ何にせよ benchmark が取れて memory layout を可視化できるようになって、準備は揃っている。
このあたりの知識は .NET の内部的な話で、先に挙げた blog のような解析をしてる人の記事以外は文書が見当たらないし、先人の通った道を自分も通ることでしか習熟しないと思うねんよな。
何より ChatGPT や Copilot ｻﾝも全然詳しくなくて当てにならないところ。尚更自分でやるしかない。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 12 Jan 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-01-05-writing-cmdlet-in-fsharp-pt60.html</guid><link>https://krymtkts.github.io/posts/2025-01-05-writing-cmdlet-in-fsharp-pt60.html</link><title>F# で Cmdlet を書いてる pt.60 - xUnit v3 と FsUnit と FsCheck</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;年末年始は結局 &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。
command-line predictor の開発は始めず。&lt;/p&gt;
&lt;p&gt;0.18.1 のリリースで小綺麗にできるようになったのもあって、基本コード最適化みたいなやつをやった。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/285&quot; title=&quot;#285&quot;&gt;#285&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/293&quot; title=&quot;#293&quot;&gt;#293&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/295&quot; title=&quot;#295&quot;&gt;#295&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/296&quot; title=&quot;#296&quot;&gt;#296&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/297&quot; title=&quot;#297&quot;&gt;#297&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/298&quot; title=&quot;#298&quot;&gt;#298&lt;/a&gt;
ずっとやらずに置かれていたページめくり &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/16&quot; title=&quot;#16&quot;&gt;#16&lt;/a&gt; や行選択 &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/17&quot; title=&quot;#17&quot;&gt;#17&lt;/a&gt; などで行を選択するやつを not planned で閉じたりもした。
PowerShell の &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_format.ps1xml?view=powershell-7.4&quot; title=&quot;Format.ps1xml&quot;&gt;Format.ps1xml&lt;/a&gt; で変わる見た目を今のところ尊重してるから使えんなという判断でだ。&lt;/p&gt;
&lt;p&gt;他に新たな試みとしては、成果物のサイズを減らしてみたり &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/284&quot; title=&quot;#284&quot;&gt;#284&lt;/a&gt; 、
&lt;a href=&quot;https://github.com/dotnet/BenchmarkDotNet&quot; title=&quot;BenchmarkDotnet&quot;&gt;BenchmarkDotnet&lt;/a&gt; でベンチマーク測定できるようにしたり &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/294&quot; title=&quot;#294&quot;&gt;#294&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;ベンチマークはまだ GitHub Actions workflow に組み込んでない。どうも実行のたびにスペックが固定されてないらしくて、安定したベンチマーク測定に向かないらしいという情報をいくつか見かけた。
ただ相対値を測るくらいなら問題ないので、ベンチマークテストも追加できたら良さそう。これは今後に託す。&lt;/p&gt;
&lt;p&gt;あと取り組んだけどうまくいかなかったものもある。 &lt;a href=&quot;https://github.com/fsprojects/FsUnit&quot; title=&quot;FsUnit&quot;&gt;FsUnit&lt;/a&gt; と &lt;a href=&quot;https://github.com/fscheck/FsCheck&quot; title=&quot;FsCheck&quot;&gt;FsCheck&lt;/a&gt; が依存する &lt;a href=&quot;https://github.com/xunit/xunit&quot; title=&quot;xUnit&quot;&gt;xUnit&lt;/a&gt; の major update だ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;FsUnit が &lt;a href=&quot;https://github.com/fsprojects/FsUnit/releases/tag/7.0.0&quot; title=&quot;7.0.0&quot;&gt;7.0.0&lt;/a&gt; で xUnit 3 系に対応したので試したら、 &lt;code&gt;.nupkg&lt;/code&gt; に dll と exe が含まれてて依存関係が解決できずそのままでは使えなかった。
報告して workaround を教えてもらったり対応してもらった &lt;a href=&quot;https://github.com/fsprojects/FsUnit/issues/298&quot; title=&quot;fsprojects/FsUnit#298&quot;&gt;fsprojects/FsUnit#298&lt;/a&gt; ので、いざ pocof でそれを使いだしたら PBT が動かなくなってしまった。
すっかり忘れてたのだけど、 FsUnit だけじゃなく FsCheck も xUnit 依存してたのだった。&lt;/p&gt;
&lt;p&gt;xUnit は v3 から NuGet package name が &lt;a href=&quot;https://www.nuget.org/packages/xunit&quot; title=&quot;&lt;code&gt;xunit&lt;/code&gt;&quot;&gt;&lt;code&gt;xunit&lt;/code&gt;&lt;/a&gt; から &lt;a href=&quot;https://www.nuget.org/packages/xunit.v3&quot; title=&quot;&lt;code&gt;xunit.v3&lt;/code&gt;&quot;&gt;&lt;code&gt;xunit.v3&lt;/code&gt;&lt;/a&gt; に変わるという変更だけでも大きいのだけど、 xUnit の extension に提供されてる interface が大幅に変更されてた。
&lt;a href=&quot;https://xunit.net/docs/getting-started/v3/migration#migrating-to-v3-packages&quot; title=&quot;Migrating from v2 to v3 [Unit test authors] &amp;gt; xUnit.net&quot;&gt;Migrating from v2 to v3 [Unit test authors] &amp;gt; xUnit.net&lt;/a&gt; 以降に詳しく書かれてる。
FsUnit の方は&lt;a href=&quot;https://github.com/fsprojects/FsUnit/pull/297/files&quot; title=&quot;ほぼコードが xUnit に依存してなくて package 変更くらいしか影響なかった&quot;&gt;ほぼコードが xUnit に依存してなくて package 変更くらいしか影響なかった&lt;/a&gt;けど、
FsCheck の方は interface 変更のあおりを受けてかなり変更しないといけない &lt;a href=&quot;https://github.com/fscheck/FsCheck/issues/690&quot; title=&quot;fscheck/FsCheck#690&quot;&gt;fscheck/FsCheck#690&lt;/a&gt;感じ。
(他の人もそう考えてたみたいだが)わたしもサクッと変更できるならコントリした方が速いなと考えて試しにやってみたが、この interface 変更やらがやたらメンドくていったん諦めた(ｵｲ)。
多分先述の xUnit の文書をガッツリ読み込めて、 xUnit の extension に詳しい人なら難しくないのだろうけど、ちょっと xUnit 素人がパパっと終えれるものではなかった。&lt;/p&gt;
&lt;p&gt;FsCheck はいま &lt;a href=&quot;https://github.com/fscheck/FsCheck/releases/tag/3.0.0-rc3&quot; title=&quot;v3 の release candidate&quot;&gt;v3 の release candidate&lt;/a&gt; の段階だし、ここでこのクソデカ変更を入れるのか？みたいなのも判断難しいと思う。
xUnit は v2, v3 別々にメンテしていくつもりで NuGet package name 分けちゃってるしな。どえらいこっちゃなという印象を受けたが、こういうの一般的なんだろうか。
FsUnit が採用した v2 との後方互換性を落として v3 一択にする方針が、コミュニティベースで開発する OSS には向いてると思うけど、 FsCheck がどうするかはまだ動きが見えてない。
メンテナの人が昔別の OSS で xUnit v1 → xUnit v2 の経験があるらしくて、そのときは &lt;a href=&quot;https://github.com/fscheck/FsCheck/issues/690#issuecomment-2568432777&quot; title=&quot;NuGet package name を分ける対応&quot;&gt;NuGet package name を分ける対応&lt;/a&gt;をしたらしい。 xUnit 流のやり方に寄せるのかなー。複数パッケージをひとつの repo から提供した経験ないから興味深く観察する。&lt;/p&gt;
&lt;p&gt;年末年始で xUnit v3 に上げれなかったのはちょっと惜しかったなと思うものの、その過程で &lt;a href=&quot;https://github.com/fsprojects/FsUnit/issues/298#issuecomment-2565124825&quot; title=&quot;package に含まれる任意のファイルを消し去る技&quot;&gt;package に含まれる任意のファイルを消し去る技&lt;/a&gt;を知れたり、 xUnit のように package name を変えて複数バージョンサポートするスタイルがあるのを知れたのはいい経験になった。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 05 Jan 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2025-01-01-planning.html</guid><link>https://krymtkts.github.io/posts/2025-01-01-planning.html</link><title>2025</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;例年通り目標をたてる。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;テーマ: 不惑&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;2023 年から続くテーマ、不惑。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2025-&quot; href=&quot;#2025-&quot;&gt;2025 年の目標&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;継続目標だが、強度を上げれるものは上げていく。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;積読消化 1 冊/月を超える&lt;ul&gt;
&lt;li&gt;読書習慣構築後は 2 ヵ月で 1 冊いけたので、次は月 1 冊&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;F# の開発&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; と &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;blog-fable&quot;&gt;blog-fable&lt;/a&gt; をやりつつ、 Command-line predictor plugin 作ってみる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;GitHub のストリークを継続する&lt;ul&gt;
&lt;li&gt;今年前半で 1,000 達するので気を抜かず取り組んでく&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;毎週ブログを書く&lt;/li&gt;&lt;li&gt;ギター練習を 4 / week&lt;/li&gt;&lt;li&gt;深酒で怪我をしない&lt;ul&gt;
&lt;li&gt;血中アルコール濃度にも気をつけたいな。測りようないかもだが&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;自分メンテナンス&lt;ul&gt;
&lt;li&gt;読書の習慣化の次は、筋トレ習慣化。いま日記とかアプリに記録してるけどそれだと効力低めなので、もっとシステマティックな習慣化できないかな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;2024 年後半は、仕事で所々迷いが生じたこともあったので、もう少し意思を堅固にしたいな。
先々のことまで考えすぎて決断の数が多いのをエッセンシャルなところに絞るべきなんやろうか。
とはいえ先のことを考える者が他にいなかったら誰かがやらないといけないから、そのジレンマとどう付き合うかよな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Wed, 01 Jan 2025 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-12-31-retrospective2024.html</guid><link>https://krymtkts.github.io/posts/2024-12-31-retrospective2024.html</link><title>振り返り 2024 年</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;2024 年を振り返る。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-01-01-planning.html&quot; title=&quot;2024 年のテーマ&quot;&gt;2024 年のテーマ&lt;/a&gt;は 2 年連続の「不惑」だった。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2024-&quot; href=&quot;#2024-&quot;&gt;2024 年の目標と成果&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;いい線いってるというのが率直な自己評価だ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭕️ 積読消化 0.5 冊/月を超える&lt;ul&gt;
&lt;li&gt;そういう機能を blog に作ったので習慣化に成功したし、定量的にも年間目標達成。ちょっと読み込み浅いかもなという懸念が浮かんできてるけど、まず息をするように数をこなせるようになるのに注力したい。現状は習慣化してるといってもなんだかんだ追われてる感が払拭できてない気がする&lt;ul&gt;
&lt;li&gt;読了&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;/booklogs/dmmf.html&quot; title=&quot;Domain Modeling Made Functional 関数型ドメインモデリング ドメイン駆動設計と F# でソフトウェアの複雑さに立ち向かおう&quot;&gt;Domain Modeling Made Functional 関数型ドメインモデリング ドメイン駆動設計と F# でソフトウェアの複雑さに立ち向かおう&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/people-powered.html&quot; title=&quot;People Powered 「ビジネス」「ブランド」「チーム」を変革するコミュニティの原則 遠くへ行きたければ、みんなで行け&quot;&gt;People Powered 「ビジネス」「ブランド」「チーム」を変革するコミュニティの原則 遠くへ行きたければ、みんなで行け&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/the-programmers-brain.html&quot; title=&quot;プログラマー脳 優れたプログラマーになるための認知科学に基づくアプローチ&quot;&gt;プログラマー脳 優れたプログラマーになるための認知科学に基づくアプローチ&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/docs-for-developers.html&quot; title=&quot;ユーザーの問題解決とプロダクトの成功を導く エンジニアのためのドキュメントライティング&quot;&gt;ユーザーの問題解決とプロダクトの成功を導く エンジニアのためのドキュメントライティング&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/how-world-class-engineers-thinks.html&quot; title=&quot;世界一流エンジニアの思考法&quot;&gt;世界一流エンジニアの思考法&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/how-to-read-a-book.html&quot; title=&quot;本を読む本&quot;&gt;本を読む本&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/property-based-testing.html&quot; title=&quot;実践プロパティベーステスト PropEr と Erlang/Elixir ではじめよう&quot;&gt;実践プロパティベーステスト PropEr と Erlang/Elixir ではじめよう&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;/li&gt;&lt;li&gt;途中&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/booklogs/introduction-to-ethics.html&quot; title=&quot;入門・倫理学&quot;&gt;入門・倫理学&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/wei-wu-zhu-sun-tzu.html&quot; title=&quot;魏武注孫子&quot;&gt;魏武注孫子&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;/booklogs/peering-chronicle-in-japan.html&quot; title=&quot;ピアリング戦記 日本のインターネットを繋ぐ技術者たち&quot;&gt;ピアリング戦記 日本のインターネットを繋ぐ技術者たち&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️ F# の開発&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;2023 末に 0.7.0 だったのが 0.18.1 まできた&lt;/li&gt;&lt;li&gt;&lt;code&gt;git log --since=&amp;quot;2024-01-01&amp;quot; --until=&amp;quot;2024-12-31&amp;quot; --date=short --pretty=format:&amp;quot;%ad %an %s&amp;quot; | ? {($_ -notmatch &amp;#39;Merge pull&amp;#39;) -and ($_ -notmatch &amp;#39;dependabot\[bot\]&amp;#39;)} | Set-Clipboard&lt;/code&gt; を GitHub Copilot(o1 preview) に食わせて出させた概要は以下の通り。微妙に説明足りてないけどそれは多分 commit message がしょぼいせい。 2024 年にできるようになったことって結構あるねんなというのが率直な感想&lt;ul&gt;
&lt;li&gt;prompt&lt;ul&gt;
&lt;li&gt;&lt;blockquote&gt;
&lt;p&gt;このコミット履歴から、機能開発の概要やバージョンアップの履歴を時系列で日本語の文章にまとめて。 2024-01-01 時点では 0.7.0 でした。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;回答&lt;ul&gt;
&lt;li&gt;&lt;blockquote&gt;
&lt;p&gt;これらのコミットでは、2024-01-01 時点で 0.7.0 だったバージョンが、主に新機能の追加やバグ修正、リファクタリング、ドキュメント更新に合わせて段階的に引き上げられています。たとえば、2024-01-13 に 0.8.0、1 月末に 0.9.0、2 月末に 0.10.0、4 月初旬に 0.11.0、5 月に 0.12.x と 0.13.0、7 月に 0.14.x、9 月に 0.15.0、10 月に 0.16.x、11 月に 0.17.0、12 月下旬に 0.18.x とリリースを重ねています。コミット内容は、クエリウィンドウや非同期レンダリング、半分の高さウィンドウ、独自のワード区切り設定など機能拡張に加え、テストやドキュメントの整備が継続的に行われ、最終的には 0.18.1 までバージョンが進みました。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;F# 的な初体験としてはコードクォートや遅延評価を実際に使ったくらい？ Cmdlet に非同期レンダリングを持ち込むのも個人的には挑戦的だったかもな。&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;あんまやるつもり無かったが booklog 機能は作ってよかった。お陰？で定期的にちょいちょい弄りたい部分も出てきた&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;新しい取り組みは Command-line predictor を作るための調査を &lt;a href=&quot;https://github.com/krymtkts/SamplePredictor&quot; title=&quot;krymtkts/SamplePredictor&quot;&gt;krymtkts/SamplePredictor&lt;/a&gt; でしたくらい、もうちょいやれたと思う。後は着手するだけなんやけどな～ 2025 入ってから alpha でもいいから作れないかな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️ GitHub のストリークを継続する&lt;ul&gt;
&lt;li&gt;きょう含め 863 。もうまず途絶えることないやろなという自信は持てた。だけど今まで見かけた中の最強が 2,500(6.8 年！) 超えてる人なのでまだまだ先は長い。なんで続けてるか忘れるくらいに没頭してからが本番かな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️ 毎週ブログを書く&lt;ul&gt;
&lt;li&gt;良く書けてる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️ ギター練習を 4 / week&lt;ul&gt;
&lt;li&gt;ちまちま 1 日 30 分くらいで。ただ相変わらず下手くそなので昔コピッた曲を練習し直したり。ライブもスタジオ練習もやってないから何曲も弾ける体力がなくなってきててすぐ息があがる&lt;/li&gt;&lt;li&gt;Tremolo unit 変えたいな～と思い出して 1 年経った。 &lt;a href=&quot;https://www.tremoline.com/tremolo-systems&quot; title=&quot;Tremoline&quot;&gt;Tremoline&lt;/a&gt; の 7 string あったら絶対買いそうやけどんないねんよな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;❌️ 深酒で怪我をしない&lt;ul&gt;
&lt;li&gt;今年は花見で派手な擦り傷したり血中アルコール濃度高めすぎて長期記憶曖昧だったりよろしくなかった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;🔺 自分メンテナンス&lt;ul&gt;
&lt;li&gt;体重あんま変わらん。こなせる負荷は増えてるし筋力アップはしる。でも今年後半忙しい時は気持ちがアゲられず何も出来ない日もあったので、もっとシステマティックな習慣化を目指す&lt;/li&gt;&lt;li&gt;何も運動しないのに加齢のせいだと思うが膝が朝バキッ！っていってから毎日パキポキいって、痛むときもある。サポートのためスクワットとカーフレイズ足した。脚太くなっていい感じなんやが、未だ動いてる時はなんともないけど停止状態から動いたときとかポキパキなんよな。病院いかなあかんかな...&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;酒とか膝とか、加齢による劣化が見られるのでなんか改善したいが何したらいいんだか。&lt;/p&gt;
&lt;p&gt;仕事に於いては、 2024 年は担う仕事のうち中長期(N ヶ月～最長起票から終わるまで 1 年 8 ヶ月)なものに取り組む中で所々判断に迷いが生じたこともあった。当然生じても遂行したが。
後半にかけてこれってもしかしてミドルエイジクライシスか！(wktk)と思ったけど、キャリアや子育てが一段落したわけでもないから多分違うな。&lt;/p&gt;
&lt;p&gt;単身で取り組むのが移行とか刷新とか構築とかのテックリ的案件で、自ら調整やら調査を経て決断することが多く、立て続けにそれらに取り組む中で疲労が溜まったからかなという見立て。
こういう決断って誰かに決めてもらえたら楽だが、現状だと誰かに期待できるものでもないし、迷ったり悩んだりしててもマジで意味なかったなと思った。やるべきなのは、ただ自律駆動で目標を撃破すること。
もちろん無印がそれに取り組んでるのも良くないので、そこは実態に沿うよう是正しよう(会社がどえらい儲かってたらなんぼでも請求したらいいけどそうじゃないのもこれまた気を遣わさせられる。我ながら優しい従業員)。&lt;/p&gt;
&lt;p&gt;私生活に於いては、今年は子どもが習い事始めたりで結構生活に時間の制限が増えて変化あったかも。
でもそれよりは 1 日 1 回の読書習慣付けとか自身に課した制約で時間に追われてる感じあったかも。
使う筋肉を最小限にした省力化に注力したらいいんかな。
過去の自分よりは絶対に充実してるけどまだまだ渇望してるので、もっと積んでいきたいところやねんよな～。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;まとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;新しい習慣も増えて良くできたなという気持ちはあれど、まだこなれてない感じはする。
もうちょい慣れて先述の通り呼吸をするようにサクサクこなせるようになりたい。
そうした後に更に目標の負荷も高めていきたいところ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Tue, 31 Dec 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-12-29-writing-cmdlet-in-fsharp-pt59.html</guid><link>https://krymtkts.github.io/posts/2024-12-29-writing-cmdlet-in-fsharp-pt59.html</link><title>F# で Cmdlet を書いてる pt.59</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;年内になんとか &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.18.0&quot; title=&quot;0.18.0&quot;&gt;0.18.0&lt;/a&gt; 、その bug 修正版の &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.18.1&quot; title=&quot;0.18.1&quot;&gt;0.18.1&lt;/a&gt; をリリースをできた。
&lt;a href=&quot;/posts/2024-12-22-writing-cmdlet-in-fsharp-pt58.html&quot; title=&quot;前回触れた以下の bug&quot;&gt;前回触れた以下の bug&lt;/a&gt; の対処が間に合って良かった。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/276&quot; title=&quot;#276&quot;&gt;#276&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;今のところただの query であれば問題ないのだけど、 property query だと指定した property が認識されてなくて絞り込めない bug がある。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;対象の絞り込みと描画が非同期に行われるため、 &lt;code&gt;-Query&lt;/code&gt; option を指定した pocof 起動直後の絞り込み時に選択可能な property の list が完成していないと property query が無効になる bug だった。
なので絞り込みのタイミングをずらすために、 query の絞り込みと property name の候補の結果を遅延評価するようにした。
F# なら &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/lazy-expressions&quot; title=&quot;Lazy Expressions&quot;&gt;Lazy Expressions&lt;/a&gt; で簡単に導入できる。
一点 &lt;code&gt;Entry seq&lt;/code&gt; の引数に &lt;code&gt;Entry pseq&lt;/code&gt; を取り回せていたところが、遅延評価にしたことで &lt;code&gt;Entry pseq Lazy&lt;/code&gt; と明示的な型の指定が必要になったのでそこだけ想定外だったか(理解不足かもしれんが元の制約が緩かっただけかな)。&lt;/p&gt;
&lt;p&gt;結果を得るタイミングを遅らせただけなので、実質的に根治策というよりある種の緩和策なところだけが懸念点か。
仕組み的に、ものすごく膨大な検索対象に複数の object が含まれていた場合、登場するのが遅い object の property はこれまで同様に起動直後の property query として無効になるだろう。
とはいえそんな膨大な検索対象の場合は &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.management.automation.cmdlet.processrecord?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;ProcessRecord&lt;/code&gt;&quot;&gt;&lt;code&gt;ProcessRecord&lt;/code&gt;&lt;/a&gt; 中の定期描画で救われるだろうから、大きく問題になることはない多分(心配なので今度試す)。&lt;/p&gt;
&lt;p&gt;遅延評価に切り替える過程で、 UI のリファクタも行った。
これは従来のレイアウトである &lt;code&gt;{prompt}&amp;gt;{query} {matcher} {operator} [{filter count}]&lt;/code&gt; だと遅延評価を組み込むのに支障があったためだ。
query window の幅を算出するのに &lt;code&gt;{query}&lt;/code&gt; 前後の &lt;code&gt;{prompt}&lt;/code&gt; と &lt;code&gt;{matcher} {operator} [{filter count}]&lt;/code&gt; の文字数を知る必要があったが、絞り込み件数を正格評価しないと &lt;code&gt;{filter count}&lt;/code&gt; の文字数を正しく算出できない。
遅延評価されても query window の幅算出に影響ないレイアウトであればよいので、解決策として 1 行ずらして notification 等を表示する行に &lt;code&gt;{matcher} {operator} {filter count}&lt;/code&gt; をずらした。
&lt;code&gt;{filter count}&lt;/code&gt; が膨大な検索対象がある場合のパフォ劣化の原因でもあるので消してもいいけど、個人的に良く見てる項目なので置いておきたかったというのもある。&lt;/p&gt;
&lt;p&gt;これが、&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt;:Name a                        match and [7]&lt;br /&gt;note&amp;gt;xxxxxx
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こうなった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt;:Name a&lt;br /&gt;note&amp;gt;xxxxxx                     match and [7]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;多少見た目悪い気もするがこれによって query window 幅の動的な計算が不要になり、今後の内部状態の設計もスッキリしそうなので、良いタイミングでの決定だったかなと。
ただ残念ながらこの &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.18.0&quot; title=&quot;0.18.0&quot;&gt;0.18.0&lt;/a&gt; のリリースで terminal 端っこにカーソルが位置したときに UI が崩壊する bug を仕込んしまったので、急遽直した。それが &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.18.1&quot; title=&quot;0.18.1&quot;&gt;0.18.1&lt;/a&gt; になった。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/281&quot; title=&quot;#281&quot;&gt;#281&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;うわ～あったなこの挙動と bug の原因に気づいてから思い出したのだけど、 &lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; なのか &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.console?view=net-9.0&quot; title=&quot;Console&quot;&gt;Console&lt;/a&gt; なのか何に由来する挙動か知らないが、行末端までカーソルが進むと改行して次の行に移るやつがあって、その影響っぽかった(忘れる前にこの現象についても調べておかな)。
行末にカーソル位置がなければ問題ではないので、現状 query window の幅を 1 文字縮めることで回避している。
自動で次の行に進んでしまうので、進んでから戻すよりも、進ませないのが手数を少なくするのを優先した対応としては正しいはず...多分。&lt;/p&gt;
&lt;p&gt;もうちょい事前にテスト出来てたら 100% 気づけた bug だが、現状手動テストしか出来ないところではあるし、中々難しおまんな。
ただ debug build でのみ有効な autopilot mode みたいなの作り込めたら E2E testing 改善の可能性あるか。
そうすれば理論的に PBT における stateful properties か state machine properties が書けるハズや。
&lt;a href=&quot;https://github.com/fscheck/FsCheck&quot; title=&quot;FsCheck&quot;&gt;FsCheck&lt;/a&gt; で &lt;a href=&quot;https://fscheck.github.io/FsCheck//StatefulTestingNew.html#Model-based-Testing-Experimental&quot; title=&quot;Model-based Testing&quot;&gt;Model-based Testing&lt;/a&gt; がそれに該当するはずやから試す価値はあるよな(まだ初歩的な generator しか使ってないし)。&lt;/p&gt;
&lt;p&gt;来年も pocof の開発することありそうな感じやな～。
やりたいことがいっぱいあるというのはいいことや。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 29 Dec 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-12-22-writing-cmdlet-in-fsharp-pt58.html</guid><link>https://krymtkts.github.io/posts/2024-12-22-writing-cmdlet-in-fsharp-pt58.html</link><title>F# で Cmdlet を書いてる pt.58</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;年末に次のリリースする。そのための修正をいくつかした。
リリースするするフラグが折れないようにするためにも後何を解消しないといけないか書いておく。&lt;/p&gt;
&lt;p&gt;1 つデカい破壊的な変更を入れた。
それは &lt;code&gt;Select-Pocof&lt;/code&gt; の parameter の &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_functions_advanced_parameters?view=powershell-7.4#position-argument&quot; title=&quot;&lt;code&gt;position=0&lt;/code&gt;&quot;&gt;&lt;code&gt;position=0&lt;/code&gt;&lt;/a&gt; を変えたことだ。
修正は軽微だがこれはデカい。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/268&quot; title=&quot;#268&quot;&gt;#268&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この変更により従来は &lt;code&gt;$datasource | pocof -Query nanigashi&lt;/code&gt; としなければならなかったところを、 parameter name を省略して &lt;code&gt;$datasource | pocof nanigashi&lt;/code&gt; とできるようにした。
もし pocof ユーザの方がいて pocof の &lt;code&gt;position=0&lt;/code&gt; だった &lt;code&gt;InputObject&lt;/code&gt; にフィルタリング対象のデータを渡している人がいたらすみません、以後 pipeline で渡してください。
破壊的変更なのでテストに影響あるかなーと思ったが影響なかったので問題ない認識。&lt;/p&gt;
&lt;p&gt;この変更は、絞りたいキーワードが分かりきっててパパッと確認したいときなんかはやはり type 数が少ない方が良いよなという判断だ。
今のところただの query であれば問題ないのだけど、 property query だと指定した property が認識されてなくて絞り込めない bug がある。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# NG&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 多分 property の Map 構築が間に合ってないか構築後の再描画に問題がある&lt;/span&gt;&lt;br /&gt;ll | pocof &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;:Name .github&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 単純な query はOK&lt;/span&gt;&lt;br /&gt;ll | pocof &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;.github&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# -NonInteractive は OK&lt;/span&gt;&lt;br /&gt;ll | pocof &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;.github&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NonInteractive&lt;/span&gt;&lt;br /&gt;ll | pocof &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;:Name .github&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NonInteractive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;非同期で処理してるためなので、過去にも似たような bug を直したがまだ直さないといけない箇所があるんやろなというお気持ち。
早く直してリリースしたい。
調査が億劫なので、他の repo の開発をしてたりして着手してない。&lt;/p&gt;
&lt;p&gt;また別の話ではあるが、喜ばしことに人生で初めて自分の repo にプルリクをいただいた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/270&quot; title=&quot;#290&quot;&gt;#290&lt;/a&gt; 嬉しい限りである。
ｳｪｰｲって投げつける側は割と誰でもなれると思うが、もらう側になったのは初めてだったので良い経験になった。&lt;/p&gt;
&lt;p&gt;GitHub の README 仕様の知らないところを教えていただいたところもあってこれまたありがたい。
みんな &lt;code&gt;README.md&lt;/code&gt; から repo 内の別の文書へのリンクは相対パスで書くんやなと知った。&lt;/p&gt;
&lt;p&gt;また external contributor から PR もらったときの GitHub Actions の挙動のチェック甘かったところもあぶり出され、ほんとありがたい限り。
エラーを起こしてしまった申し訳ない感じではあるが。
この機会に Codecov は token なしでも coverage を upload できる機能があるのを知った。
そして Snyk は token なしだと単にエラーになる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.codecov.com/docs/codecov-tokens#uploading-without-a-token&quot; title=&quot;Uploading without a token - Codecov Tokens&quot;&gt;Uploading without a token - Codecov Tokens&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/snyk/actions&quot; title=&quot;snyk/actions: A set of GitHub actions for checking your projects for vulnerabilities&quot;&gt;snyk/actions: A set of GitHub actions for checking your projects for vulnerabilities&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;blockquote&gt;
&lt;p&gt;Note that GitHub Actions will not pass on secrets set in the repository to forks being used in pull requests, and so the Snyk actions that require the token will fail to run.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;今年も残すところわずかなので、件の課題に年末中に着手し、解決したい、というかしなければならない。
来週には今年の振り返りをしたいし。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 22 Dec 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-12-15-writing-cmdlet-in-fsharp-pt57.html</guid><link>https://krymtkts.github.io/posts/2024-12-15-writing-cmdlet-in-fsharp-pt57.html</link><title>F# で Cmdlet を書いてる pt.57 - PlatyPS v1 preview の bug</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;PlatyPS についていくつか覚え書きしておくのと、 .NET 9 及び F# 9 対応に進展がありひとまず PR を merge できた。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/Microsoft.PowerShell.PlatyPS/1.0.0-preview1&quot; title=&quot;PlatyPS の v1 の preview&quot;&gt;PlatyPS の v1 の preview&lt;/a&gt; の挙動に関してメモしておく。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;あと地味に Markdown の table が MAML 翻訳されない bug も直ってるようなので、コレを気に pocof の help も多少綺麗にできるかな。
&lt;a href=&quot;https://github.com/PowerShell/platyPS/issues/577&quot; title=&quot;Markdown tables not rendered properly in MAML · Issue #577 · PowerShell/platyPS&quot;&gt;Markdown tables not rendered properly in MAML · Issue #577 · PowerShell/platyPS&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-12-08-writing-cmdlet-in-fsharp-pt56.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;触れたこれ、直ってるっぽいけどその確認の過程で変なエラーに遭遇した。
再現条件がイマイチ分からなかったが、&lt;code&gt;Export-MamlCommandHelp&lt;/code&gt; で必ず壊れた MAML が出力されるようだった。
壊れた MAML を &lt;code&gt;Show-HelpPreview&lt;/code&gt; するとわかりやすくエラーになる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Show-HelpPreview&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; .\src\pocof\pocof&lt;span class=&quot;hljs-literal&quot;&gt;-Help&lt;/span&gt;.xml&lt;br /&gt;InvalidArgument: Cannot convert value &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;lt;?xml version=&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; encoding=&amp;quot;&lt;/span&gt;utf&lt;span class=&quot;hljs-literal&quot;&gt;-8&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;?&amp;gt; &amp;lt;helpItems xmlns:maml=&amp;quot;&lt;/span&gt;http://schemas.microsoft.com/maml&lt;br /&gt;... &amp;lt;/helpItems&amp;gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; to type &amp;quot;&lt;/span&gt;System.Xml.XmlDocument&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;. Error: &amp;quot;&lt;/span&gt;The specified node cannot be inserted as the valid child of this node, because the specified node is the wrong &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt;.&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;pocof でこのエラーが発生した場面は、元々 Markdown の table が使えなかったので code block (&lt;code&gt;```md&lt;/code&gt; ~ &lt;code&gt;```&lt;/code&gt;)で囲んでいた箇所を通常の Markdown に戻したあとだった。
pocof の Markdown command help は scheme 更新した関係で &lt;code&gt;Locale: en-US&lt;/code&gt; や &lt;code&gt;title: ...&lt;/code&gt; が生えてなかったのだけど、これらの不足した属性がエラーとは関係ないのは確認した(あってもなくてもエラーになる)。
このとき MAML 最後尾の tag が重複して出力されていた。以下のような感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;   &amp;lt;/command:command&amp;gt;&lt;br /&gt; &amp;lt;/helpItems&amp;gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+  &amp;lt;/command:command&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&amp;lt;/helpItems&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;MAML command help を出力するコマンドは以下の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Measure-PlatyPSMarkdown&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; ./docs/pocof/*.md | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; Filetype &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; CommandHelp | &lt;span class=&quot;hljs-built_in&quot;&gt;Import-MarkdownCommandHelp&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FilePath} | &lt;span class=&quot;hljs-built_in&quot;&gt;Export-MamlCommandHelp&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-OutputFolder&lt;/span&gt; .\src\ &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;1 つわかったのは、エラーを回避するには出力済みの MAML command help を物理的に削除して、再度出力し直す必要があったことだ。
つまり &lt;code&gt;-Force&lt;/code&gt; option 付きでの上書きの問題があるっぽい？何にせよ workaround があってよかった。
どうにもよくわからんが &lt;code&gt;Export-MamlCommandHelp&lt;/code&gt; が不正な XML を出力する issue もあるしその関連かなあ。 &lt;a href=&quot;https://github.com/PowerShell/platyPS/issues/692&quot; title=&quot;OPS13 Export-MamlCommandHelp creates invalid XML · Issue #692 · PowerShell/platyPS&quot;&gt;OPS13 Export-MamlCommandHelp creates invalid XML · Issue #692 · PowerShell/platyPS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;他に、 &lt;code&gt;INPUT&lt;/code&gt; &lt;code&gt;OUTPUT&lt;/code&gt; の section は code を使ってると &lt;code&gt;Markdig.Syntax.Inlines.CodeInline&lt;/code&gt; が出力されてしまう。
そうなると繰り返し &lt;code&gt;Update-MarkdownCommandHelp&lt;/code&gt; を実行したとき冪等性がないっぽくて、 section が無限増殖してしまう。
workaround としては code を section に使わなければ良い。&lt;/p&gt;
&lt;p&gt;最後に、 pipeline で使いにくい件は &lt;code&gt;Path&lt;/code&gt; に Alias なりついてりゃいいよなと思ってるのだけど、 &lt;code&gt;Path&lt;/code&gt; parameter 周りでなんか改善の予定あるみたいだしそん時に前提的に見直されたりするのかも？様子見。
&lt;a href=&quot;https://github.com/PowerShell/platyPS/issues/696&quot; title=&quot;Make Path and LiteralPath parameters work like they do for Item cmdlets · Issue #696 · PowerShell/platyPS&quot;&gt;Make Path and LiteralPath parameters work like they do for Item cmdlets · Issue #696 · PowerShell/platyPS&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと .NET 9 及び F# 9 対応に進展があり、ついに PR を merge できた。やったね。&lt;/p&gt;
&lt;p&gt;取り敢えず残された課題のうち、最低限 &lt;a href=&quot;https://github.com/fsprojects/fantomas&quot; title=&quot;Fantomas&quot;&gt;Fantomas&lt;/a&gt; が対応できたら merge しようと考えてた。
でも format できないわ～参ったね... と思って &lt;a href=&quot;https://github.com/fsprojects/fantomas/issues/3142&quot; title=&quot;issue を立てた&quot;&gt;issue を立てた&lt;/a&gt;のだけど、実は &lt;a href=&quot;https://www.nuget.org/packages/fantomas/7.0.0-alpha-003&quot; title=&quot;preview&quot;&gt;preview&lt;/a&gt; リリースで対応していましたという話だった。
メンテナの人達は忙しかろうから一瞬 Issue を立てて迷惑やったな...と思ったが、立てるまでその preview リリースに気づいてなかったのもあり、結果的に解決に至れたのでヨシッ！とした。
副次的に Fantomas の online で&lt;a href=&quot;https://fsprojects.github.io/fantomas-tools/#/fantomas/preview&quot; title=&quot;最新の preview が使える&quot;&gt;最新の preview が使える&lt;/a&gt;(Setting で変えれる)のも知ったし、 .NET 9 対応の流れも知れた。&lt;/p&gt;
&lt;p&gt;もうそろそろ pocof の今年最後のリリースしても良さそうな感じになってきた。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 15 Dec 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-12-08-writing-cmdlet-in-fsharp-pt56.html</guid><link>https://krymtkts.github.io/posts/2024-12-08-writing-cmdlet-in-fsharp-pt56.html</link><title>F# で Cmdlet を書いてる pt.56 - PlatyPS v1 preview</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;まだ &lt;a href=&quot;https://fscheck.github.io/FsCheck/index.html&quot; title=&quot;FsCheck&quot;&gt;FsCheck&lt;/a&gt; を使った既存の事例テストを PBT で置き換えてる最中。
なるべくシンプルなプロパティにして、ジェネレータでいろんなパターンを書くような感じで今は上手くハマっている。
今はまだ簡単な関数に対するプロパティしか書いてないので、もうそろそろ難易度上げても良い頃合いかも。&lt;/p&gt;
&lt;p&gt;.NET 9 のやつも放置状態。 FSharpLint の .NET 9 の問題は issue ができてた。 &lt;a href=&quot;https://github.com/fsprojects/FSharpLint/issues/718&quot; title=&quot;Latest version incompatible with .NET 9 · Issue #718 · fsprojects/FSharpLint&quot;&gt;Latest version incompatible with .NET 9 · Issue #718 · fsprojects/FSharpLint&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;他に新しいネタとしては、 2024-10-30 に dev blog に出てた &lt;a href=&quot;https://www.powershellgallery.com/packages/Microsoft.PowerShell.PlatyPS/1.0.0-preview1&quot; title=&quot;PlatyPS の v1 の preview&quot;&gt;PlatyPS の v1 の preview&lt;/a&gt; へ移行始めてみた。
調べた内容を整理する意味も込めてまとめておく。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devblogs.microsoft.com/powershell/announcing-platyps-100-preview1/&quot; title=&quot;Announcing Microsoft.PowerShell.PlatyPS 1.0.0-Preview1 - PowerShell Team&quot;&gt;Announcing Microsoft.PowerShell.PlatyPS 1.0.0-Preview1 - PowerShell Team&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;まだ preview なので PlatyPS のチュートリアルは更新されてない。 &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/utility-modules/platyps/create-help-using-platyps?view=ps-modules&quot; title=&quot;Create XML-based help using PlatyPS - PowerShell | Microsoft Learn&quot;&gt;Create XML-based help using PlatyPS - PowerShell | Microsoft Learn&lt;/a&gt;
install は先に挙げた dev blog に従ってやる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Install-PSResource&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; Microsoft.PowerShell.PlatyPS &lt;span class=&quot;hljs-literal&quot;&gt;-Prerelease&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; AllUsers
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-PSResource&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; platyPS,Microsoft.PowerShell.PlatyPS &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; AllUsers | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; Name,Version,PublishedDate&lt;br /&gt;&lt;br /&gt;Name                         Version PublishedDate&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                         &lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-------------&lt;/span&gt;&lt;br /&gt;platyPS                      &lt;span class=&quot;hljs-number&quot;&gt;0.14&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;  &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-07-02&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;53&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;28&lt;/span&gt;&lt;br /&gt;Microsoft.PowerShell.PlatyPS &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;   &lt;span class=&quot;hljs-number&quot;&gt;2024&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-10-29&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;38&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;53&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;実に 3 年ぶりの更新になる様子。 &lt;a href=&quot;/posts/2022-05-07-start-to-write-cmdlet-by-fsharp.html&quot; title=&quot;pocof を作り始めたとき&quot;&gt;pocof を作り始めたとき&lt;/a&gt;から v0.14.2 を使ってた。
module name も変わった。 &lt;code&gt;PowerShellGet&lt;/code&gt; が &lt;code&gt;PSResourceGet&lt;/code&gt; になったのと同じ命名規則なので、 PowerShell Team の module は将来皆こうなるんかな。&lt;/p&gt;
&lt;p&gt;module に含まれる Function, Cmdlet は随分様変わりした。コレはなるほど使い方がわからん。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Command&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Module&lt;/span&gt; platyPS&lt;br /&gt;&lt;br /&gt;CommandType     Name                                               Version    Source&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-----------&lt;/span&gt;     &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                                               &lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;    &lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;Get-HelpPreview&lt;/span&gt;                                    &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;14&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;2&lt;/span&gt;     &lt;span class=&quot;hljs-title&quot;&gt;platyPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;Get-MarkdownMetadata&lt;/span&gt;                               &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;14&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;2&lt;/span&gt;     &lt;span class=&quot;hljs-title&quot;&gt;platyPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;Merge-MarkdownHelp&lt;/span&gt;                                 &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;14&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;2&lt;/span&gt;     &lt;span class=&quot;hljs-title&quot;&gt;platyPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;New-ExternalHelp&lt;/span&gt;                                   &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;14&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;2&lt;/span&gt;     &lt;span class=&quot;hljs-title&quot;&gt;platyPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;New-ExternalHelpCab&lt;/span&gt;                                &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;14&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;2&lt;/span&gt;     &lt;span class=&quot;hljs-title&quot;&gt;platyPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;New-MarkdownAboutHelp&lt;/span&gt;                              &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;14&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;2&lt;/span&gt;     &lt;span class=&quot;hljs-title&quot;&gt;platyPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;New-MarkdownHelp&lt;/span&gt;                                   &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;14&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;2&lt;/span&gt;     &lt;span class=&quot;hljs-title&quot;&gt;platyPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;New-YamlHelp&lt;/span&gt;                                       &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;14&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;2&lt;/span&gt;     &lt;span class=&quot;hljs-title&quot;&gt;platyPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;Update-MarkdownHelp&lt;/span&gt;                                &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;14&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;2&lt;/span&gt;     &lt;span class=&quot;hljs-title&quot;&gt;platyPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;Update-MarkdownHelpModule&lt;/span&gt;                          &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;14&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;2&lt;/span&gt;     &lt;span class=&quot;hljs-title&quot;&gt;platyPS&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Command&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Module&lt;/span&gt; Microsoft.PowerShell.PlatyPS&lt;br /&gt;&lt;br /&gt;CommandType     Name                                               Version    Source&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-----------&lt;/span&gt;     &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                                               &lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;    &lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;New-HelpCabinetFile&lt;/span&gt;                                &lt;span class=&quot;hljs-title&quot;&gt;1&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;      &lt;span class=&quot;hljs-title&quot;&gt;Microsoft&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;PowerShell&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;PlatyPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;Show-HelpPreview&lt;/span&gt;                                   &lt;span class=&quot;hljs-title&quot;&gt;1&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;      &lt;span class=&quot;hljs-title&quot;&gt;Microsoft&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;PowerShell&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;PlatyPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Compare-CommandHelp&lt;/span&gt;                                &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Export-MamlCommandHelp&lt;/span&gt;                             &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Export-MarkdownCommandHelp&lt;/span&gt;                         &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Export-MarkdownModuleFile&lt;/span&gt;                          &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Export-YamlCommandHelp&lt;/span&gt;                             &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Export-YamlModuleFile&lt;/span&gt;                              &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Import-MamlHelp&lt;/span&gt;                                    &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Import-MarkdownCommandHelp&lt;/span&gt;                         &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Import-MarkdownModuleFile&lt;/span&gt;                          &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Import-YamlCommandHelp&lt;/span&gt;                             &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Import-YamlModuleFile&lt;/span&gt;                              &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Measure-PlatyPSMarkdown&lt;/span&gt;                            &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;New-CommandHelp&lt;/span&gt;                                    &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;New-MarkdownCommandHelp&lt;/span&gt;                            &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;New-MarkdownModuleFile&lt;/span&gt;                             &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Test-MarkdownCommandHelp&lt;/span&gt;                           &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Update-CommandHelp&lt;/span&gt;                                 &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Update-MarkdownCommandHelp&lt;/span&gt;                         &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS&lt;br /&gt;Cmdlet          &lt;span class=&quot;hljs-built_in&quot;&gt;Update-MarkdownModuleFile&lt;/span&gt;                          &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;      Microsoft.PowerShell.PlatyPS
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;PlatyPS の reference は更新されてるので、そこを参考に手で試しながら理解するしかないか。
&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/?view=ps-modules&quot; title=&quot;Microsoft.PowerShell.PlatyPS Module - PowerShell | Microsoft Learn&quot;&gt;Microsoft.PowerShell.PlatyPS Module - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;pocof の用途だと「既存の help をイイ感じに更新したい」ところなので、その周りの機能を確認する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/measure-platypsmarkdown?view=ps-modules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Markdown help が含む content type と schema version を検証する&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Filetype が enum なので stringify された値に対して match しないと filter できない&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Output の path 属性が Filepath なので pipeline でそのまま渡しにくい&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 気が利いた機能だが出力が微妙に行けてなくて PlatyPS 内での取り回しが良くない&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Measure-PlatyPSMarkdown&lt;/span&gt; .\docs\*.md&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Title   Filetype              Filepath&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# -----   --------              --------&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# unknown CommandHelp, V1Schema C:\Users\takatoshi\dev\github.com\krymtkts\pocof\docs\Select-Pocof.md&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/test-markdowncommandhelp?view=ps-modules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Markdown command help の内容を検査する&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Measure-PlatyPSMarkdown&lt;/span&gt; .\docs\*.md | ? Filetype &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; CommandHelp | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; FilePath | &lt;span class=&quot;hljs-built_in&quot;&gt;Test-MarkdownCommandHelp&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-DetailView&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Test-MarkdownCommandHelp&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   Valid: True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   File: C:\Users\takatoshi\dev\github.com\krymtkts\pocof\docs\Select-Pocof.md&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Messages:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: First element is a thematic break&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: SYNOPSIS found.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: SYNOPSIS is in order.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: SYNTAX found.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: SYNTAX is in order.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: DESCRIPTION found.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: DESCRIPTION is in order.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: EXAMPLES found.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: EXAMPLES is in order.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: PARAMETERS found.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: PARAMETERS is in order.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: INPUTS found.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: INPUTS is in order.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: OUTPUTS found.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: OUTPUTS is in order.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: NOTES found.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: NOTES is in order.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: RELATED LINKS found.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   PASS: RELATED LINKS is in order.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/import-markdowncommandhelp?view=ps-modules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Markdown command help を読み込んで command help の object を作る&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$before&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Measure-PlatyPSMarkdown&lt;/span&gt; .\docs\*.md | ? Filetype &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; CommandHelp | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; FilePath | &lt;span class=&quot;hljs-built_in&quot;&gt;Import-MarkdownCommandHelp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/update-commandhelp?view=ps-modules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# command help object を session に存在する同名 cmdlet の情報で更新する&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$after&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Measure-PlatyPSMarkdown&lt;/span&gt; .\docs\*.md | ? Filetype &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; CommandHelp | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; FilePath | &lt;span class=&quot;hljs-built_in&quot;&gt;Update-CommandHelp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/compare-commandhelp?view=ps-modules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# command help object 同士を比較した text を出力する&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 出力される text が D=delete, M=modified, S=same ぽいので適宜 filter しないといけない&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Compare-CommandHelp&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$before&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$after&lt;/span&gt; | ? {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-notlike&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;S*&amp;#x27;&lt;/span&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# M Inspecting dictionary CommandHelp.Metadata&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# D   CommandHelp.Metadata: ms.date does not exist in reference&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# M Inspecting list CommandHelp.Syntax&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# D CommandHelp.Syntax lists are different sizes (1 vs 2)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 省略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/export-markdowncommandhelp?view=ps-modules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# command help object を Markdown command help に出力する&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# OutputFolder 配下に module name で directory が作成されてその中に出力される&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# module name の directory 作らず平置きしてる場合は注意&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$after&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Export-MarkdownCommandHelp&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-OutputFolder&lt;/span&gt; .\docs&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/update-markdowncommandhelp?view=ps-modules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Markdown command help を session に存在する同名 cmdlet の情報で更新する&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# デフォ *.bak ファイルを作ってくるので、 -NoBackup を指定すると作らなくなる&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# description とか example に手で書いた内容は消えないので気軽に実行できる&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Measure-PlatyPSMarkdown&lt;/span&gt; .\docs\*.md | ? Filetype &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; CommandHelp | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; FilePath | &lt;span class=&quot;hljs-built_in&quot;&gt;Update-MarkdownCommandHelp&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NoBackup&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/export-mamlcommandhelp?view=ps-modules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# OutputFolder 配下に module name で directory が作成されてその中に `${moduleName}-Help.xml` 出力される&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Measure-PlatyPSMarkdown&lt;/span&gt; .\docs\*.md | ? Filetype &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; CommandHelp | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; FilePath | &lt;span class=&quot;hljs-built_in&quot;&gt;Import-MarkdownCommandHelp&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Export-MamlCommandHelp&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-OutputFolder&lt;/span&gt; ./src/&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.platyps/show-helppreview?view=ps-modules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 出力した MAML を Markdown preview する。何故かこいつは Path が Position 0 じゃなく Named なので注意&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Show-HelpPreview&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; .\src\pocof\pocof&lt;span class=&quot;hljs-literal&quot;&gt;-Help&lt;/span&gt;.xml&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 省略&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;Measure-PlatyPSMarkdown&lt;/code&gt; の output の object が pipeline で使いにくいのだけ気に入らんが、他は良好な使用感そう。&lt;/p&gt;
&lt;p&gt;pocof の古いドキュメントを更新するにあたってやるべきことも見えてきた。
&lt;code&gt;Update-MarkdownCommandHelp&lt;/code&gt; を 0.14.2 で作った Markdown command help に対して実行すると scheme の version が 1 -&amp;gt; 2 になって結構変わるので、初回は scheme の更新のみで実行する方が良さそう。
&lt;code&gt;OutputFolder&lt;/code&gt; 配下に module name の directory ができるのもあるし、出力されるファイル名が変わるのもあるし、まずは今の構造を変えるのが良さげやな。&lt;/p&gt;
&lt;p&gt;あと地味に Markdown の table が MAML 翻訳されない bug も直ってるようなので、コレを気に pocof の help も多少綺麗にできるかな。
&lt;a href=&quot;https://github.com/PowerShell/platyPS/issues/577&quot; title=&quot;Markdown tables not rendered properly in MAML · Issue #577 · PowerShell/platyPS&quot;&gt;Markdown tables not rendered properly in MAML · Issue #577 · PowerShell/platyPS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 08 Dec 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-12-01-writing-cmdlet-in-fsharp-pt55.html</guid><link>https://krymtkts.github.io/posts/2024-12-01-writing-cmdlet-in-fsharp-pt55.html</link><title>F# で Cmdlet を書いてる pt.55 - FsCheck</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;.NET 9 への更新は &lt;a href=&quot;https://github.com/ionide/ionide-vscode-fsharp/issues/2048&quot; title=&quot;Ionide が .NET 9 に対応&quot;&gt;Ionide が .NET 9 に対応&lt;/a&gt;して 1 つ課題が解消された。
あと &lt;a href=&quot;https://github.com/dotnet/sdk/issues/44838&quot; title=&quot;.NET 9 SDK の bug&quot;&gt;.NET 9 SDK の bug&lt;/a&gt; の影響で &lt;a href=&quot;https://github.com/fsprojects/fantomas&quot; title=&quot;Fantomas&quot;&gt;Fantomas&lt;/a&gt; が動かないやつが解消されたら最低限 OK かなと。
&lt;a href=&quot;https://github.com/fsprojects/FSharpLint&quot; title=&quot;FSharpLint&quot;&gt;FSharpLint&lt;/a&gt; が動かなくなったやつはどうにもならなそうなので何かできることがないか長期的に模索しようと考えている。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;さて、その間に他の開発が止まるのもイマイチなので、新しい取り組みとして &lt;a href=&quot;https://fscheck.github.io/FsCheck/index.html&quot; title=&quot;FsCheck&quot;&gt;FsCheck&lt;/a&gt; の利用を始めてみた。
&lt;a href=&quot;/booklogs/property-based-testing.html&quot; title=&quot;最近 PBT の本を読んでる&quot;&gt;最近 PBT の本を読んでる&lt;/a&gt;ことで感覚が培われてきたような気がするので、多分機は熟している。
初回の対応は従来のテストケースの置き換え。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/264&quot; title=&quot;#264&quot;&gt;#264&lt;/a&gt;
あまり PBT しても意味ないようなケースだが、欲しい型のジェネレータを自分で書く辺りは良い練習になるかなと思って試した。&lt;/p&gt;
&lt;p&gt;リヨウしている FsCheck の version は &lt;a href=&quot;https://www.nuget.org/packages/FsCheck/3.0.0-rc3&quot; title=&quot;3.0.0-rc&quot;&gt;3.0.0-rc&lt;/a&gt; 。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Xunit&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; FsUnitTyped&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; FsCheck.FSharp&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; FsCheck.Xunit&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; unwrap &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System.Collections&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System.Management.Automation&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; psObjectGen &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        ArbMap.defaults&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; ArbMap.generate&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Gen.map (PSObject.AsPSObject &lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; Entry.Obj)&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; dictionaryEntryGen &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        ArbMap.defaults&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; ArbMap.generate&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Gen.two&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Gen.map (DictionaryEntry &lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; Entry.Dict)&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;EntryPSObject&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; Double() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; psObjectGen &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Arb.fromGen&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Property(Arbitrary = [| typeof&amp;lt;EntryPSObject&amp;gt; |], EndSize = &lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;)&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``should return PSObject sequence.``&lt;/span&gt; (data&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Entry &lt;span class=&quot;hljs-type&quot;&gt;list&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        data&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; unwrap&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.ofSeq&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; shouldEqual (&lt;br /&gt;            data&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.map (&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Entry.Obj x &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; x&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;failwith&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Dict is unreachable&amp;quot;&lt;/span&gt;)&lt;br /&gt;        )&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Prop.collect (List.length data)&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;EntryDictionaryEntry&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; Double() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; dictionaryEntryGen &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Arb.fromGen&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;MixedEntry&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; Generate() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            Gen.oneof [ psObjectGen; dictionaryEntryGen ] &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Gen.listOf &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Arb.fromGen&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Property(Arbitrary = [| typeof&amp;lt;MixedEntry&amp;gt; |], EndSize = &lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;)&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``should return mixed sequence.``&lt;/span&gt; (data&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Entry &lt;span class=&quot;hljs-type&quot;&gt;list&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        data&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; unwrap&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.ofSeq&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; shouldEqual (&lt;br /&gt;            data&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.map (&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Entry.Obj x &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; x&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Entry.Dict x &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; x)&lt;br /&gt;        )&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Prop.collect (&lt;br /&gt;            List.length data,&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;TODO:&lt;/span&gt; use .Is* after bumping to F# 9.&lt;/span&gt;&lt;br /&gt;            data&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.filter (&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Entry.Obj _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;)&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.length,&lt;br /&gt;            data&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.filter (&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Entry.Dict _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;)&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.length&lt;br /&gt;        )
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Xunit, FsUnit, FsCheck が滑らかに統合されておりいい感じ。まだ解像度高くないから今後高まったときに気になる点とか出てくるかもしれんな。
手を動かしてみていくつか覚えたことをまとめておく。
概ね公式文書の焼き直しだが、動かしてみてわかった点もある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fscheck.github.io/FsCheck/RunningTests.html#Using-FsCheck-Xunit&quot; title=&quot;Using FsCheck.Xunit - Running tests&quot;&gt;Using FsCheck.Xunit - Running tests&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;xUnit を利用している場合は &lt;code&gt;FsCheck.Xunit&lt;/code&gt; にある &lt;code&gt;PropertyAttribute&lt;/code&gt; を使うと、従来のテストケースと FsCheck のテストケースが滑らかに繋がって良い&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Arbitrary&lt;/code&gt; instance の上書きを使うとケース、 class, module, assembly 毎にジェネレータを設定できる。ケース以外に設置する場合は &lt;code&gt;PropertiesAttribute&lt;/code&gt; を使う&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;Arbitrary&lt;/code&gt; instance の &lt;code&gt;Arbitrary&amp;lt;&amp;#39;Value&amp;gt;&lt;/code&gt; を返す static method の名前は何でもいいみたい&lt;ul&gt;
&lt;li&gt;今回の実装では先 2 つのジェネレータがコピペ元のママ &lt;code&gt;Double&lt;/code&gt; になってて、その後書き加えたジェネレータで &lt;code&gt;Generate&lt;/code&gt; にしても問題なく動くいてるので reflection で拾ってきてるぽい(実装はまだ追えてない)&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;PBT 本で学んだ通り統計情報を出しておいた方がどのようなテストが行われたか可視化出来て良い(ただしログは汚れる)。 FsCheck では &lt;code&gt;Prop.collect&lt;/code&gt; で出せる&lt;/li&gt;&lt;li&gt;&lt;code&gt;PSObject&lt;/code&gt; &lt;code&gt;DictionaryEntry&lt;/code&gt; を &lt;code&gt;ArbMap.generate&lt;/code&gt; で直に生成できないので &lt;code&gt;ArbMap.generate&amp;lt;string&amp;gt;&lt;/code&gt; で生成したデータを詰めれば良い&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;当面はステートレスプロパティでの置き換えを先にやってみて、次にステートフルプロパティ、多分 FsCheck で言うところの &lt;a href=&quot;https://fscheck.github.io/FsCheck//StatefulTestingNew.html&quot; title=&quot;Model-based Testing&quot;&gt;Model-based Testing&lt;/a&gt; に手を出そうかと考えている。&lt;/p&gt;
&lt;p&gt;公式文書にもあるが、内容が 3.x に追随してないらしくて、唯一 API docs が最新を反映されてる状態らしい。 API docs 見て感覚つかめる人ならそれで学んで、わたしのようによくわからんなーとなってしまう人なら docs 見つつ直にコード書いて試すのが良さそう。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 01 Dec 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-11-24-writing-cmdlet-in-fsharp-pt54.html</guid><link>https://krymtkts.github.io/posts/2024-11-24-writing-cmdlet-in-fsharp-pt54.html</link><title>F# で Cmdlet を書いてる pt.54 - .NET 9</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;.NET 9 に更新してみた。
結論から言うと 2024-11-24 時点ではなかなか厳しいなという感触だった。
ということで一旦寝かせて状況を見る。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;詰まってるのは以下の課題。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dotnet fsharplint lint&lt;/code&gt; が遂にどうにも動かなくなった。&lt;/li&gt;&lt;li&gt;.NET 9 SDK の bug の影響で &lt;code&gt;fantomas&lt;/code&gt; がコケる&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/sdk/issues/44838&quot; title=&quot;dotnet list package --vulnerable throws ArgumentException: &amp;#39;&amp;#39; is not a valid version string [.NET 9] · Issue #44838 · dotnet/sdk&quot;&gt;dotnet list package --vulnerable throws ArgumentException: &amp;#39;&amp;#39; is not a valid version string [.NET 9] · Issue #44838 · dotnet/sdk&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;Ionide は .NET 9 未対応&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ionide/ionide-vscode-fsharp/issues/2048&quot; title=&quot;Update FSAC used in Ionide to the 9.0.100 version · Issue #2048 · ionide/ionide-vscode-fsharp&quot;&gt;Update FSAC used in Ionide to the 9.0.100 version · Issue #2048 · ionide/ionide-vscode-fsharp&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;もともと fsharplint のやつは &lt;a href=&quot;https://github.com/fsprojects/FSharpLint/issues/687&quot; title=&quot;Execution fails when using dotnet 7.x or 8.x to target net6.0 project · Issue #687 · fsprojects/FSharpLint&quot;&gt;Execution fails when using dotnet 7.x or 8.x to target net6.0 project · Issue #687 · fsprojects/FSharpLint&lt;/a&gt; という課題にぶち当たってて、 0.24.2 を使えば回避できるのでそうしてた。
ただ .NET 9 になってエラーが出るようになって遂にどうにもならなくなった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; dotnet fsharplint lint pocof.sln&lt;br /&gt;Lint failed to parse files. Failed with: Aborted &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; check.&lt;br /&gt;Aborted &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; check.&lt;br /&gt;Aborted &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; check.&lt;br /&gt;(略)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最新の &lt;a href=&quot;https://www.nuget.org/packages/dotnet-fsharplint/0.24.2&quot; title=&quot;0.24.2&quot;&gt;0.24.2&lt;/a&gt; とか &lt;a href=&quot;https://www.nuget.org/packages/dotnet-fsharplint/0.24.3--date20240609-0921.git-873d145&quot; title=&quot;0.24.3 の preview&quot;&gt;0.24.3 の preview&lt;/a&gt; に変えてみても issue と同じ既知のエラーが出るのみ。
このエラーは fsharplint が .NET 6 を target framework にしてて、利用してるプロジェクトがそれより高い .NET 8 とかを利用してることに起因するらしいのだけど、よくわかってない。
プロジェクトに dotnet tool を入れてるとそのプロジェクトの .NET SDK で動く仕組みに問題があるんじゃないのみたいな話もあるようだけど、恐らくその仕組み自体は変わらんだろうしツールの提供側で前方・後方互換性を維持するしかないような感じはするな。&lt;/p&gt;
&lt;p&gt;.NET SDK と Ionide ののやつは時が経てばコミュニティが解決してくれそうやけど、 fsharplint のはどうやろな。 .NET 6 は EOL したし target framework が変わればなにか改善できるのかもしらんけど。他力本願じゃなくコントリして直せよって話かも知れんが。&lt;/p&gt;
&lt;p&gt;話は変わって言語機能的なところでいうと、 pocof は以下を使えたので利用してみた。
良さげ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#nullable-reference-types&quot; title=&quot;Nullable reference types&quot;&gt;Nullable reference types&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#partial-active-patterns-can-return-bool-instead-of-unit-option&quot; title=&quot;Partial active patterns can return &lt;code&gt;bool&lt;/code&gt; instead of &lt;code&gt;unit option&lt;/code&gt;&quot;&gt;Partial active patterns can return &lt;code&gt;bool&lt;/code&gt; instead of &lt;code&gt;unit option&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;ただ先述の通り、まだ Ionide が対応してない。ビルドは成功するけど VS Code 上ではエラーになる状態で、これはちょっと開発しにくい。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 24 Nov 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-11-17-writing-cmdlet-in-fsharp-pt53.html</guid><link>https://krymtkts.github.io/posts/2024-11-17-writing-cmdlet-in-fsharp-pt53.html</link><title>F# で Cmdlet を書いてる pt.53</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;その前に、毎年恒例 .NET の新しい major が出ましたな。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9&quot; title=&quot;What&amp;#39;s new in F# 9 - F# Guide - .NET | Microsoft Learn&quot;&gt;What&amp;#39;s new in F# 9 - F# Guide - .NET | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nullable reference がでかいのかな。 リリース後ブログになってたし。 &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/nullable-reference-types-in-fsharp-9/&quot; title=&quot;Nullable Reference Types in F# 9 - .NET Blog&quot;&gt;Nullable Reference Types in F# 9 - .NET Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;個人的には &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#enforce-attribute-targets&quot; title=&quot;Enforce attribute targets&quot;&gt;Enforce attribute targets&lt;/a&gt; はよく間違うのでありがたそう。&lt;/p&gt;
&lt;p&gt;pocof 的には &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#optimized-equality-checks&quot; title=&quot;Optimized equality checks&quot;&gt;Optimized equality checks&lt;/a&gt; &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#field-sharing-for-struct-discriminated-unions&quot; title=&quot;Field sharing for struct discriminated unions&quot;&gt;Field sharing for struct discriminated unions&lt;/a&gt; あたりの IL の改善が効果でたらうれしいな。
equality の最適化は半年ほど前ブログにもなってて、すご...と思ったやつだ。 &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/fsharp-developer-stories-how-weve-finally-fixed-a-9yearold-performance-issue/&quot; title=&quot;F# developer stories: how we&amp;#39;ve finally fixed a 9-year-old performance issue - .NET Blog&quot;&gt;F# developer stories: how we&amp;#39;ve finally fixed a 9-year-old performance issue - .NET Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/enhancing-help-in-fsi/&quot; title=&quot;Enhancing #help in F# Interactive - .NET Blog&quot;&gt;Enhancing #help in F# Interactive - .NET Blog&lt;/a&gt; もブログになってたやつ。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#extended-help-directive-in-fsi-to-show-documentation-in-the-repl&quot; title=&quot;Extended #help directive in fsi to show documentation in the REPL&quot;&gt;Extended #help directive in fsi to show documentation in the REPL&lt;/a&gt;
早速使ってみてる。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;先に .NET の最新リリースに触れたが、 pocof でも毎年恒例の .NET 更新をやりたいので、それに合わせて今着手中の開発を一区切りして &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.17.0&quot; title=&quot;0.17.0&quot;&gt;0.17.0&lt;/a&gt; でリリースした。&lt;/p&gt;
&lt;p&gt;含まれるのは、 word 操作。これは自分の日常使いで早速使い込む予定。
あとはキーに対応づいた操作の、内部コードのリファクタリングをしてた。
例えば、対称な処理が個別の実装になってるのを 1 つにまとめたり。
クエリ文字列を操作するあたりはまだゴチャついてて、もっとよくできる直感があるけど、リリースのために後回し。&lt;/p&gt;
&lt;p&gt;リリース自体は問題なくいったのだけど、リリース前に既存バグを見つけたので、リリース後にその対処をした。
ずっと気づいてなかったが、 pocof のいくつかの option に &lt;code&gt;$null&lt;/code&gt; を渡すと validation されてなくて &lt;code&gt;NullReferenceError&lt;/code&gt; が出たりしてたので、カッコ悪かった。
とりあえずこいつは直した。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/261&quot; title=&quot;#261&quot;&gt;#261&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;その過程で知ったのだけど、 &lt;code&gt;pocof&lt;/code&gt; の switch parameter に &lt;code&gt;$null&lt;/code&gt; を渡したら truthy な動作をするのよね。
なんとなく &lt;code&gt;$false&lt;/code&gt; が渡されたときみたいな挙動になるのかと思いきや、 &lt;code&gt;$true&lt;/code&gt; を渡されたような挙動になる。&lt;/p&gt;
&lt;p&gt;あんまり switch parameter に &lt;code&gt;$null&lt;/code&gt; を渡すような変なことしないようなので、以下の辺りがわたしが探してることに近そうかな...という感じはしてるが、まだよくわかってない。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PowerShell/PowerShell/issues/16852&quot; title=&quot;Reconcile -Switch:$false parameter invocation with parameter set resolution · Issue #16852 · PowerShell/PowerShell&quot;&gt;Reconcile -Switch:$false parameter invocation with parameter set resolution · Issue #16852 · PowerShell/PowerShell&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://keithga.wordpress.com/2017/10/09/powershell-switch-type-never-null/&quot; title=&quot;PowerShell Switch type never $null | Keith&amp;#39;s Consulting Blog&quot;&gt;PowerShell Switch type never $null | Keith&amp;#39;s Consulting Blog&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;この件に関しては大した情報もなさそうやと思ってコード見に行ったのだけど、まだ追いきれなくてよくわからんかった。この辺は宿題としたい。
一応 PowerShell で簡易的に switch parameter の挙動をチェックする PowerShell の関数を作ったのだけど、こいつだと falsy な挙動になる。なんでや...ひょっとしたら pocof のバグなんかも。
あるいはバイナリ Cmdlet だと違うとか？めんど...宿題。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;test-switch&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;([switch]&lt;span class=&quot;hljs-variable&quot;&gt;$Switch&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;is null=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$Switch&lt;/span&gt; -eq &lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt;)&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;is false=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$Switch&lt;/span&gt; -eq &lt;span class=&quot;hljs-variable&quot;&gt;$false&lt;/span&gt;)&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;is true=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$switch&lt;/span&gt; -eq &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;)&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;isPresent=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$Switch&lt;/span&gt;.IsPresent)&amp;quot;&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 狂気のワンライナー&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;plain&amp;#x27;&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;test-switch&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Switch&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;$false&amp;#x27;&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;test-switch&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Switch&lt;/span&gt;:&lt;span class=&quot;hljs-variable&quot;&gt;$false&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;$true&amp;#x27;&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;test-switch&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Switch&lt;/span&gt;:&lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;null&amp;#x27;&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;test-switch&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Switch&lt;/span&gt;:&lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# plain&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is null=False&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is false=False&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is true=True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# isPresent=True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# $false&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is null=False&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is false=True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is true=False&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# isPresent=False&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# $true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is null=False&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is false=False&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is true=True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# isPresent=True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is null=False&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is false=True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# is true=False&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# isPresent=False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 17 Nov 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-11-10-writing-cmdline-predictor-in-fsharp-pt1.html</guid><link>https://krymtkts.github.io/posts/2024-11-10-writing-cmdline-predictor-in-fsharp-pt1.html</link><title>F# で command-line predictor を書いてる Part 1 - sample 実装を F# に翻訳する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;ちょっと前触れた &lt;a href=&quot;/posts/2024-10-13-i-want-to-write-predictor-in-fsharp.html&quot; title=&quot;command-line predictor を書きたい&quot;&gt;command-line predictor を書きたい&lt;/a&gt;というやつを試し始めた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-cmdline-predictor?view=powershell-7.4&quot; title=&quot;How to create a command-line predictor - PowerShell | Microsoft Learn&quot;&gt;How to create a command-line predictor - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これ ↑ を参考にお試しする。
記事によると command-line predictor は &lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; の 7.2 のときに登場した機能らしい。
7.4 でアナウンスされた &lt;a href=&quot;https://devblogs.microsoft.com/powershell/what-are-feedback-providers/&quot; title=&quot;feedback provider&quot;&gt;feedback provider&lt;/a&gt; はなんか印象強かったが、 command-line predictor の方が先輩機能だった。
日本語の方のドキュメントを見たら「コマンドライン予測器」というある意味カッコいいがなんとも伝わらなそうな名前になっているので、英語の command-line predictor の方を使うことにする。
略記は記事の URL に含まれてる cmdline predictor に倣うとする。&lt;/p&gt;
&lt;p&gt;command-line predictor の記事によれば、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A predictor is a PowerShell binary module.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことでバイナリモジュールじゃないとダメなようだ。
確かに始め簡単に試したかったので sample code を AI と一緒に PowerShell に翻訳したものを作ってみたが、ダメだった。&lt;/p&gt;
&lt;p&gt;諦めて真面目に F# で翻訳したやつを作ってみた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/SamplePredictor&quot; title=&quot;krymtkts/SamplePredictor: A sample command-line predictor written in F#.&quot;&gt;krymtkts/SamplePredictor: A sample command-line predictor written in F#.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今回は素振りなので、次に本ちゃんを作る時用に手順を残した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet new classlib &lt;span class=&quot;hljs-literal&quot;&gt;--name&lt;/span&gt; SamplePredictor &lt;span class=&quot;hljs-literal&quot;&gt;--language&lt;/span&gt; F&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; SamplePredictor&lt;br /&gt;git init&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Initial commit.&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--allow-empty&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# translate code.&lt;/span&gt;&lt;br /&gt;git add .\Library.fs .\SamplePredictor.fsproj&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Initialize F# project.&amp;#x27;&lt;/span&gt;&lt;br /&gt;touch .gitignore&lt;br /&gt;git add .\.gitignore&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Add `.gitignore`.&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;dotnet build&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# confirm that PredictionSource is set to HistoryAndPlugin.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-PSReadLineOption&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; PredictionSource&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PredictionSource&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ----------------&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# HistoryAndPlugin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Import-Module&lt;/span&gt; .\bin\Debug\net6.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\SamplePredictor.dll&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# confirm that SamplePredictor is added to Implementations.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-PSSubsystem&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Kind&lt;/span&gt; CommandPredictor&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Kind              SubsystemType      IsRegistered Implementations&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ----              -------------      ------------ ---------------&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# CommandPredictor  ICommandPredictor          True {Windows Package Manager - WinGet, SamplePredictor}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;New-GitHubRepository&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;pwd&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Split-Path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Leaf&lt;/span&gt;) &lt;span class=&quot;hljs-literal&quot;&gt;-Description&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;A sample command-line predictor written in F#.&amp;#x27;&lt;/span&gt;&lt;br /&gt;git remote add origin &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;Get-GitHubRepository&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-OwnerName&lt;/span&gt; krymtkts &lt;span class=&quot;hljs-literal&quot;&gt;-RepositoryName&lt;/span&gt; SamplePredictor | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; ssh_url)&lt;br /&gt;git push &lt;span class=&quot;hljs-literal&quot;&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;雑にこんな感じで作れる。&lt;/p&gt;
&lt;p&gt;実装は元記事の sample を丸ごとコピペ翻訳しても良かったが、 .NET 素人のためプロジェクト構成の &lt;code&gt;GenerateDependencyFile&lt;/code&gt; &lt;code&gt;PublishDir&lt;/code&gt; &lt;code&gt;ExcludeAssets&lt;/code&gt; &lt;code&gt;PrivateAssets&lt;/code&gt; 辺りが何を意図して設定したものか理解してなかったので、部分ごとにちまちま確認しつつコピペ翻訳した。
お陰で &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; でも試せそうやなというのが理解できた。
あと挙動がわからんのでファイルにログ出力する雑実装を入れて追跡を容易にし、念の為 sample から GUID も変えてる。&lt;/p&gt;
&lt;p&gt;使い方は README.md にも書いてるが、これによって &lt;code&gt;Import-Module ~&lt;/code&gt; 後に PSReadLine の suggestion に追加した command-line predictor のエントリが現れる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; sss&lt;br /&gt;&amp;lt;-/&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&amp;gt;                                                       &amp;lt;SamplePredictor(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&amp;gt;&lt;br /&gt;&amp;gt; sss HELLO WORLD                                              [&lt;span class=&quot;hljs-type&quot;&gt;SamplePredictor&lt;/span&gt;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この実装だと、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.subsystem.prediction.icommandpredictor?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;ICommandPredictor&lt;/code&gt;&quot;&gt;&lt;code&gt;ICommandPredictor&lt;/code&gt;&lt;/a&gt; の &lt;code&gt;CanAcceptFeedback&lt;/code&gt; &lt;code&gt;GetSuggestion&lt;/code&gt; が呼ばれるタイミングはわかったが、他のメソッドが何するとき動くかは理解できてない。
ドキュメント見てもぱっとせんので、手で試行錯誤するのが良さそう。
あと既にコミュニティで作成されてる predictor の困りごとを探るとか、
&lt;a href=&quot;https://github.com/PowerShell/PSReadLine/issues?q=is%3Aissue+is%3Aopen+predictor&quot; title=&quot;&lt;code&gt;PSReadLine&lt;/code&gt; の issue&quot;&gt;&lt;code&gt;PSReadLine&lt;/code&gt; の issue&lt;/a&gt; を漁って、今出来ないことを探ってくのが現実的な理解方法かも知れんな。
ざっと見た感じ &lt;code&gt;ICommandPredictor&lt;/code&gt; は 20ms 以内に response しないといけないやつが短過ぎるって意見があるから、重めの処理ができそうにないのは理解した。
にしてもやで、 &lt;code&gt;ICommandPredictor&lt;/code&gt; で検索してもあんま情報ないな command-line predictor 。調べ方が悪いんかな。或いはどんだけ人気ないねん。 GitHub で &lt;code&gt;ICommandPredictor&lt;/code&gt; 検索して直に見ていくしかないか。&lt;/p&gt;
&lt;p&gt;何も内容がない日記になったが、個人的な理解は進んでるはずなのでヨシッ！&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 10 Nov 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-11-03-start-booklog-pt4.html</guid><link>https://krymtkts.github.io/posts/2024-11-03-start-booklog-pt4.html</link><title>booklog はじめた 4</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2024-09-01-start-booklog.html&quot; title=&quot;8 月半ばにつけはじめた booklog&quot;&gt;8 月半ばにつけはじめた booklog&lt;/a&gt; もはや 3 ヶ月目。
そろそろ streak を数値化したくなったので、そういう機能を &lt;a href=&quot;https://github.com/krymtkts/blog-fable/&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; に追加してみた。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/259&quot; title=&quot;#259&quot;&gt;#259&lt;/a&gt;
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/264&quot; title=&quot;#264&quot;&gt;#264&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;新機能によると、昨日時点で 76 日連続で読書できてるらしい。
この週間を始めてから読み始めた本だと、読みかけも含めて 5 冊。
つまみ読みや輪読会&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;の課題図書も含めて 9 冊。
少なく見ても月 1 冊以上は読めてるので、 &lt;a href=&quot;/posts/2024-01-01-planning.html&quot; title=&quot;年初の目標 0.5 冊/月&quot;&gt;年初の目標 0.5 冊/月&lt;/a&gt;をさばけてて、いい感じ。&lt;/p&gt;
&lt;p&gt;1 回あたりのページ数は、調子がいい時は 20 前後、ダメな時は数ページ。
ダメな時は概ね忙しくて寝る前にざっと読んで記録をつけてる感じ。そういう時は 30 分以内で処理できてるのでちょっとは早くなったのか？
あと仕事で自分で決める事が多く決断力を消費して疲弊することが多いのだけど、そういう頭がこんがらがってる時に数ページでも読書すると、頭がスーッとして休憩みたいになって良いのを知った。
これは習慣化しないと見えなかった風景やな。&lt;/p&gt;
&lt;p&gt;輪読会の日は課題図書と自分が読んでる本で 2 冊になるのでちょっと忙しい。
けどそういう時はダメな時のような急いでなんかできる感じじゃなく、あらかじめどのタイミングで読んで～といった計画性が必要になってくるので、そういう点ではより強制力高くて良いなと感じている。&lt;/p&gt;
&lt;p&gt;ただ今強度を高めると中折れしそうなので、とりあえず 1 年間続けられたらその先同じ用に繰り返せば何年でもできる感触がつかめるだろうから、そのときにページ数の縛りだとかの制約を追加しても良いかもしれない。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;ところでこの booklog の streak 機能、 static site generator なため日付が変わっても streak が 0 にならないのよな。
コンテンツ生成時に現在日付をもとに計算しても良かったが、なんかイマイチかもなと思って今のところ最後の streak が current streak になる「仕様」になってる。&lt;/p&gt;
&lt;p&gt;これだと streak が止まった時のショックが小さくなってしまうから、なんか動的な仕組み考えたほうが良いのかもなー。
GitHub Actions を日次実行するような無駄な使い方になってしまうけど。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;知人に付き合ってもらってる輪読会。ゆるく開催してて概ね月 0 ~ 4 回くらい。 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 03 Nov 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-10-27-writing-cmdlet-in-fsharp-pt52.html</guid><link>https://krymtkts.github.io/posts/2024-10-27-writing-cmdlet-in-fsharp-pt52.html</link><title>F# で Cmdlet を書いてる pt.52</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;word 操作の実装中 &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/173&quot; title=&quot;#173&quot;&gt;#173&lt;/a&gt; で、移動、選択、削除を雑に作った。&lt;/p&gt;
&lt;p&gt;多分まだ日記でどういう方針で実装するかを書いてなかったので、備忘がてら実装開始前のメモを記しておく。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;word 操作の実装は PSReadLine を参考にするつもり。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSReadLine/blob/e87a265ef8d2c6c5498500deb155bf6258b34629/PSReadLine/Movement.cs#L406&quot; title=&quot;PSReadLine/PSReadLine/Movement.cs at e87a265ef8d2c6c5498500deb155bf6258b34629 · PowerShell/PSReadLine&quot;&gt;PSReadLine/PSReadLine/Movement.cs at e87a265ef8d2c6c5498500deb155bf6258b34629 · PowerShell/PSReadLine&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;_singleton.Options.WordDelimiters&lt;/code&gt; は &lt;code&gt;Get-PSReadLineOption | Select-Object WordDelimiters&lt;/code&gt; のこと。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;;:,.[]{}()/\|!?^&amp;amp;*-=+&amp;#39;&amp;quot;–—―&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;この文字列に対して独自の文字列一致関数を使って一致したか判定している。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSReadLine/blob/e87a265ef8d2c6c5498500deb155bf6258b34629/PSReadLine/StringBuilderCharacterExtensions.cs#L32-L35&quot; title=&quot;PSReadLine/PSReadLine/StringBuilderCharacterExtensions.cs at e87a265ef8d2c6c5498500deb155bf6258b34629 · PowerShell/PSReadLine&quot;&gt;PSReadLine/PSReadLine/StringBuilderCharacterExtensions.cs at e87a265ef8d2c6c5498500deb155bf6258b34629 · PowerShell/PSReadLine&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;また加えて、&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSReadLine/blob/e87a265ef8d2c6c5498500deb155bf6258b34629/PSReadLine/StringBuilderCharacterExtensions.cs#L65-L77&quot; title=&quot;PSReadLine/PSReadLine/StringBuilderCharacterExtensions.cs at e87a265ef8d2c6c5498500deb155bf6258b34629 · PowerShell/PSReadLine&quot;&gt;PSReadLine/PSReadLine/StringBuilderCharacterExtensions.cs at e87a265ef8d2c6c5498500deb155bf6258b34629 · PowerShell/PSReadLine&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;を見てわかるように character が whitespace の場合は問答無用で区切る。&lt;/p&gt;
&lt;p&gt;pocof も同様に Option で指定できるようにしてジャンプ位置を指定するようにしようかな。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; の word の特徴？なのか bash とは別の動きするので PowerShell の流儀的に pocof もそれに倣うため実装を参考にしてる。
ただ、 pocof では選択範囲ありの行頭・行末までの削除の挙動が独自なのだけど、今回の word 削除でも同じく独自にした。
PSReadLine では選択範囲を無視して word を削除するが、 pocof では選択範囲も削除する。&lt;/p&gt;
&lt;p&gt;あと当初の予定の範囲で実装できてないのが、区切り文字の Option 指定。
これは他の Option 同様に内部状態に加えるだけなので実装自体はたいしたことない。
個人的には &lt;code&gt;_&lt;/code&gt; も区切りたいのだけど、これは自分でデフォルトパラメータを設定したらいいだけなので、足さない。&lt;/p&gt;
&lt;p&gt;そこまでできたら最後にリファクタリングが必要だ。
何故なら、今回の実装で痛感したが、文字の選択と削除の実装が結構バラバラで苦労したからだ。
1 文字消すのと複数文字消すのと行頭行末まで消すので実装マチマチなので、なんか統一的な操作に落とし込めるだろこれｗみたいな。
過去の自分のツケが回ってきた。&lt;/p&gt;
&lt;p&gt;あと特に認知的な負荷が高いと思ってるのが、選択範囲の実装。
正負の整数でカーソルの前後にある選択範囲の文字数を示してるので、最近全然触ってなかったし結構混乱した。
すでに discriminated union にくるまれた整数だが、更に DU を分けるべきなのか、 Units of measure で上手くできるもんなのか、検討する。
実際選択範囲を正負の整数で表現することで、カーソル位置から選択範囲を加減算するだけで選択範囲のカーソル位置がわかる便利さはあるのだけど、案外リファクタリングの過程で別のわかりやすい実装が見つかるかも知れんし。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 27 Oct 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-10-20-writing-cmdlet-in-fsharp-pt51.html</guid><link>https://krymtkts.github.io/posts/2024-10-20-writing-cmdlet-in-fsharp-pt51.html</link><title>F# で Cmdlet を書いてる pt.51 - Windows PowerShell on GitHub Actions workflow</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-10-06-writing-cmdlet-in-fsharp-pt50.html&quot; title=&quot;以前発見した .NET の挙動が文書と違うやつ&quot;&gt;以前発見した .NET の挙動が文書と違うやつ&lt;/a&gt; は .NET Framework に依存する Windows PowerShell だけで発生するエラーがあったためだが、それを自動的に検知する仕組みは作ってなかった(このときは手で見つけた)。
今後も同じような事があると面倒なので、 pull request を作成したときに自動で検知できるよう GitHub Actions workflow の matrix に Windows PowerShell を追加した。&lt;/p&gt;
&lt;p&gt;job の step で Windows PowerShell を利用するには、&lt;a href=&quot;https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell&quot; title=&quot;&lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps[*].shell&lt;/code&gt;&quot;&gt;&lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps[*].shell&lt;/code&gt;&lt;/a&gt; に &lt;code&gt;powershell&lt;/code&gt; と指定すればいい。
&lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps[*].shell&lt;/code&gt; を使うのは、 pocof の Github Actions workflow は処理を共通化するのに &lt;a href=&quot;https://docs.github.com/en/actions/sharing-automations/creating-actions/creating-a-composite-action&quot; title=&quot;Composite action&quot;&gt;Composite action&lt;/a&gt; を使ってるからで、 step ごとに指定する必要があるから(確か)。
当然コレを使えるのは platform が Windows の場合だけ。
job runner が Windows の場合だけ &lt;code&gt;pwsh&lt;/code&gt; と &lt;code&gt;powershell&lt;/code&gt; の 2 つの &lt;code&gt;shell&lt;/code&gt; を Composite action に追加してやれば良い。&lt;/p&gt;
&lt;p&gt;従来はすべての platform で &lt;code&gt;pwsh&lt;/code&gt; を利用する &lt;a href=&quot;https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix&quot; title=&quot;&lt;code&gt;matrix&lt;/code&gt;&quot;&gt;&lt;code&gt;matrix&lt;/code&gt;&lt;/a&gt; になってたので、 Windows の場合だけ拡張してやる必要がある。
これには &lt;a href=&quot;https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/running-variations-of-jobs-in-a-workflow#expanding-or-adding-matrix-configurations&quot; title=&quot;&lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.strategy.matrix.include&lt;/code&gt;&quot;&gt;&lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.strategy.matrix.include&lt;/code&gt;&lt;/a&gt; が使えた。
&lt;code&gt;matrix&lt;/code&gt; 定義の追加や上書きができるみたい。便利すぎ。&lt;/p&gt;
&lt;p&gt;結果この様になった。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/246&quot; title=&quot;#246&quot;&gt;#246&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;composite action の &lt;a href=&quot;https://docs.github.com/en/actions/sharing-automations/creating-actions/metadata-syntax-for-github-actions#inputs&quot; title=&quot;&lt;code&gt;inputs&lt;/code&gt;&quot;&gt;&lt;code&gt;inputs&lt;/code&gt;&lt;/a&gt; に &lt;code&gt;shell&lt;/code&gt; を追加して、それで &lt;code&gt;jobs.&amp;lt;job_id&amp;gt;.steps[*].shell&lt;/code&gt; を設定する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;inputs:&lt;br /&gt;   codecov_token:&lt;br /&gt;     description: &amp;quot;Codecov token&amp;quot;&lt;br /&gt;     required: true&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+  shell:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    description: &amp;quot;Shell for the job. pwsh or powershell&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    required: true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    default: pwsh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;       with:&lt;br /&gt;         global-json-file: ./global.json&lt;br /&gt;     - name: Install modules from PSGallery&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-      shell: pwsh&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      shell: ${{ inputs.shell }}&lt;/span&gt;&lt;br /&gt;       run: |&lt;br /&gt;         Set-PSResourceRepository PSGallery -Trusted&lt;br /&gt;         Install-PSResource Psake,Pester,PSScriptAnalyzer -Quiet -Reinstall -Scope CurrentUser&lt;br /&gt;     - name: Execute All Tests&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-      shell: pwsh&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      shell: ${{ inputs.shell }}&lt;/span&gt;&lt;br /&gt;       run: Invoke-Psake -taskList TestAll&lt;br /&gt;     - name: Upload coverage reports to Codecov&lt;br /&gt;       uses: codecov/codecov-action@v4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;include&lt;/code&gt; を使って Windows runner の &lt;code&gt;matrix&lt;/code&gt; を拡張する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;     strategy:&lt;br /&gt;       matrix:&lt;br /&gt;         os:&lt;br /&gt;           - windows-latest&lt;br /&gt;           - ubuntu-latest&lt;br /&gt;           - macos-latest&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        shell:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          - pwsh&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        include:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          - os: windows-latest&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            shell: pwsh&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          - os: windows-latest&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            shell: powershell&lt;/span&gt;&lt;br /&gt;     runs-on: ${{ matrix.os }}&lt;br /&gt;     steps:&lt;br /&gt;       - name: Checkout
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;         uses: ./.github/actions/test&lt;br /&gt;         with:&lt;br /&gt;           codecov_token: ${{ secrets.CODECOV_TOKEN }}&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          shell: ${{ matrix.shell }}&lt;/span&gt;&lt;br /&gt;       - name: Run Snyk to check for vulnerabilities&lt;br /&gt;         uses: snyk/actions/dotnet@master&lt;br /&gt;         # snyk/actions uses Container action that is only supported on Linux.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで完成かと思いきや、 3 つ障害があった。
まず &lt;a href=&quot;https://github.com/pester/Pester&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; 用のテストスクリプトに Windows PowerShell 非互換の機能があったので取り除く必要があった。
また GitHub Actions workflow で使える Windows Server 2022 の runner には &lt;a href=&quot;https://github.com/PowerShell/PSResourceGet&quot; title=&quot;PSResourceGet&quot;&gt;PSResourceGet&lt;/a&gt; が入ってなかったので、 PowerShell Module の準備を &lt;code&gt;pwsh&lt;/code&gt; 用と &lt;code&gt;powershell&lt;/code&gt; 用に分けた。
この 2 つはテストスクリプトと workflow を調整するだけで済んだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/split-path?view=powershell-7.4#-leafbase&quot; title=&quot;&lt;code&gt;Split-Path -LeafBase&lt;/code&gt;&quot;&gt;&lt;code&gt;Split-Path -LeafBase&lt;/code&gt;&lt;/a&gt; は PowerShell 6.0 以降の機能で Windows PowerShell で使えなかったので &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-7.4&quot; title=&quot;&lt;code&gt;Get-ChildItem&lt;/code&gt;&quot;&gt;&lt;code&gt;Get-ChildItem&lt;/code&gt;&lt;/a&gt; で代用。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;     if ($DryRun -eq $null) {&lt;br /&gt;         $DryRun = $true&lt;br /&gt;     }&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    $ModuleName = Resolve-Path ./src/*/*.psd1 | Split-Path -LeafBase&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $ModuleName = Get-ChildItem ./src/*/*.psd1 | Select-Object -ExpandProperty BaseName&lt;/span&gt;&lt;br /&gt;     $ModuleVersion = (Resolve-Path &amp;quot;./src/${ModuleName}/*.fsproj&amp;quot; | Select-Xml &amp;#x27;//Version/text()&amp;#x27;).Node.Value&lt;br /&gt;     $ModuleSrcPath = Resolve-Path &amp;quot;./src/${ModuleName}/&amp;quot;&lt;br /&gt;     $ModulePublishPath = Resolve-Path &amp;quot;./publish/${ModuleName}/&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;shell&lt;/code&gt; の内容に応じて &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/install-psresource?view=powershellget-3.x&quot; title=&quot;&lt;code&gt;Install-PSResource&lt;/code&gt;&quot;&gt;&lt;code&gt;Install-PSResource&lt;/code&gt;&lt;/a&gt; と &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/powershellget/install-module?view=powershellget-2.x&quot; title=&quot;&lt;code&gt;Install-Module&lt;/code&gt;&quot;&gt;&lt;code&gt;Install-Module&lt;/code&gt;&lt;/a&gt; を使う &lt;code&gt;step&lt;/code&gt; に分ける。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;       uses: actions/setup-dotnet@v4&lt;br /&gt;       with:&lt;br /&gt;         global-json-file: ./global.json&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    - name: Install modules from PSGallery&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    - name: Install modules from PSGallery (pwsh)&lt;/span&gt;&lt;br /&gt;       shell: ${{ inputs.shell }}&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      if: inputs.shell == &amp;#x27;pwsh&amp;#x27;&lt;/span&gt;&lt;br /&gt;       run: |&lt;br /&gt;         Set-PSResourceRepository PSGallery -Trusted&lt;br /&gt;         Install-PSResource Psake,Pester,PSScriptAnalyzer -Quiet -Reinstall -Scope CurrentUser&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    - name: Install modules from PSGallery (powershell)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      shell: ${{ inputs.shell }}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      if: inputs.shell == &amp;#x27;powershell&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      run: |&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        Install-Module -Name Psake,Pester,PSScriptAnalyzer -Force -Scope CurrentUser -Repository PSGallery -SkipPublisherCheck&lt;/span&gt;&lt;br /&gt;     - name: Execute All Tests&lt;br /&gt;       shell: ${{ inputs.shell }}&lt;br /&gt;       run: Invoke-Psake -taskList TestAll
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最後の障害は解消できなかったので、暫定対応とした。
解決できなかったのは、 &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.threading.thread.currentculture?view=net-8.0&quot; title=&quot;&lt;code&gt;[System.Threading.Thread]::CurrentThread.CurrentCulture&lt;/code&gt;&quot;&gt;&lt;code&gt;[System.Threading.Thread]::CurrentThread.CurrentCulture&lt;/code&gt;&lt;/a&gt; に設定した &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.globalization.datetimeformatinfo.shortdatepattern?view=net-8.0&quot; title=&quot;&lt;code&gt;DateTimeFormat.ShortDatePattern&lt;/code&gt;&quot;&gt;&lt;code&gt;DateTimeFormat.ShortDatePattern&lt;/code&gt;&lt;/a&gt; が pocof に伝播されない点だ。
この &lt;code&gt;DateTimeFormat.ShortDatePattern&lt;/code&gt; に &lt;code&gt;&amp;#39;yyyy-MM-dd&amp;#39;&lt;/code&gt; を設定したら、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.datetime.tostring?view=net-8.0&quot; title=&quot;&lt;code&gt;DateTime.ToString()&lt;/code&gt;&quot;&gt;&lt;code&gt;DateTime.ToString()&lt;/code&gt;&lt;/a&gt; でそのパターンが参照されるはずだが、されなくてテストがコケる。
自 PC であれば PowerShell でも Windows PowerShell でも上手くいくが、 GitHub Actions の Windows Server 2022 runner では反映されなかった。&lt;/p&gt;
&lt;p&gt;culture を設定した thread と違う thread で動いたのか？とか考えられるが、となると解消方法は &lt;code&gt;DateTime.ToString()&lt;/code&gt; に culture を直に渡す方法になる。これはやりたいものではない。
現時点で恒久対応が難しかったので、 skip 判断で良かったと思う。
Pester で提供されてた &lt;a href=&quot;https://pester.dev/docs/usage/skip#conditional-skip&quot; title=&quot;Conditional skip&quot;&gt;Conditional skip&lt;/a&gt; 機能で条件付き skip を実現できた。便利すぎ。
&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_editions?view=powershell-7.4#long-description&quot; title=&quot;&lt;code&gt;$PSVersionTable.PSEdition -eq &amp;#39;Desktop&amp;#39;&lt;/code&gt;&quot;&gt;&lt;code&gt;$PSVersionTable.PSEdition -eq &amp;#39;Desktop&amp;#39;&lt;/code&gt;&lt;/a&gt; で判断しているので Windows PowerShell だけこの test case が skip 対象となる。
ついでに culture の変更は &lt;a href=&quot;https://pester.dev/docs/commands/BeforeEach&quot; title=&quot;&lt;code&gt;BeforeEach&lt;/code&gt;&quot;&gt;&lt;code&gt;BeforeEach&lt;/code&gt;&lt;/a&gt; &lt;a href=&quot;https://pester.dev/docs/commands/AfterEach&quot; title=&quot;&lt;code&gt;AfterEach&lt;/code&gt;&quot;&gt;&lt;code&gt;AfterEach&lt;/code&gt;&lt;/a&gt; を使うようにした(&lt;code&gt;*All&lt;/code&gt; でいい気もするが)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;         Context &amp;#x27;with culture&amp;#x27; -ForEach @(&lt;br /&gt;             @{ Matcher = &amp;#x27;match&amp;#x27;; Operator = &amp;#x27;or&amp;#x27;; Query = &amp;#x27;24-01&amp;#x27; }&lt;br /&gt;         ) {&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            BeforeEach {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                $global:culture = [System.Threading.Thread]::CurrentThread.CurrentCulture&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                $global:testCulture = [System.Globalization.CultureInfo]::GetCultureInfo(&amp;#x27;en-US&amp;#x27;).Clone()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                $global:testCulture.DateTimeFormat.ShortDatePattern = &amp;#x27;yyyy-MM-dd&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                [System.Threading.Thread]::CurrentThread.CurrentCulture = $global:testCulture&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            AfterEach {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                [System.Threading.Thread]::CurrentThread.CurrentCulture = $global:culture&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            }&lt;/span&gt;&lt;br /&gt;             It &amp;quot;Given &amp;#x27;&amp;lt;InputObject&amp;gt;&amp;#x27;, it keeps order as &amp;#x27;&amp;lt;Expected&amp;gt;&amp;#x27;.&amp;quot; -TestCases @(&lt;br /&gt;                 @{InputObject = 1..12 | ForEach-Object {&lt;br /&gt;                         Get-Date (&amp;#x27;2024-{0:D2}-01&amp;#x27; -f $_)&lt;br /&gt;                     }; Expected = @(&lt;br /&gt;                         Get-Date &amp;#x27;2024-01-01&amp;#x27;&lt;br /&gt;                     ) ; Params = $BaseParam + $_&lt;br /&gt;                 }&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            ) {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                $culture = [System.Threading.Thread]::CurrentThread.CurrentCulture&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                $testCulture = [System.Globalization.CultureInfo]::GetCultureInfo(&amp;#x27;en-US&amp;#x27;).Clone()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                $testCulture.DateTimeFormat.ShortDatePattern = &amp;#x27;yyyy-MM-dd&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                [System.Threading.Thread]::CurrentThread.CurrentCulture = $testCulture&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            ) -Skip:($PSVersionTable.PSEdition -eq &amp;#x27;Desktop&amp;#x27; ) {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                # TODO: This test is not working on Windows PowerShell on GitHub Actions. It works well locally.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                # TODO: It seems that the culture is not changed.&lt;/span&gt;&lt;br /&gt;                 $InputObject | Select-Pocof @Params | Should -BeExactly -ExpectedValue $Expected&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                [System.Threading.Thread]::CurrentThread.CurrentCulture = $culture&lt;/span&gt;&lt;br /&gt;             }&lt;br /&gt;         }&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;現状 skip してるが根治できたらしたいな。継続して調査する。&lt;/p&gt;
&lt;p&gt;ひとまずこれで v0.16.0 のリリースしたあと Windows PowerShell 出だけ発生するエラーがあるとかは事前に気づける。
あとやっぱ今の PowerShell は Windows PowerShell より大分速いんやなと実感できた。 Windows PowerShell の job は他よりも完了するのがめちゃくちゃ遅い。
いい仕事をした。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 20 Oct 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-10-13-i-want-to-write-predictor-in-fsharp.html</guid><link>https://krymtkts.github.io/posts/2024-10-13-i-want-to-write-predictor-in-fsharp.html</link><title>F# で command-line predictor を書きたい</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; はちょこちょこいじってるだけ、また&lt;a href=&quot;/posts/2024-10-06-writing-cmdlet-in-fsharp-pt50.html&quot; title=&quot;前回発見した .NET の挙動が文書と違うやつ&quot;&gt;前回発見した .NET の挙動が文書と違うやつ&lt;/a&gt;も意図した挙動で長くドキュメント不備だっただけらしいので、特に進捗なし。 &lt;a href=&quot;https://github.com/dotnet/dotnet-api-docs/issues/10508#issuecomment-2397449030&quot; title=&quot;dotnet/dotnet-api-docs#10508&quot;&gt;dotnet/dotnet-api-docs#10508&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;なので今日は今後やりたいなと思ってることをメモしておく。&lt;/p&gt;
&lt;p&gt;ちょっと前にに Windows Terminal に Snippets Pane ていう機能が来てた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-22-release/#snippets-pane&quot; title=&quot;Snippets Pane | Windows Terminal Preview 1.22 Release - Windows Command Line&quot;&gt;Snippets Pane | Windows Terminal Preview 1.22 Release - Windows Command Line&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Have you ever woken up at 3:00 AM after getting paged for a SEV1 and frantically struggled to remember what commands you need to revive a production cluster? Well, maybe the Snippets Pane can help with that…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;意訳するとこう。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;深夜 3:00 に緊急対応で起こされて本番クラスタを復活するためのコマンドを思い出すのに必死になったことはあらへんか？ Snippets Pane が助けてくれるかも知れへんで...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;要はタダのスニペット挿入機能なんやけど、 Windows Terminal の複数プロファイルを束ねる特性と組み合わさることで、様々な環境に対して同じワンライナー(ここでいう snippets)を挿入できる素敵な機能になってる。
登場以来わたしもよく使ってる。&lt;/p&gt;
&lt;p&gt;ただ満足してるわけではないねんよな。何故かというとこの機能は個々のシェルの外側にいるので、そのシェルの中で滑らかにつながってない。
郷に入っては郷に従えではないが、そのシェルの中、ここでは PowerShell のお作法に従って滑らかに繋がってるスニペット挿入機能があってほしい。
日常使いする PowerShell は自分のローカル開発環境でしかほぼ使わないから、 PowerShell のスニペットを Windows Terminal に保存しても特に嬉しいことないねんよな。
PowerShell のような人少なめコミュニティでもスニペットみたいなみんなが欲しい機能は当然昔からあるようで、調べたらなんぼでも出てくるのよね。例えば新し目のだと &lt;a href=&quot;https://github.com/mdowst/PSNotes&quot; title=&quot;mdowst/PSNotes&quot;&gt;mdowst/PSNotes&lt;/a&gt; とか良さそうよな。&lt;/p&gt;
&lt;p&gt;ただ、わたしの場合スニペットに名前をつけて覚えといて、その名前で利用するときに呼び出すなんてことは面倒そうな気がしてる。
Windows Terminal の Snippets Pane を使うまでは履歴から目当てのコマンドを拾って実行したりしてたので、その利用感でスニペットを優先的に表示できたらなんか良さそうよな。
だからやりたいのは &lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; の補完候補のところにスニペットを出したい。&lt;/p&gt;
&lt;p&gt;少し調べたところ、 PowerShell 7.2 &amp;amp; PSReadLine 2.2.2 から使える command-line predictor という機能を使えばやりたいことができそう。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-cmdline-predictor?view=powershell-7.4&quot; title=&quot;How to create a command-line predictor - PowerShell | Microsoft Learn&quot;&gt;How to create a command-line predictor - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Microsoft 様公式ドキュメントもパッと見充実しており、というかコレ以外はあまりまともそうな資料が見つからないのだけど、これを使って意中の機能を実装できないかなーと検討している。 F# で。
command-line predictor と、追加・削除のための Cmdlet を提供できたら、いい感じに日常使いが回るかなと考えている。
ひょっとしたら世界の何処かで誰かが既に実装してるかも知れないが、見つけられなかったので自作する。&lt;/p&gt;
&lt;p&gt;それならまずサンプル実装をしてみようと思ってたのだけど、時間取れず着手できないまま 2 ヶ月近く経過してしまった。
このままではまずい。
ということで、とりあえず今日は日記に書くネタがなかったし、代わりにこの話を書くことで自身に対する実行の強制力を高めようという目論見だ。
日記に書く暇あったら sample だけでもはよ作れよという感じではあるが。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 13 Oct 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-10-06-writing-cmdlet-in-fsharp-pt50.html</guid><link>https://krymtkts.github.io/posts/2024-10-06-writing-cmdlet-in-fsharp-pt50.html</link><title>F# で Cmdlet を書いてる pt.50</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。 &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.16.0&quot; title=&quot;v0.16.0&quot;&gt;v0.16.0&lt;/a&gt; と、そのバグ修正版の &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.16.1&quot; title=&quot;v0.16.1&quot;&gt;v0.16.1&lt;/a&gt; をリリースしたのでその話を書く。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/fsharp/language-reference/code-quotations&quot; title=&quot;コードクォート&quot;&gt;コードクォート&lt;/a&gt;でクエリの述語を実装してみた版を v0.16.0 でリリースした。
pocof は &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/standard/net-standard?tabs=net-standard-2-0&quot; title=&quot;.NET Standard 2.0&quot;&gt;.NET Standard 2.0&lt;/a&gt; を対象にしてるので PowerShell と Windows PowerShell の両方で動くのだけど、この版に含まれる変更に起因して Windows PowerShell でだけエラーになるバグ &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/235&quot; title=&quot;#235&quot;&gt;#235&lt;/a&gt; が発生した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt; | pocof&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# pocof : The startIndex argument must be greater than or equal to zero.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Parameter name: startIndex&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# At line:1 char:6&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# + &amp;#x27;&amp;#x27; | pocof&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# +      ~~~~~&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     + CategoryInfo          : NotSpecified: (:) [Select-Pocof], ArgumentOutOfRangeException&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     + FullyQualifiedErrorId : System.ArgumentOutOfRangeException,Pocof.SelectPocofCommand&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Windows/Linux/MacOS の PowerShell ではエラーにならない。率直に Windows PowerShell になにか問題あるよなと考えた。&lt;/p&gt;
&lt;p&gt;バグが入り込んだコミット &lt;a href=&quot;https://github.com/krymtkts/pocof/commit/255409205df5a238abf00dbe2806b65e411e2d82&quot; title=&quot;krymtkts/pocof@2554092&quot;&gt;krymtkts/pocof@2554092&lt;/a&gt; は人力二分探索で特定した。
該当のコミットでの変更差分は以下の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;         member __.Receive() =&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            match renderStack.Count with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            | 0 -&amp;gt; RenderMessage.None&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            | c -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                let items = Array.zeroCreate&amp;lt;RenderEvent&amp;gt; c&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                renderStack.TryPopRange(items) |&amp;gt; ignore&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                items |&amp;gt; Array.toList |&amp;gt; getLatestEvent&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            let items = Array.zeroCreate&amp;lt;RenderEvent&amp;gt; renderStack.Count&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            renderStack.TryPopRange(items) |&amp;gt; ignore&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            items |&amp;gt; Array.toList |&amp;gt; getLatestEvent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コレ見て分かる通り、 0 のケースを &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentstack-1.trypoprange?view=net-8.0#system-collections-concurrent-concurrentstack-1-trypoprange(-0())&quot; title=&quot;&lt;code&gt;ConcurrentStack&amp;lt;T&amp;gt;.TryPopRange&lt;/code&gt;&quot;&gt;&lt;code&gt;ConcurrentStack&amp;lt;T&amp;gt;.TryPopRange&lt;/code&gt;&lt;/a&gt; に寄せたのが良くなかったみたい。
PowerShell 7.4 と Windows PowerShell 5.1 はそれぞれ .NET 8 と .NET Framework 4.5 に依存しててたまに挙動の違いがあるからこういうこともあるよなという感じ。
今回はそこのテストが不十分だった。&lt;/p&gt;
&lt;p&gt;このエラーは Windows PowerShell でも確認できる。依存する .NET/.NET Framework で動くからな。
(Windows PowerShell のほうが CLRVersion 4.0. ~ なのがよくわからんかったが CLRVersion は major version で一緒ということを知った)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PowerShell の場合&lt;/span&gt;&lt;br /&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$PSVersionTable&lt;/span&gt;; &lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;System.Collections.Concurrent.ConcurrentStack&lt;/span&gt;[&lt;span class=&quot;hljs-type&quot;&gt;System.String&lt;/span&gt;]]::new(); &lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt;.Count; &lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt;.TryPopRange(&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;())&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name                           Value&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ----                           -----&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PSVersion                      7.4.5&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PSEdition                      Core&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# GitCommitId                    7.4.5&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# OS                             Microsoft Windows 10.0.22631&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Platform                       Win32NT&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PSRemotingProtocolVersion      2.3&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# SerializationVersion           1.1.0.1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# WSManStackVersion              3.0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Windows PowerShell の場合&lt;/span&gt;&lt;br /&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$PSVersionTable&lt;/span&gt;; &lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;System.Collections.Concurrent.ConcurrentStack&lt;/span&gt;[&lt;span class=&quot;hljs-type&quot;&gt;System.String&lt;/span&gt;]]::new(); &lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt;.Count; &lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt;.TryPopRange(&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;())&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name                           Value&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ----                           -----&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PSVersion                      5.1.22621.4249&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PSEdition                      Desktop&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# BuildVersion                   10.0.22621.4249&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# CLRVersion                     4.0.30319.42000&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# WSManStackVersion              3.0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PSRemotingProtocolVersion      2.3&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# SerializationVersion           1.1.0.1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Exception calling &amp;quot;TryPopRange&amp;quot; with &amp;quot;1&amp;quot; argument(s): &amp;quot;The startIndex argument must be greater than or equal to zero.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Parameter name: startIndex&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# At line:1 char:104&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# + ... ConcurrentStack[System.String]]::new(); $s.Count; $s.TryPopRange(@())&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# +                                                       ~~~~~~~~~~~~~~~~~~~&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     + FullyQualifiedErrorId : ArgumentOutOfRangeException&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;とここまで追い込んだら修正するだけだったので、 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/237&quot; title=&quot;#237&quot;&gt;#237&lt;/a&gt; で修正して v0.16.1 を出した。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;ここからはタダの brain dump だ。&lt;/p&gt;
&lt;p&gt;直し方がわかって修正したらあとはこの動作の差異が何なのかというのが気になる。コードを見に行った。
&lt;a href=&quot;https://github.com/microsoft/referencesource/?tab=MIT-1-ov-file#readme&quot; title=&quot;microsoft/referencesource&quot;&gt;microsoft/referencesource&lt;/a&gt; &lt;a href=&quot;https://github.com/dotnet/runtime/blob/main/LICENSE.TXT&quot; title=&quot;dotnet/runtime/&quot;&gt;dotnet/runtime/&lt;/a&gt; どちらもライセンスが MIT なので snippet を貼る。
以下は &lt;code&gt;ConcurrentStack&amp;lt;T&amp;gt;.TryPopRange&lt;/code&gt; の引数の validation をしているメソッドだ。&lt;/p&gt;
&lt;p&gt;.NET の方は &lt;a href=&quot;https://github.com/dotnet/runtime/blob/48dbc4fc836da67cf1efb6b348499a918c4dea8e/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentStack.cs#L390-L404&quot; title=&quot;runtime/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentStack.cs&quot;&gt;runtime/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentStack.cs&lt;/a&gt; から &lt;a href=&quot;https://github.com/dotnet/runtime/blob/48dbc4fc836da67cf1efb6b348499a918c4dea8e/src/libraries/System.Collections/src/System/Collections/ThrowHelper.cs#L64-L71&quot; title=&quot;runtime/src/libraries/System.Collections/src/System/Collections/ThrowHelper.cs&quot;&gt;runtime/src/libraries/System.Collections/src/System/Collections/ThrowHelper.cs&lt;/a&gt; を呼ぶ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;        &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ValidatePushPopRangeInput&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;T[] items, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; startIndex, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; count&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;            ArgumentNullException.ThrowIfNull(items);&lt;br /&gt;&lt;br /&gt;            ArgumentOutOfRangeException.ThrowIfNegative(count);&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; length = items.Length;&lt;br /&gt;            ArgumentOutOfRangeException.ThrowIfGreaterThan(startIndex, length);&lt;br /&gt;            ArgumentOutOfRangeException.ThrowIfNegative(startIndex);&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (length - count &amp;lt; startIndex) &lt;span class=&quot;hljs-comment&quot;&gt;//instead of (startIndex + count &amp;gt; items.Length) to prevent overflow&lt;/span&gt;&lt;br /&gt;            {&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ArgumentException(SR.ConcurrentStack_PushPopRange_InvalidCount);&lt;br /&gt;            }&lt;br /&gt;        }
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;        &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ThrowIfGreaterThan&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-title&quot;&gt;T&lt;/span&gt;&amp;gt;(&lt;span class=&quot;hljs-params&quot;&gt;T &lt;span class=&quot;hljs-keyword&quot;&gt;value&lt;/span&gt;, T other, [CallerArgumentExpression(&lt;span class=&quot;hljs-keyword&quot;&gt;nameof&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;value&lt;/span&gt;&lt;/span&gt;))] &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;? paramName&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;)&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;where&lt;/span&gt; T : IComparable&amp;lt;T&amp;gt;&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;value&lt;/span&gt;.CompareTo(other) &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                ThrowGreater(&lt;span class=&quot;hljs-keyword&quot;&gt;value&lt;/span&gt;, other, paramName);&lt;br /&gt;            }&lt;br /&gt;        }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;.NET Framework の方は &lt;a href=&quot;https://github.com/microsoft/referencesource/blob/51cf7850defa8a17d815b4700b67116e3fa283c2/mscorlib/system/collections/Concurrent/ConcurrentStack.cs#L473C1-L492&quot; title=&quot;referencesource/mscorlib/system/collections/Concurrent/ConcurrentStack.cs&quot;&gt;referencesource/mscorlib/system/collections/Concurrent/ConcurrentStack.cs&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;        &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ValidatePushPopRangeInput&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;T[] items, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; startIndex, &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; count&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (items == &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;items&amp;quot;&lt;/span&gt;);&lt;br /&gt;            }&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (count &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ArgumentOutOfRangeException(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;count&amp;quot;&lt;/span&gt;, Environment.GetResourceString(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ConcurrentStack_PushPopRange_CountOutOfRange&amp;quot;&lt;/span&gt;));&lt;br /&gt;            }&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; length = items.Length;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (startIndex &amp;gt;= length || startIndex &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ArgumentOutOfRangeException(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;startIndex&amp;quot;&lt;/span&gt;, Environment.GetResourceString(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ConcurrentStack_PushPopRange_StartOutOfRange&amp;quot;&lt;/span&gt;));&lt;br /&gt;            }&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (length - count &amp;lt; startIndex) &lt;span class=&quot;hljs-comment&quot;&gt;//instead of (startIndex + count &amp;gt; items.Length) to prevent overflow&lt;/span&gt;&lt;br /&gt;            {&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ArgumentException(Environment.GetResourceString(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ConcurrentStack_PushPopRange_InvalidCount&amp;quot;&lt;/span&gt;));&lt;br /&gt;            }&lt;br /&gt;        }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;.NET の方で &lt;code&gt;ArgumentOutOfRangeException.ThrowIfGreaterThan(startIndex, length)&lt;/code&gt; になったとき &lt;code&gt;startIndex = length&lt;/code&gt; のケースがエラーの対象に含まれなくなってんのよね。&lt;/p&gt;
&lt;p&gt;ドキュメントも見てきた。
.NET 8 が &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentstack-1.trypoprange?view=net-8.0#system-collections-concurrent-concurrentstack-1-trypoprange(-0())&quot; title=&quot;ConcurrentStack&lt;T&gt;.TryPopRange Method (System.Collections.Concurrent) | Microsoft Learn&quot;&gt;ConcurrentStack&lt;T&gt;.TryPopRange Method (System.Collections.Concurrent) | Microsoft Learn&lt;/a&gt; 。
.NET Framework 4.5.2 が &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentstack-1.trypoprange?view=netframework-4.5.2#system-collections-concurrent-concurrentstack-1-trypoprange(-0()-system-int32-system-int32)&quot; title=&quot;ConcurrentStack&lt;T&gt;.TryPopRange Method (System.Collections.Concurrent) | Microsoft Learn&quot;&gt;ConcurrentStack&lt;T&gt;.TryPopRange Method (System.Collections.Concurrent) | Microsoft Learn&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;どっちも &lt;code&gt;ArgumentOutOfRangeException&lt;/code&gt; にはこう書いてる。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ArgumentOutOfRangeException
startIndex or count is negative. Or &lt;strong&gt;startIndex is greater than or equal to the length of items.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;これって実装がドキュメントの挙動と違うねんけど、どっちが間違ってんの？となって理解進んでないのが現状。いやさっさと聞きに行ったら良いねんけど、どっちが妥当なんか自分の中で腑に落ちてなくて立ち止まってるところ。
空の配列渡したら何の操作もなく戻る現状の挙動の方が使い良くて好きやけど、ちゃんとした裏付けしたいのでもうちょっと調べる。&lt;/p&gt;
&lt;p&gt;例えばやで、仮にこう ↓ するとエラーにならんのよね。これは &lt;code&gt;item.Length&lt;/code&gt; より大きい index を &lt;code&gt;startIndex&lt;/code&gt; が指してるからやっぱおかしい気もするわ。
&lt;code&gt;count = 0&lt;/code&gt; の場合を特別扱いにするとかしないと辻褄あった API 仕様にならんのちゃうかなあ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;System.Collections.Concurrent.ConcurrentStack&lt;/span&gt;[&lt;span class=&quot;hljs-type&quot;&gt;System.String&lt;/span&gt;]]::new(); &lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt;.Push(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;a&amp;quot;&lt;/span&gt;); &lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt;.Count; &lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt;); &lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt;.TryPopRange(&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;a&amp;#x27;&lt;/span&gt;), &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 06 Oct 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-09-29-writing-cmdlet-in-fsharp-pt49.html</guid><link>https://krymtkts.github.io/posts/2024-09-29-writing-cmdlet-in-fsharp-pt49.html</link><title>F# で Cmdlet を書いてる pt.49 - コードクォート</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。最近のまとめ。&lt;/p&gt;
&lt;p&gt;以前&lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/fsharp/language-reference/code-quotations&quot; title=&quot;コードクォート&quot;&gt;コードクォート&lt;/a&gt;&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;でクエリの述語を実装してみるアイデアを記した。
多重で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/lambda-expressions-the-fun-keyword&quot; title=&quot;lambda&quot;&gt;lambda&lt;/a&gt; を入れ子にするよりもコードクォートで条件を平坦に繋いだ lambda にした方が速そうやなというやつ。&lt;/p&gt;
&lt;p&gt;趣味プロなのでパフォーマンスの計測とかせずそのまま実装に移してしまっても良かったが、一応サンプルとして lambda 入れ子版とコードクォート版を作って比較してみた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/fsharp-cmdlet-sandbox/blob/main/src/code-quote/Library.fs&quot; title=&quot;fsharp-cmdlet-sandbox/src/code-quote/Library.fs at main · krymtkts/fsharp-cmdlet-sandbox&quot;&gt;fsharp-cmdlet-sandbox/src/code-quote/Library.fs at main · krymtkts/fsharp-cmdlet-sandbox&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;コードはこんな感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; buildExpr conditions op &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        conditions&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.rev&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.reduce (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; acc x &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; e &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; op (acc e) (x e))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;(*&lt;br /&gt;        or condition&lt;br /&gt;        if expr1 x then true else xxx&lt;br /&gt;        if expr2 x then true else xxx&lt;br /&gt;        if expr3 x then true else xxx&lt;br /&gt;        if expr4 x then true else xxx&lt;br /&gt;        if expr5 x then true else false&lt;br /&gt;&lt;br /&gt;        and condition&lt;br /&gt;        if expr1 x then xxx else false&lt;br /&gt;        if expr2 x then xxx else false&lt;br /&gt;        if expr3 x then xxx else false&lt;br /&gt;        if expr4 x then xxx else false&lt;br /&gt;        if expr5 x then true else false&lt;br /&gt;    *)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; generateExpr conditions op &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; xVar &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Var(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;x&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;)&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; x &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; xVar &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Expr.Var &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Expr.Cast&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; combination &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; op &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Operator.And &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; c acc &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; Expr.IfThenElse(&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;@&lt;/span&gt; c &lt;span class=&quot;hljs-operator&quot;&gt;%&lt;/span&gt;x &lt;span class=&quot;hljs-operator&quot;&gt;@&amp;gt;&lt;/span&gt;, acc, &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;@&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;@&amp;gt;&lt;/span&gt;)&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Operator.Or &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; c acc &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; Expr.IfThenElse(&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;@&lt;/span&gt; c &lt;span class=&quot;hljs-operator&quot;&gt;%&lt;/span&gt;x &lt;span class=&quot;hljs-operator&quot;&gt;@&amp;gt;&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;@&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;@&amp;gt;&lt;/span&gt;, acc)&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;rec&lt;/span&gt; recBody acc conditions &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; conditions &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; [] &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; acc&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; condition &lt;span class=&quot;hljs-operator&quot;&gt;::&lt;/span&gt; conditions &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; acc &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; combination condition acc&lt;br /&gt;                recBody acc conditions&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; body &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; conditions &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.rev &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; [] &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;@@&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;@@&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; condition &lt;span class=&quot;hljs-operator&quot;&gt;::&lt;/span&gt; conditions &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; term &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Expr.IfThenElse(&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;@&lt;/span&gt; condition &lt;span class=&quot;hljs-operator&quot;&gt;%&lt;/span&gt;x &lt;span class=&quot;hljs-operator&quot;&gt;@&amp;gt;&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;@&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;@&amp;gt;&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;@&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;@&amp;gt;&lt;/span&gt;)&lt;br /&gt;                recBody term conditions&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; lambda &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Expr.Lambda(xVar, body)&lt;br /&gt;&lt;br /&gt;        lambda&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; LeafExpressionConverter.EvaluateQuotation&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;:?&amp;gt;&lt;/span&gt; string &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; bool
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コードクォートを使って組み合わせて作った lambda の AST を評価することで関数を動的に生成する。
body の組み立てに必要な &lt;code&gt;(||)&lt;/code&gt; や &lt;code&gt;(&amp;amp;&amp;amp;)&lt;/code&gt; は &lt;a href=&quot;https://github.com/dotnet/fsharp/blob/0a5901fd9c02b4c3b066678a1f7b68ce5939b774/src/FSharp.Core/prim-types.fs#L640-L644&quot; title=&quot;&lt;code&gt;F# の repo&lt;/code&gt;&quot;&gt;&lt;code&gt;F# の repo&lt;/code&gt;&lt;/a&gt; を見てわかるように &lt;code&gt;if ~ then ~ else&lt;/code&gt; の構文糖なので、 AST 組み立てでも &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-quotations-fsharpexpr.html#IfThenElse&quot; title=&quot;ExprIfThenElse&quot;&gt;ExprIfThenElse&lt;/a&gt; を利用して再現する。
コードクォート同士の組み合わせは &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations#splicing-operators&quot; title=&quot;Splicing operator&quot;&gt;Splicing operator&lt;/a&gt; を使って、最後に &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-quotations-fsharpexpr.html#Lambda&quot; title=&quot;Expr.Lambda&quot;&gt;Expr.Lambda&lt;/a&gt; に食わせることで lambda が出来上がるという仕組み。
AST の組み立ては型のサポートあれど、不正な文法だと実行時のエラーでしか気付けないのでちょっと面倒だった。しかし面倒さを払う価値ある強力な機能。&lt;/p&gt;
&lt;p&gt;以降は 2017 Razer Blade Stealth RAM 16 GB で計測した結果の話をする。&lt;/p&gt;
&lt;p&gt;結果の数値をコピってなかったが、件数が多いとコードクォートの方が明らかに速かった。
デメリットとして、コードクォートから lambda を構築するのに 100ms 程度のオーバーヘッドが生じるようだった。
lambda の方は単純に組み合わせていくだけなので、構築するのに大して時間がかからない。&lt;/p&gt;
&lt;p&gt;ただ lambda 版の方は入れ子の階層が深いほど lambda の呼び出し回数が増加してパフォ劣化が如実になるようだった。
そのオーバヘッドを回収するのはそんなに難しいことではないなと判断し、 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/224&quot; title=&quot;#224&quot;&gt;#224&lt;/a&gt; で pocof へ実装した。コードは&lt;a href=&quot;https://github.com/krymtkts/pocof/blob/417b109280568cc2c258acb677a72cb27ba24957/src/pocof/Query.fs#L147-L173&quot; title=&quot;こんな感じ&quot;&gt;こんな感じ&lt;/a&gt;でほぼサンプル実装と同じ。&lt;/p&gt;
&lt;p&gt;pocof 実装の note にもあるが、条件を末尾から組み立てる必要があるので &lt;code&gt;(Entry -&amp;gt; bool) list&lt;/code&gt; の並び順は事前に反転してある。
また pocof では &lt;code&gt;hashtable&lt;/code&gt; をサポートする関係で評価の対象が &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.dictionaryentry?view=net-8.0&quot; title=&quot;&lt;code&gt;DictionaryEntry&lt;/code&gt;&quot;&gt;&lt;code&gt;DictionaryEntry&lt;/code&gt;&lt;/a&gt; の場合の条件組み立てで key と value を評価した結果を &lt;code&gt;(||)&lt;/code&gt; か &lt;code&gt;(&amp;amp;&amp;amp;)&lt;/code&gt; で判定する必要があるのだけど、それは &lt;code&gt;Entry -&amp;gt; bool&lt;/code&gt; の関数を構築する時点で解決しておりここには載ってない。
パフォに関しては、 pocof の場合は動的にプロパティの値にアクセスするコードがあるのもあってか、サンプル実装よりも条件の組み合わせが増えた場合の lambda 版の速度劣化が著しかった。
コードクォート版なら条件の数が多くてもさほど遅くならない。複数条件を入力することが多いし、大いにコードクォートを使う価値があったな～という感じ。&lt;/p&gt;
&lt;p&gt;わずかでも pocof が速くなったし、コードクォートの実践もできたし、なかなか良かった。
コードクォートはまだ簡単な使い方しかできないし、型情報有り無しの取り扱いもこなれてないので、 pocof とは別の形でもいいので更に掘り下げたいな。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;プログラミング F# ではコード引用符と呼んでたがどうもコードクォートとカタカナ表記するのが一般的なようなのでこっちに寄せる。 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 29 Sep 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-09-22-start-booklog-pt3.html</guid><link>https://krymtkts.github.io/posts/2024-09-22-start-booklog-pt3.html</link><title>booklog はじめた 3</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2024-09-01-start-booklog.html&quot; title=&quot;先日はじめた booklog&quot;&gt;先日はじめた booklog&lt;/a&gt; が 1 ヶ月を超えた。
&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; でコード引用符使ってみるのも結構うまくいってる(つもりや)けど、今日は booklog を続けてみて思ったことついて記す。&lt;/p&gt;
&lt;p&gt;取り戻した読書習慣について触れるには未だ継続期間が短く、平日は特に追い立てられて読んでる感じが強い。読書習慣の再開で未だ次のステージに進んだ感じはなく、なんとか前いた地点に戻ろうとしてる感じかな。&lt;/p&gt;
&lt;p&gt;なので主に booklog 機能について思うところに触れる。
カレンダーによる streak の可視化の効果については前から触れてるので、それ以外について書いてみる。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;notes は未記入可能にしてるのだけど、今のところ毎日記入することにしている。
うっすい付け焼き刃のコメントでも毎回書かないといけないので、読んでる途中で頭の中を強制的にまとめる練習になっている。
恥ずかしくて書かないよりも、多少恥ずかしくても書いて、また読み直して理解を深めてからまた書いたらいい。
でもこればっかりは疲れ切ってるときに書けない可能性もあるので、 optional としておいておくつもり。&lt;/p&gt;
&lt;p&gt;書籍の属性と booklog を切り分けたのも良かった。
コピペする量が減っただけだが、モバイルでコピペして書き足すときに多少楽だと感じる。
書籍ごとのまとめページを作った際に、書籍の URL を決めるための ID を付与する必要があったけど、これも書籍の属性を切り分けてたことですんなりできた。
もしこれらの情報が booklog にベタのままだったらコピペ量爆発してクソダル案件になってたろうことは想像するに易い。&lt;/p&gt;
&lt;p&gt;書籍のまとめページは現状シンプルなものだが、サクッと振り返る程度には役に立つ。
未だ複数回読んだ書籍が booklog に出てきてないので、そういうのが現れたときに不便だったら更にグルーピングするのもいいかも知れない。&lt;/p&gt;
&lt;p&gt;総じて良いと思ってるけど、機能的にイマイチな点もある。&lt;/p&gt;
&lt;p&gt;まずリンクの位置がイマイチ。
画面最下部までジャンプしないと使えないあたりがそう。
書籍のまとめページは日々の booklog の書籍タイトルから飛べるようにしたので未だマシとして、年ごとのまとめが下部のリンクしかないので、カレンダーにそういう機能を足してもいいかも。&lt;/p&gt;
&lt;p&gt;あと気になるのが年ごとのまとめページの高さが相当高くなりそうな点。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; で毎日記録したパターンのサンプルを作って使用に耐えるか見てみた方が良いかな。
個人的に、ブログサービスでよくある月ごとに分かれてるようなのはページ内の検索性低くて好きじゃないので、文量が許すなら年ごとのままいきたい。&lt;/p&gt;
&lt;p&gt;結局近い将来にまた機能追加しないと満足いかなさそうではあるが、現状は満足しており習慣化の促進にもなってるので良いよな、という自画自賛の感想であった。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 22 Sep 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-09-15-writing-cmdlet-in-fsharp-pt48.html</guid><link>https://krymtkts.github.io/posts/2024-09-15-writing-cmdlet-in-fsharp-pt48.html</link><title>F# で Cmdlet を書いてる pt.48 - コード引用符</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。
日記にするのは約 1 ヵ月ぶりか。&lt;/p&gt;
&lt;p&gt;この 1 ヶ月の間、 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/209&quot; title=&quot;#209&quot;&gt;#209&lt;/a&gt; 以降はちょうど盆、日本の夏休みということで、移動の車中や山に囲まれて細々とした修正を重ねてきた。
&lt;code&gt;None&lt;/code&gt; operator を消して、それに伴うドキュメント修正し、プロパティ候補が case insensitive になってないバグ直したり、気になるコードをキレイにしてみたり...ほんと細々と。
そういうのの対処をしたあと、 &lt;a href=&quot;/posts/2024-09-01-start-booklog.html&quot; title=&quot;blog に booklog 機能を実装する&quot;&gt;blog に booklog 機能を実装する&lt;/a&gt; のに注力してる間は、完全に放置してた。
先週になって booklog が 100% ではないが概ね満足いくものになったので、全部ひっくるめて &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.15.0&quot; title=&quot;v0.15.0&quot;&gt;v0.15.0&lt;/a&gt; としてリリース。
めでたしめでたしさて次何やるかなというところだった。&lt;/p&gt;
&lt;p&gt;pocof のクエリ改善にコード引用符が使えそうやなという閃きが頭に降りてきた。その頃ちょうど &lt;a href=&quot;/booklogs/dmmf.html&quot; title=&quot;dmmf 本&quot;&gt;dmmf 本&lt;/a&gt; を読み終えたところで、本から特別な何かを得たわけじゃなかったが F# の本なんてそう日本語で読めるもんでもないので、刺激になったみたい。
dmmf 本には全然コード引用符書いてないけどｗ
母国語で興味のあるトピックに触れたことでシナプスが発火したのかな。いい経験したわ。&lt;/p&gt;
&lt;p&gt;そこで &lt;a href=&quot;/booklogs/programming-fsharp.html&quot; title=&quot;プログラミング F# のコード引用符の章&quot;&gt;プログラミング F# のコード引用符の章&lt;/a&gt; と&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations&quot; title=&quot;Code Quotations - F# | Microsoft Learn&quot;&gt;Code Quotations - F# | Microsoft Learn&lt;/a&gt; を読んでイメージを膨らませ、 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/224&quot; title=&quot;#224&quot;&gt;#224&lt;/a&gt; で実装はじめてみた。&lt;/p&gt;
&lt;p&gt;クエリの箇所は元が気合の再帰で実装してるのもあって(それより前は &lt;code&gt;List&lt;/code&gt; 処理でもっと遅かったけど)、軽く見た感じ結構速くなりそう。ところがうまくいかんのよね。昔のわたしが書いたテストをクリアできない。なんでかなーとなるわけやけど調査してみたら、ちょっと前に非同期レンダリングを入れたときに non-interactive mode のプロパティ検索がバグってたみたい。
処理が遅いうちは気付かないが、速くなるとプロパティ読み替え用の &lt;code&gt;Map&lt;/code&gt; の構築が追いつかなくて、プロパティ検索できなくなってるみたい。
&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/223&quot; title=&quot;#223&quot;&gt;#223&lt;/a&gt;
どうにもならんので準備がてらきょう直してみたらテスト通る様になったので、やっぱコイツが原因だったか... まあ直ってよかったわ。&lt;/p&gt;
&lt;p&gt;いまは未だ、入力されたクエリを個別の条件式の lambda にして &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; か &lt;code&gt;||&lt;/code&gt; でつなぐというところまでしかやってない。
これだと個別の条件式の数だけ lambda が増殖する。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/224/files#diff-7243da75219fb90456ee38cde35e5d411c463aa6ea393727bf526c89cd032587R232-R236&quot; title=&quot;Implementation to replace with a lightweight predicate. by krymtkts · Pull Request #224 · krymtkts/pocof&quot;&gt;Implementation to replace with a lightweight predicate. by krymtkts · Pull Request #224 · krymtkts/pocof&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; QueryPart.End &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; acc &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; [] &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; alwaysTrue&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;TODO:&lt;/span&gt; should i use code quotation to remove redundant lambda?&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; acc &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.rev &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.reduce (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; acc x &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; e &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; combination (acc e) (x e))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この余分な lambda を取り除いて平坦な式にするのにコード引用符を使えたらなって考えている。 fsi で試す感じ &lt;code&gt;&amp;lt;@ %acc &amp;amp;&amp;amp; x e @&amp;gt;&lt;/code&gt; って感じにできそうやねんよな。&lt;/p&gt;
&lt;p&gt;この対応で気になってるのはコード引用符の評価にどんくらいのオーバヘッドがあるかよくわかってないところ。
デフォで使える &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-linq-runtimehelpers-leafexpressionconverter.html#EvaluateQuotation&quot; title=&quot;&lt;code&gt;LeafExpressionConverter.EvaluateQuotation&lt;/code&gt;&quot;&gt;&lt;code&gt;LeafExpressionConverter.EvaluateQuotation&lt;/code&gt;&lt;/a&gt; を使うつもりなんやが、こいつのオーバヘッドが lambda を入れ子にしまくるオーバヘッドに勝れば、いい感じよな。&lt;/p&gt;
&lt;p&gt;他にも難しく考えすぎてややこしく遅くなってる pocof のコードって意外にありそうなので、まだまだ楽しませてくれそうな気がする。
続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 15 Sep 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-09-08-start-booklog-pt2.html</guid><link>https://krymtkts.github.io/posts/2024-09-08-start-booklog-pt2.html</link><title>booklog はじめた 2</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2024-09-01-start-booklog.html&quot; title=&quot;先日はじめた booklog&quot;&gt;先日はじめた booklog&lt;/a&gt; がきょうで 3 週間になった。
仕組みを構築したことで明らかにい強制力働いてるあたり自身の単純さに笑える。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; も再開したが、次やりたいことは多少練習しないとできなそうなので、今日はまた当ブログの booklog 機能について記す。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;booklog 機能のバグ修正と機能追加をちまちま行ってきた。
雑多なリファクタリング &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/232&quot; title=&quot;#232&quot;&gt;#232&lt;/a&gt; と
Light テーマの対応漏れ &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/233&quot; title=&quot;#233&quot;&gt;#233&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;既読日のセルからログにジャンプするリンクは、元々手抜きでその日の最初のログ(&lt;code&gt;${date}-1&lt;/code&gt;)に飛ぶようになってた。でも登録降順でログ表示しているから 1 番目に飛べても嬉しくない。なのでその日の最後のログに飛ぶようにした。これなら描画域先頭が最後になりその日のログをある程度一覧できて良い。&lt;/p&gt;
&lt;p&gt;あと忘れがちというか忘れてたのだけど light &amp;amp; dark theme 対応しているので、 Solarized Light っぽいカレンダーの色も考えた。ゆーても未読の日のセルの色を調整しただけなので、多少 cyan が目立つかなーというのはある。
また既読のセルの色を GitHub の Activity みたいに回数でグラデーションしたようなのは考えてないから、配色はコレで固まったかなという感じ。&lt;/p&gt;
&lt;p&gt;あと足したい機能として考えてるのが、サマリ系の機能。
current streak &amp;amp; longest streak を表示しておきたいのと、あと書籍ごとにログをまとめたページを作りたい。&lt;/p&gt;
&lt;p&gt;tag は要るかなと思って属性のみ設けていたけど、要らない気がしてきた。 tag のページから書籍のサマリの一覧があるといいかもなというのはあるが、そんなに既読の書籍が貯まるのは未だ先の話だと思う。
その時になって tag で書籍を管理できたらいいなという感覚があれば対処するものとしたい。
streak はそんなに難しくないけど、書籍ごとまとめはちょっと難しいなと考えてる。何が難しいかというと URL どうするかというところ。なんかいい感じに ASCII だけの URL にしたいけど日本語の書籍ばっか読むのでどーにもならん。 Punycode だと URL を一見して何のページかわからなくなるし。&lt;/p&gt;
&lt;p&gt;となるとやで、手動で書籍ごとに識別子を考えて付与してやるのがいいと思うが、 booklog の YAML に毎回書くのはちょっとなあという感じがする。
なので現実的な解としては書籍の名前から識別子を引くための YAML を個別に作って、そこに登録されてたら書籍のサマリを生成するってのがいいかな。ちょっとめんどいけど。
そうするとなればいま booklog の YAML に直に書いてる著者名や前読んだかの属性も本に寄せた方がログ追記も楽やろなとなる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/f4ee5cc9c3198596539d34588570619d7ba6e07a/src/Booklog.fs#L8-L16&quot; title=&quot;blog-fable/src/Booklog.fs at f4ee5cc9c3198596539d34588570619d7ba6e07a · krymtkts/blog-fable&quot;&gt;blog-fable/src/Booklog.fs at f4ee5cc9c3198596539d34588570619d7ba6e07a · krymtkts/blog-fable&lt;/a&gt; は以下のようになるはず。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// これが&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Booklog&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; date&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; bookTitle&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; bookAuthor&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; readCount&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; previouslyRead&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; pages&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; notes&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// こうなるはず&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Booklog&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; date&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; bookTitle&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; readCount&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; pages&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; notes&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// NEW!&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; bookTitle&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; bookAuthor&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; previouslyRead&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当初 1 ファイルにまとめたかったからそうしていたけど、結局ファイルを分けて正規化することになろうとはな。&lt;/p&gt;
&lt;p&gt;ファーストクソコードは依然そのままだが、今やりたいことが実現できれば機能的に満足いくようになって、そこで一段落かなと考えている。あとは習慣を継続することのみに注力できそう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 08 Sep 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-09-01-start-booklog.html</guid><link>https://krymtkts.github.io/posts/2024-09-01-start-booklog.html</link><title>booklog はじめた</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2024-08-18-github-streak-2-years.html&quot; title=&quot;先日 GitHub の Current Streak が 2 年に達した&quot;&gt;先日 GitHub の Current Streak が 2 年に達した&lt;/a&gt;のを機に、新しい習慣 booklog をはじめた。&lt;/p&gt;
&lt;p&gt;こちらが実装したモノで、&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/commit/1e3c577a087a89e8de5cfea729b6e1ee4db994ef&quot; title=&quot;Merge pull request #220 from krymtkts:feature/booklogs · krymtkts/blog-fable@1e3c577&quot;&gt;Merge pull request #220 from krymtkts:feature/booklogs · krymtkts/blog-fable@1e3c577&lt;/a&gt;
(この他にもちまちま修正を進めている)&lt;/p&gt;
&lt;p&gt;それを使って出力したのが以下の Booklog ページだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/booklogs.html&quot; title=&quot;krymtkts - Booklogs&quot;&gt;krymtkts - Booklogs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;正直なところ休みや空き時間でドバーッと書いたコードなので、まさにファーストクソコードと呼ぶに相応しき醜さだ。
未だバグあるし、ない機能もあるし、 module 構成なんか後付感すごく元の奴らと調和してない。
ただブツさえ生成できるようになればあとは改善やバグ修正は容易いので、まずはモノができたことを祝いたい。&lt;/p&gt;
&lt;p&gt;わたしの booklog は今のところカレンダーの生成と 1 年毎のページに booklog がまとめられるのみだが、今後は tag やタイトルでまとめたページを作るのも良さそうだなと考えている。
特に書籍ごとのグルーピングは工夫すれば書評になるよなと思っている。
小言の羅列で連続性がないかも知れないけど、そこはまとめてみてのお楽しみ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あといくつか実装前に想像していたことに対して実際どうなったのか書いていく。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;あと自分に習慣を刻み込むにあたり、 GitHub の activity の heatmap みたいなの(calendar chart とかいうらしい)、日本で例えるなら夏休みに体操の判子押してくれるカレンダーみたいなのがあればめちゃくちゃ強制力があるのは、 Current streak の経験からわかっている。
なのでそういう形式の book log を自分でこしらえようと思いついた。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;この通りなので booklog のカレンダーを作るにあたって見た目 GitHub の Activity を参考にした。
やはりアノ見た目は継続中毒者の心を鷲掴みにするので取り入れたかった。
とはいえこちらは静的ページなので、あちらのような click した日のデータを動的に読み込む機能はない。
代わりに 1 年間の booklog が日付降順で一覧されているので、その日付に飛べる。&lt;/p&gt;
&lt;p&gt;このカレンダーの実装は GitHub Copilot や ChatGPT に投げつけたらすぐできるやろと高をくくっていたのだが、コイツラ全然満足なコードを出せなかった。
細かい箇所では彼彼女らのコードが使われた箇所もあるが、結局大部分で自ら書いた。
おかげで？愛着のあるものになった。早くゴチャついた部分のコードもキレイにしてあげたい。&lt;/p&gt;
&lt;p&gt;この booklog のカレンダーだが、 &lt;a href=&quot;/archives.html&quot; title=&quot;Archives&quot;&gt;Archives&lt;/a&gt; のページで post と page の記録日見れてもいいかもなと思ったが、週末しか書かないと悲しいカレンダーになるので今んところはナシかな。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;そういう SaaS を使うのも良いが、やはりデータが自分の手元にないのは良くない。
plaintext に保存したデータから calendar chart が描けて、ついでに memo や読んだ回数、回数がわからなくても昔読んだことがあるかとかの属性も残せるやつ。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;booklog のデータの保存形式は以下のような &lt;a href=&quot;https://yaml.org/&quot; title=&quot;YAML&quot;&gt;YAML&lt;/a&gt; 形式にした。いくつかの省略可能な属性を省いている。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;date:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2024-08-19&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;bookTitle:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Domain&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Modeling&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Made&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Functional&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;関数型ドメインモデリング&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ドメイン駆動設計と&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;F#&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;でソフトウェアの複雑さに立ち向かおう&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;bookAuthor:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Scott&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Wlaschin&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;pages:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;vi&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;notes:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;冒頭を読んだだけ。なんとなく丁寧な印象を受けた。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;F# 側の厳密な型は以下のようにしている。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/ea7bec057edd5f9ec1420318e4627bf42ecd965d/src/Booklog.fs#L8C1-L16C38&quot; title=&quot;blog-fable/src/Booklog.fs at ea7bec057edd5f9ec1420318e4627bf42ecd965d · krymtkts/blog-fable&quot;&gt;blog-fable/src/Booklog.fs at ea7bec057edd5f9ec1420318e4627bf42ecd965d · krymtkts/blog-fable&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Booklog&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; date&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; bookTitle&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; bookAuthor&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; readCount&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; previouslyRead&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; pages&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; tags&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; ResizeArray &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; notes&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;readCount&lt;/code&gt; を記録できるようにしてみて、かつ回数を覚えてないようなものは &lt;code&gt;previouslyRead&lt;/code&gt; で前読んだことがあるのを意思表示する。
&lt;code&gt;readCount&lt;/code&gt; はそのままの数字が印字されるが、 &lt;code&gt;previouslyRead&lt;/code&gt; を入れてると &lt;code&gt;n+1&lt;/code&gt; のような印字になる。
&lt;code&gt;notes&lt;/code&gt; は無駄に Markdown で書けるようにしてある。技術書を読んでると感想にも &lt;code&gt;code&lt;/code&gt; を書きたくなるので、ほぼそのためだけ。
あとあんまりにもおもんない本であれば &lt;code&gt;notes&lt;/code&gt; を書くこともないかなと思い &lt;code&gt;option&lt;/code&gt; とした。
&lt;code&gt;tag&lt;/code&gt; は先述の通り未だ実装してないが事前に定義しておいた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;book log ができるまでは素朴に Markdown にでも記録していって、モノができたら変換して取り込むようにしてみようかな。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;毎日更新するので気軽にかける形式が良いし、 &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; には既に front matter のデータを取り込むための YAML パーサ &lt;a href=&quot;https://github.com/eemeli/yaml&quot; title=&quot;eemeli/yaml&quot;&gt;eemeli/yaml&lt;/a&gt; があったので、 YAML にした。
TOML も好きなのだけど、&lt;a href=&quot;https://toml.io/en/v1.0.0#array&quot; title=&quot;連続した要素の記述でカッコを書く&quot;&gt;連続した要素の記述でカッコを書く&lt;/a&gt;のだるそうやなとか、&lt;a href=&quot;https://toml.io/en/v1.0.0#string&quot; title=&quot;複数行の文字列&quot;&gt;複数行の文字列&lt;/a&gt;も面倒そうかなとか思い、やめた。
実際 2 週間ほど booklog をつけてきたが YAML ならかなり楽に更新できる。
まだ &lt;a href=&quot;https://github.com/lostintangent/gistpad/tree/master&quot; title=&quot;GistPad&quot;&gt;GistPad&lt;/a&gt; からの更新はしてない(commit sign がつかないのが潔癖症に引っかかる)けど、いつかやる日が来るはず。
そうなればほぼメモ更新間隔で booklog をつけれるようになる。&lt;/p&gt;
&lt;p&gt;理想的には &lt;code&gt;bookTitle&lt;/code&gt; と &lt;code&gt;bookAuthor&lt;/code&gt; は別のデータで管理してそれに参照するのが良いが、 1 ファイルに booklog を追記するだけで良いという利点を損なうので正規化していない。
書くときは愚直に前の booklog をコピペし展開していく運用にしている。
でもコピペと言っても毎回同じデータを書くのもダルいので、いつか省略できる仕組みは導入したい。&lt;/p&gt;
&lt;p&gt;あと &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; のプログラミングが久しぶりだったので地味に Fable から Node.js の eemeli/yaml 使うのでハマった。 &lt;code&gt;ResizeArray&lt;/code&gt; じゃないと array がマッピングされない点。
これで無駄に時間を溶かしたが次忘れないように note を残せたからヨシとする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; parseBooklogs (str&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; requires to define as ResizeArray to convert from raw JavaScript array.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; bs&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Booklog ResizeArray &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Yaml.parse str&lt;br /&gt;&lt;br /&gt;        bs &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.ofSeq
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;モノがないとあんまり続けられる気がしないけど、習慣化の道筋はできたのでなんかいけそうな気がしてきた。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;これについては booklog 機能をブログに実装すると決めたときから、書いておかないと booklog カレンダーを華やかすことができないという強制力が働いて、機能が出来上がるまでの間も習慣を続けられた。
機能なくても良かったのかも知れんが、長期になったら続かなかっただろうし多分必要だった。これは必然やな。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;ちまちま booklog の実装してた間は &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; を放置してたけど、今後はそんな集中していじることもないと思うので、まずリリースから再開しよう。
と言いつつこの日記をしたためている間にバグを見つけた。実装してない機能もあるし、 pocof にはもう少し待ってもらうのが良いか、あるいは行ったり来たりが良いか。
気分と相談してやること決めていく。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 01 Sep 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-08-25-resolve-terminal-icons-unclear-error.html</guid><link>https://krymtkts.github.io/posts/2024-08-25-resolve-terminal-icons-unclear-error.html</link><title>Terminal-Icons のよくわからないエラーを解決する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;ちょっと前から、 pwsh 起動時の profile 読み込みでエラーが出るようになった。&lt;/p&gt;
&lt;p&gt;どうも出どころは &lt;a href=&quot;https://github.com/devblackops/Terminal-Icons/&quot; title=&quot;Terminal-Icons&quot;&gt;Terminal-Icons&lt;/a&gt; みたい。 &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7.4#errorview&quot; title=&quot;&lt;code&gt;$ErrorView = &amp;#39;DetailedView&amp;#39;&lt;/code&gt;&quot;&gt;&lt;code&gt;$ErrorView = &amp;#39;DetailedView&amp;#39;&lt;/code&gt;&lt;/a&gt; にして &lt;code&gt;$Error&lt;/code&gt; で表示した内容は以下の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Exception             :&lt;br /&gt;    Type        : System.Management.Automation.RuntimeException&lt;br /&gt;    ErrorRecord :&lt;br /&gt;        Exception             :&lt;br /&gt;            Type    : System.Management.Automation.ParentContainsErrorRecordException&lt;br /&gt;            Message : Index operation failed; the array index evaluated to null.&lt;br /&gt;            HResult : -2146233087&lt;br /&gt;        CategoryInfo          : InvalidOperation: (:) [], ParentContainsErrorRecordException&lt;br /&gt;        FullyQualifiedErrorId : NullArrayIndex&lt;br /&gt;        InvocationInfo        :&lt;br /&gt;            ScriptLineNumber : 3416&lt;br /&gt;            OffsetInLine     : 5&lt;br /&gt;            HistoryId        : 1&lt;br /&gt;            ScriptName       : C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0\Terminal-Icons.psm1&lt;br /&gt;            Line             :     $userThemeData.Themes.Icon[$userIconTheme.Name] = $userIconTheme&lt;br /&gt;&lt;br /&gt;            Statement        : $userThemeData.Themes.Icon[$userIconTheme.Name] = $userIconTheme&lt;br /&gt;            PositionMessage  : At C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0\Terminal-Icons.psm1:3416 char:5&lt;br /&gt;                               +     $userThemeData.Themes.Icon[$userIconTheme.Name] = $userIconTheme&lt;br /&gt;                               +     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;            PSScriptRoot     : C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0&lt;br /&gt;            PSCommandPath    : C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0\Terminal-Icons.psm1&lt;br /&gt;            CommandOrigin    : Internal&lt;br /&gt;        ScriptStackTrace      : at &amp;lt;ScriptBlock&amp;gt;, C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0\Terminal-Icons.psm1: line 3416&lt;br /&gt;                                at &amp;lt;ScriptBlock&amp;gt;, C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0\Terminal-Icons.psm1: line 3414&lt;br /&gt;                                at &amp;lt;ScriptBlock&amp;gt;, C:\Users\takatoshi\OneDrive\Documents\PowerShell\Scripts\PSResource\PSResource.psm1: line 27&lt;br /&gt;                                at &amp;lt;ScriptBlock&amp;gt;, C:\Users\takatoshi\OneDrive\Documents\PowerShell\Microsoft.PowerShell_profile.ps1: line 18&lt;br /&gt;                                at &amp;lt;ScriptBlock&amp;gt;, &amp;lt;No file&amp;gt;: line 1&lt;br /&gt;    TargetSite  : System.Object CallSite.Target(System.Runtime.CompilerServices.Closure, System.Runtime.CompilerServices.CallSite, System.Object, System.Object, System.Object)&lt;br /&gt;    Message     : Index operation failed; the array index evaluated to null.&lt;br /&gt;    Data        : System.Collections.ListDictionaryInternal&lt;br /&gt;    Source      : Anonymously Hosted DynamicMethods Assembly&lt;br /&gt;    HResult     : -2146233087&lt;br /&gt;    StackTrace  :&lt;br /&gt;   at CallSite.Target(Closure, CallSite, Object, Object, Object)&lt;br /&gt;   at System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2)&lt;br /&gt;   at System.Management.Automation.Interpreter.DynamicInstruction`4.Run(InterpretedFrame frame)&lt;br /&gt;   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)&lt;br /&gt;CategoryInfo          : InvalidOperation: (:) [], RuntimeException&lt;br /&gt;FullyQualifiedErrorId : NullArrayIndex&lt;br /&gt;InvocationInfo        :&lt;br /&gt;    ScriptLineNumber : 3416&lt;br /&gt;    OffsetInLine     : 5&lt;br /&gt;    HistoryId        : 1&lt;br /&gt;    ScriptName       : C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0\Terminal-Icons.psm1&lt;br /&gt;    Line             :     $userThemeData.Themes.Icon[$userIconTheme.Name] = $userIconTheme&lt;br /&gt;&lt;br /&gt;    Statement        : $userThemeData.Themes.Icon[$userIconTheme.Name] = $userIconTheme&lt;br /&gt;    PositionMessage  : At C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0\Terminal-Icons.psm1:3416 char:5&lt;br /&gt;                       +     $userThemeData.Themes.Icon[$userIconTheme.Name] = $userIconTheme&lt;br /&gt;                       +     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;    PSScriptRoot     : C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0&lt;br /&gt;    PSCommandPath    : C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0\Terminal-Icons.psm1&lt;br /&gt;    CommandOrigin    : Internal&lt;br /&gt;ScriptStackTrace      : at &amp;lt;ScriptBlock&amp;gt;, C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0\Terminal-Icons.psm1: line 3416&lt;br /&gt;                        at &amp;lt;ScriptBlock&amp;gt;, C:\Program Files\PowerShell\Modules\Terminal-Icons\0.11.0\Terminal-Icons.psm1: line 3414&lt;br /&gt;                        at &amp;lt;ScriptBlock&amp;gt;, C:\Users\takatoshi\OneDrive\Documents\PowerShell\Scripts\PSResource\PSResource.psm1: line 27&lt;br /&gt;                        at &amp;lt;ScriptBlock&amp;gt;, C:\Users\takatoshi\OneDrive\Documents\PowerShell\Microsoft.PowerShell_profile.ps1: line 18&lt;br /&gt;                        at &amp;lt;ScriptBlock&amp;gt;, &amp;lt;No file&amp;gt;: line 1&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/devblackops/Terminal-Icons/blob/46866e45a602566bb8a52af5a04dac1d69482c29/Terminal-Icons/Terminal-Icons.psm1#L43-L48&quot; title=&quot;&lt;code&gt;Terminal-Icons.psm1&lt;/code&gt; のここ&quot;&gt;&lt;code&gt;Terminal-Icons.psm1&lt;/code&gt; のここ&lt;/a&gt; でエラーが出てる。
&lt;code&gt;the array index evaluated to null.&lt;/code&gt; とのことなので &lt;code&gt;$userIconTheme.Name&lt;/code&gt; が &lt;code&gt;$null&lt;/code&gt; であると。んなアホな。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Load user icon and color themes&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# We&amp;#x27;re ignoring the old &amp;#x27;theme.xml&amp;#x27; from Terimal-Icons v0.3.1 and earlier&lt;/span&gt;&lt;br /&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$userThemePath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Filter&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;*_icon.xml&amp;#x27;&lt;/span&gt;).ForEach({&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$userIconTheme&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Import-CliXml&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$userThemeData&lt;/span&gt;.Themes.Icon[&lt;span class=&quot;hljs-variable&quot;&gt;$userIconTheme&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;.Name&lt;/span&gt;] = &lt;span class=&quot;hljs-variable&quot;&gt;$userIconTheme&lt;/span&gt;&lt;br /&gt;})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;なんじゃー？と思ったら自分の icon テーマ &lt;code&gt;krymtkts&lt;/code&gt; の名称が取れてないっぽい。なんでよ。
更に追うと &lt;code&gt;krymtkts.psd1&lt;/code&gt; から生成される &lt;code&gt;$env:APPDATA\powershell\Community\Terminal-Icons\krymtkts_icon.xml&lt;/code&gt; で &lt;code&gt;Name&lt;/code&gt; 要素がダブってた。
&lt;code&gt;krymtkts_icon.xml&lt;/code&gt; の場合は先頭と末尾にふたつ &lt;code&gt;Name&lt;/code&gt; 要素のセクションができてた。以下再現イメージ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;Objs&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Version&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;1.1.0.1&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http://schemas.microsoft.com/powershell/2004/04&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;Obj&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;RefId&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;TN&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;RefId&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;T&lt;/span&gt;&amp;gt;&lt;/span&gt;Deserialized.System.Collections.Hashtable&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;T&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;T&lt;/span&gt;&amp;gt;&lt;/span&gt;Deserialized.System.Object&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;T&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;TN&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;DCT&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;En&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;S&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;N&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;Name&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;S&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;S&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;N&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Value&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;krymtkts&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;S&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;En&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;En&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- 省略 --&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;En&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;En&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;S&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;N&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;Name&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;S&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;S&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;N&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Value&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;krymtkts&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;S&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;En&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;DCT&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;Obj&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;Objs&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このように &lt;code&gt;Name&lt;/code&gt; 要素がダブってると値が &lt;code&gt;$null&lt;/code&gt; になってだめみたい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$x&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Import-CliXml&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$env:APPDATA&lt;/span&gt;\powershell\Community\Terminal&lt;span class=&quot;hljs-literal&quot;&gt;-Icons&lt;/span&gt;\krymtkts_icon.xml&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$x&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name                           Value&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ----                           -----&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name                           krymtkts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name                           krymtkts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Types                          {[Directories, System.Collections.Hashtable], [Files, System.Collections.Hashtable], [Directories, Sy…&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$x&lt;/span&gt;.Name &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;なんでこれが発生して解消の仕方わからんので、とりあえず &lt;code&gt;krymtkts_icon.xml&lt;/code&gt; 末尾の &lt;code&gt;Name&lt;/code&gt; をコメントアウトし profile 再読み込みで &lt;code&gt;Terminal-Icons&lt;/code&gt; を再度 import したら、ダブらずに生成されるようになった。
起動時に正常な theme は &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/export-clixml?view=powershell-7.4&quot; title=&quot;&lt;code&gt;Export-CliXml&lt;/code&gt;&quot;&gt;&lt;code&gt;Export-CliXml&lt;/code&gt;&lt;/a&gt; されてて、そこでコメントが消えてきれいになったみたい。&lt;/p&gt;
&lt;p&gt;流れとしては、 &lt;a href=&quot;https://github.com/devblackops/Terminal-Icons/blob/46866e45a602566bb8a52af5a04dac1d69482c29/Terminal-Icons/Terminal-Icons.psm1#L37&quot; title=&quot;&lt;code&gt;Import-Preferences&lt;/code&gt;&quot;&gt;&lt;code&gt;Import-Preferences&lt;/code&gt;&lt;/a&gt; が &lt;code&gt;prefs.xml&lt;/code&gt; に設定された &lt;code&gt;CurrentIconTheme&lt;/code&gt; を読み込み、そのあと問題なければ &lt;a href=&quot;https://github.com/devblackops/Terminal-Icons/blob/46866e45a602566bb8a52af5a04dac1d69482c29/Terminal-Icons/Terminal-Icons.psm1#L68-L71&quot; title=&quot;&lt;code&gt;Export-CliXml&lt;/code&gt;&quot;&gt;&lt;code&gt;Export-CliXml&lt;/code&gt;&lt;/a&gt; で保存される。
はじめは途中で &lt;code&gt;Terminal-Icons.psm1&lt;/code&gt; がコケるため保存までいかなかったが、コメントアウトしてエラーが無くなり &lt;code&gt;krymtkts_icon.xml&lt;/code&gt; が補正された結果が保存されたと。&lt;/p&gt;
&lt;p&gt;解せんのは、何故このエラー原因となった &lt;code&gt;Name&lt;/code&gt; の重複が発生したか、というところ。
元ファイルが変わってないのと Module 自体も変わってないのを考えたら、壊したのは &lt;code&gt;Export-CliXml&lt;/code&gt; よなー。
&lt;code&gt;*_icon.xml&lt;/code&gt; が壊れるという意味で似たような Issue はあれど、今回のケースでは XML の syntax がが壊れることはなかったしなんかよくわからん。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/devblackops/Terminal-Icons/issues/121&quot; title=&quot;Getting error on importing the terminal icons module · Issue #121 · devblackops/Terminal-Icons&quot;&gt;Getting error on importing the terminal icons module · Issue #121 · devblackops/Terminal-Icons&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ちょっとよくわからんので追いきれない感じがしたが、暫定的でも対処法がわかってよかった。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 25 Aug 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-08-18-github-streak-2-years.html</guid><link>https://krymtkts.github.io/posts/2024-08-18-github-streak-2-years.html</link><title>GitHub streak 2 years</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;夏休みという名の 1 週間の休みの内に &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の細かな開発を結構できたのだけど、きょうはもうすぐ 2 年を迎える Github の Current streak について書く。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;2022-08-22 から Current streak が続いてるので、来たる 2024-08-21 で 731(閏年を含む) 連続になって 2 年間続けたことになる。
365 に至るまでの 1 年目は、継続するためのちょっとした頑張りが今よりも必要だったように思う。
でも 2 年目ともなると習慣が定着してきて、適切な言葉が見つからないが惰性のようなもので継続する心理的負担は減ったように思う。
単純にサンクコストバイアスをポジティブな方向に使えてるってだけかも知れんけどな。積み上げを壊すのが怖い的な。しらんけど。&lt;/p&gt;
&lt;p&gt;日常的ではない終日束縛されるようなイベント、例えば旅行だったり法事に行ったときでも、普通にプログラミングしたり日記を書いて普通にコミットできるようになった。
何か他のことをやってるときに頭の中にあれやろこれやろが浮かんでて、それを移動中とか空いた時間で commit する(ただし両手が塞がっていない場合に限る)。
事実、家事の合間に laptop のところに行って数分でまた料理作りに戻ってとか、毎週末よくやってる。
以前は意識的にやっていたこと、例えば何を commit するか日記に何書こうかどうしよう等を考えるの自体は無くなってないけど、それらを浮かばせておく行動が生活に溶け込んでるから何とも思わなくなったと認識している。&lt;/p&gt;
&lt;p&gt;でも未だたまに多忙だったりすると「あー、なんか commit しないと途切れるな」みたいな感じで継続することが意識に上がってくる状態なので、これが息をするように commit するようになってくれば、自分でも胸張ってある境地に達したと言えるかな。
「面倒くさいけど今日も commit したわ」「気付いたら commit してたわ」みたいな。
自分でも狂ってるなと思えるところまで行きたい。
既に家族からはいつも laptop のところを行き来してて頭おかしいと思われてる可能性もあるけど。&lt;/p&gt;
&lt;p&gt;思えば、昔から何かをずっと続けることが得意なのかも知れない。流行りが終わったゲームも延々 1 人でプレイし続けてたりしてた。
気に入った映画は何度も観れるし、読んだ事がある本を何度も読める。
太く短い瞬発力ある取り組みは苦手(疲れる)だが、薄く延々と続くようなの、そういうのが多分向いてる。
エンジニアの知人だったりバンドメンバが「モチベーションが...」とか言うて活動を休止したりするのも理解できないことが殆どなので、多分わたしの脳みその中のブレーキが壊れてる。それはある意味走り出したら止まれない暴走特急なのかも。
こういうのはもっと若い頃に気づきたかったな。年食って経験増えたから気づいたのかも知れんけど。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;2 年間 GitHub の Current streak を続けたあと、 Current streak の次のマイルストンはやっぱ 4 桁突入の 1000 かなと思うが、そこまでの距離はもう遠くない。
自分が死なない限り、毎日積み上げていったら 2025-05 には達成することになるので、歩いてきた道のりより短いねんよな。
となると習慣化した Current streak がヌルゲーになってしまって張りがないので、他に狂気の取り組みを始められないかと考えている。
(今の Current streak を public なコントリのみに絞るというのもアリだろうがそれは普通に続かなそうｗなので時期尚早と見た)&lt;/p&gt;
&lt;p&gt;今年の目標にあるものから選ぶなら、ずっと習慣化に失敗している読書がいいかな。
これは何度も書いてる話ではあるが、通勤がなくなって読書への強制力がなくなり、読書習慣が失われてしまった。
親切な知人エンジニアが月に数回輪読会を一緒にやってくれていて、そこでなんとか最低限の読書をしているが、理想はもっと狂ったように読書したい。&lt;/p&gt;
&lt;p&gt;これは言い訳だが、最近は調べ物が多くて Web の文書とかを読みまくる&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;ので文字で胃もたれして読めなくなってのはあるかも知れん。
そもそもの食 ≒ 読書量が細ってるから自主的な読書が受け付けれなくなったんじゃないかと感じている。
そういう状況だったのもあって最近は積読を増やさないような本の買い方になってたのだけど、また習慣化した暁には昔みたいに積極的に積読していきたい。
(増えるだけだと物理本の場合はほんと場所に困るので適切に陳腐化した書籍だったりを処分するのも含めてやりたい)&lt;/p&gt;
&lt;p&gt;単に食が細ってるだけナノだったら、毎日少しずつリハビリしていけばまたモリモリ食べれる様になるかも知れんよな。
とりあえず 1 日に数ページでいいから、読み始めてみようか。&lt;/p&gt;
&lt;p&gt;あと自分に習慣を刻み込むにあたり、 GitHub の activity の heatmap みたいなの(calendar chart とかいうらしい)、日本で例えるなら夏休みに体操の判子押してくれるカレンダーみたいなのがあればめちゃくちゃ強制力があるのは、 Current streak の経験からわかっている。
なのでそういう形式の book log を自分でこしらえようと思いついた。
そういう SaaS を使うのも良いが、やはりデータが自分の手元にないのは良くない。
plaintext に保存したデータから calendar chart が描けて、ついでに memo や読んだ回数、回数がわからなくても昔読んだことがあるかとかの属性も残せるやつ。
book log ができるまでは素朴に Markdown にでも記録していって、モノができたら変換して取り込むようにしてみようかな。
モノがないとあんまり続けられる気がしないけど、習慣化の道筋はできたのでなんかいけそうな気がしてきた。&lt;/p&gt;
&lt;p&gt;毎日 commit し続けるとか、読書習慣を始めるのに記録方法から作ってまで読書を習慣付けたいとか、この行動が具体的な何かにつながるかはサッパリ想像もつかない。
でもあんまり世間一般の人がやってなさそうなことほど楽しくなるし、その継続で磨き上げられた何かは一般のそれとは全く違うものになってるはずよ。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;これが現職での仕事がそうなのか時代が変わったのかは検証してない &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 18 Aug 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-08-11-writing-cmdlet-in-fsharp-pt47.html</guid><link>https://krymtkts.github.io/posts/2024-08-11-writing-cmdlet-in-fsharp-pt47.html</link><title>F# で Cmdlet を書いてる pt.47</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-08-04-writing-cmdlet-in-fsharp-pt46.html&quot; title=&quot;前回に引き続き&quot;&gt;前回に引き続き&lt;/a&gt; &lt;code&gt;Query.run&lt;/code&gt; 自体の最適化をしている。いつ終わるんだよ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/208&quot; title=&quot;#208&quot;&gt;#208&lt;/a&gt; 、 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/209&quot; title=&quot;#209&quot;&gt;#209&lt;/a&gt; でコツコツ改善？してみた。
わたしの laptop で 1 ~ 10 万までの数字から 1 つ選ぶのに 4 秒切りたかったがそこには達せず、伸びも見られなくなってきた。
単純な検索についてはそうなんやけど、プロパティ検索時においては修正前後で &lt;code&gt;null&lt;/code&gt; の扱いがめちゃくちゃ雑なママ放置してて例外処理に任せてた部分を適切に取り持ったことで爆発的に速くなった。
他にもプロパティ検索周りはまだ改善の余地があるので、後ほど処置したい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions&quot; title=&quot;判別共用体&quot;&gt;判別共用体&lt;/a&gt; を &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/structs&quot; title=&quot;構造体&quot;&gt;構造体&lt;/a&gt; に置き換える最適化は、適用しどころを間違ってたみたい。
&lt;a href=&quot;https://github.com/krymtkts/pocof/blob/cc9c317247adf010ff54cfdfc03bfbe70044922b/src/pocof/Data.fs#L138-L142&quot; title=&quot;&lt;code&gt;Data.Entry&lt;/code&gt;&quot;&gt;&lt;code&gt;Data.Entry&lt;/code&gt;&lt;/a&gt; を構造体にしても効果なかった。
直感が外れたのは単純に理解が間違ってたからで、変更頻度が高い使い捨てのデータに対してこのアプローチをすべきだったからだ。
&lt;code&gt;Data.Entry&lt;/code&gt; はオブジェクトの生成頻度こそ高けれど、一度生成されたあと変更されることがなく、アプリが終了するまで永続的に保持される。
そのため構造体が適しておらず最適化に貢献しなかったという理解だ。
代わりに &lt;a href=&quot;https://github.com/krymtkts/pocof/blob/cc9c317247adf010ff54cfdfc03bfbe70044922b/src/pocof/Query.fs#L169-L201&quot; title=&quot;&lt;code&gt;processQueries&lt;/code&gt;&quot;&gt;&lt;code&gt;processQueries&lt;/code&gt;&lt;/a&gt; 内でのみ利用される &lt;a href=&quot;https://github.com/krymtkts/pocof/blob/cc9c317247adf010ff54cfdfc03bfbe70044922b/src/pocof/Query.fs#L158-L167&quot; title=&quot;&lt;code&gt;QueryResult&lt;/code&gt;&quot;&gt;&lt;code&gt;QueryResult&lt;/code&gt;&lt;/a&gt; に対して利用した。
繰り返し生成されて関数内で利用されるのみでまさに使い捨て用途がハマってる。でもそんな爆発的な効果は出てなくて少し残念。&lt;/p&gt;
&lt;p&gt;実は最近のこの最適化で結構バグってるみたいで、細かく見れていなかった箇所のテストケースを追加するなどもしている。
その中で &lt;a href=&quot;https://github.com/krymtkts/pocof/blob/cc9c317247adf010ff54cfdfc03bfbe70044922b/src/pocof/Data.fs#L238&quot; title=&quot;&lt;code&gt;Operator.None&lt;/code&gt;&quot;&gt;&lt;code&gt;Operator.None&lt;/code&gt;&lt;/a&gt; もう要らんのちゃうかないう気が湧いてきたので、今後取り除いていくつもり。
先述した最適化に伴うバグには、この &lt;code&gt;Operator.None&lt;/code&gt; の挙動が変わってしまってるのも含まれる。
&lt;code&gt;Operator.None&lt;/code&gt; を取り除いたことでロジックが簡略化されれば多少最適化にも貢献するだろう的なことも期待している。&lt;/p&gt;
&lt;p&gt;元々空白を含めて検索したい場合に正規表現気にせず使えたらいいかなと思って準備したけど、キーワードの組み合わせで絞り込むことが多くてほぼ使わんし。
作った本人が使いこなせていないというのは恥ずかしい話やが、不要だと思った時に機能を取り除けるのは作った本人しか無理なので、この際やってしまう。&lt;/p&gt;
&lt;p&gt;結構この最適化周りで修正重ねてるけどいまいちリリースしていいかなって思える状態にならない。
はよ出したいけど次の v0.15 を出すのはもう少し先になりそう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 11 Aug 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-08-04-writing-cmdlet-in-fsharp-pt46.html</guid><link>https://krymtkts.github.io/posts/2024-08-04-writing-cmdlet-in-fsharp-pt46.html</link><title>F# で Cmdlet を書いてる pt.46</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-07-28-writing-cmdlet-in-fsharp-pt45.html&quot; title=&quot;前回に引き続き&quot;&gt;前回に引き続き&lt;/a&gt; &lt;code&gt;Query.run&lt;/code&gt; 自体の最適化をしている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/208/files&quot; title=&quot;ちまちまと変更を加えて&quot;&gt;ちまちまと変更を加えて&lt;/a&gt;、もとよりは多少速くなってそう。
わたしのしょぼい 2017 年製 laptop で 1 ~ 100000 までの数字から 100000 を探し出すのに 5 秒前後かかっていたのが、 4.5 秒前後になったぽい。
ほんまかー？という感じではあるが、実際に数を増やして 1 ~ 500000 までの数字から 500000 を探し出してみても修正後の方が 2 ~ 2.5 秒速いので、効果は確かなようだ。&lt;/p&gt;
&lt;p&gt;前回の修正も含めて行った最適化は、 &lt;code&gt;inline&lt;/code&gt; 化や &lt;code&gt;List&lt;/code&gt; を末尾再帰に置き換えるといった簡単なものだけだ。
それでも noob F# ninja のわたしには多くの気付きがあった。
&lt;code&gt;inline&lt;/code&gt; をつけた関数であっても関数合成を使うと &lt;code&gt;inline&lt;/code&gt; 化されないので pipeline を使う必要があるとか。&lt;/p&gt;
&lt;p&gt;また特定のケースでは末尾再帰が &lt;code&gt;List&lt;/code&gt; より速いようで、少し驚いた。 &lt;code&gt;List&lt;/code&gt; は結構速いモノの認識だったが、更に突き詰めた局所最適化だと末尾再帰という primitive な形に落ち着くねんな...という気づきを獲た。
まーでもどの言語でも配列やリスト構造をそれ用の関数でグルグル回すよりは単純なループのほうが速いこともあるし、そういうことなんやろなという認識(末尾再帰は loop に最適化されるため)。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions&quot; title=&quot;判別共用体&quot;&gt;判別共用体&lt;/a&gt; を &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/structs&quot; title=&quot;構造体&quot;&gt;構造体&lt;/a&gt; に置き換えるとかのより踏み込んだ最適化はまだやってない。
まだただの直感だが、 &lt;a href=&quot;https://github.com/krymtkts/pocof/blob/main/src/pocof/Data.fs#L100-L104&quot; title=&quot;&lt;code&gt;Data.Entry&lt;/code&gt;&quot;&gt;&lt;code&gt;Data.Entry&lt;/code&gt;&lt;/a&gt; を構造体にしたら、処理するデータ件数が大きいほど効果があるのかもなと思っている。
この手法は確か &lt;a href=&quot;https://github.com/bcarruthers/garnet&quot; title=&quot;bcarruthers/garnet&quot;&gt;bcarruthers/garnet&lt;/a&gt; を見つけたときに知ったのだったが、 pros. cons. あり検証を要するのでインスタントにできるものでは
そこに踏み込むにはまだやっていないことがあるので、計測・検証して順次試していくつもり。&lt;/p&gt;
&lt;p&gt;他にも F# の最適化の手段は色々あるようで、 F# performance tips でググった上位 3 つを読むだけでもお腹いっぱいになってしまった。
全部は消化しきれないので地道に .NET のプロファイリングから学んでいくか。
ここ 1 月くらいで ILSpy を使い始めたのだけど、更にツールが増えるのかな...&lt;/p&gt;
&lt;p&gt;因みに GitHub Copilot や ChatGPT に聞いても似たような回答をくれるが、(文脈理解してるはずなのに)一般的な話をされて pocof の文脈にそぐわないような回答をいただくばかり。
なので、この件に関してはあまり使い物になってない(プロンプトが悪いのかも知れんが)。
リスト処理を末尾再帰に変えてくれとか具体的な指示になったら元気に回答くれるけど(微妙に間違ってるけど)。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bartoszsypytkowski.com/writing-high-performance-f-code/&quot; title=&quot;Writing high performance F# code&quot;&gt;Writing high performance F# code&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;これはレイヤが低めで .NET の理解度が求められ難しめ&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://dev.to/t4rzsan/real-life-performance-optimizations-in-f-3nep&quot; title=&quot;Real life performance optimizations in F# - DEV Community&quot;&gt;Real life performance optimizations in F# - DEV Community&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;これはかなり簡単な部類&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/9252660/how-to-optimize-f-programs-generally&quot; title=&quot;performance - How to optimize F# programs generally - Stack Overflow&quot;&gt;performance - How to optimize F# programs generally - Stack Overflow&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;まとめみたいなやつ。辿るのがダルい&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;まだやっていないことの 1 つは今対処中で、 &lt;code&gt;Query.run&lt;/code&gt; が実行されるときに行われていたリストを取り除くことだ。
これは検索条件を &lt;code&gt;List&lt;/code&gt; に詰め込んでいたところを残していたので、そこを判別共用体で作った自作の連結リストに変えるものだ。これも多少速くなったようだ。
教科書的な木構造の実装なんかで見た判別共用体の連鎖を普通に実用レベルで使えるねんなというのは気付きやな。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/209&quot; title=&quot;#209&quot;&gt;#209&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;     [&amp;lt;RequireQualifiedAccess&amp;gt;]&lt;br /&gt;     [&amp;lt;NoComparison&amp;gt;]&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    [&amp;lt;NoEquality&amp;gt;]&lt;/span&gt;&lt;br /&gt;     type QueryPart =&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        | Normal of value: string&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        | Property of lowerCaseName: string * value: string&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        | Normal of is: (string -&amp;gt; bool)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        | Property of lowerCaseName: string * is: (string -&amp;gt; bool)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    [&amp;lt;RequireQualifiedAccess&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    [&amp;lt;NoComparison&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    [&amp;lt;NoEquality&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    type QueryNode =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        | Part of head: QueryPart * tail: QueryNode&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        | End&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;今はこんな風に変えてて、まだちょっとイマイチ。 &lt;code&gt;QueryPart&lt;/code&gt; と &lt;code&gt;QueryNode&lt;/code&gt; は分ける必要ないかなと思っているところ。
元は検索条件の値だけを持った &lt;code&gt;List&lt;/code&gt; を取り回して、 &lt;code&gt;Query.processQueries&lt;/code&gt; 自体が引数に持つテスト関数で条件に一致しているか見ていた。
これを検索条件の関数を持った連結リストにして、 &lt;code&gt;Query.processQueries&lt;/code&gt; 自体はテスト関数を持たなくさせる。
これは、今 &lt;code&gt;Regex.IsMatch&lt;/code&gt; を使ってキャッシュされることを期待している部分を、事前にコンパイル済みのパターンを使うようにしてるための前準備でもある。
これも効果あるかは試さないとわからない。現時点でキャッシュが効いてるのであれば多分変わらないのじゃないかなと思っている。&lt;/p&gt;
&lt;p&gt;これまでの改善同様に爆発的な効果は出てないけど、地道に試行錯誤してく予定。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 04 Aug 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-07-28-writing-cmdlet-in-fsharp-pt45.html</guid><link>https://krymtkts.github.io/posts/2024-07-28-writing-cmdlet-in-fsharp-pt45.html</link><title>F# でコマンドレットを書いてる pt.45</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-07-07-writing-cmdlet-in-fsharp-pt44.html&quot; title=&quot;前回のバグ対応&quot;&gt;前回のバグ対応&lt;/a&gt; を &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.14.1&quot; title=&quot;v0.14.1&quot;&gt;v0.14.1&lt;/a&gt; としてリリースして以降、 pocof をパフォ改善する開発はあんまうまく進んでいない。
そろそろ真面目に profiling すべきなんかも。 .NET 門外漢過ぎてわからん。&lt;/p&gt;
&lt;p&gt;pocof の最適化については前にも触れてるが、当初 Trie や Suffix Tree を使って事前に検索しやすい形を構築しようかと考えていた。
けど、これを全プロパティ + 文字列化されたオブジェクト分で構築すると空間計算量がかなり高く付くので、これはどうなんかな～と思って踏ん切りがつかなかった。
同時に正規表現を捨てるのも覚悟が足りず。
自身の利用シーンでは最低限として中間一致だけの検索モードを提供するってのはありかもなーと思ったが、これも踏ん切りがつかず。&lt;/p&gt;
&lt;p&gt;他にできることとして &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.psobject?view=powershellsdk-7.4.0&quot; title=&quot;PSObject&quot;&gt;PSObject&lt;/a&gt; を何度も &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.psobject.tostring?view=powershellsdk-7.4.0&quot; title=&quot;toString&quot;&gt;toString&lt;/a&gt; している箇所が重いんかなと生成回数を減らすよう変えてみたが、効果は全くなかった。&lt;/p&gt;
&lt;p&gt;もう CPU で殴るしかないかなということで、先達である &lt;a href=&quot;https://github.com/fsprojects/FSharp.Collections.ParallelSeq/tree/main&quot; title=&quot;fsprojects/FSharp.Collections.ParallelSeq&quot;&gt;fsprojects/FSharp.Collections.ParallelSeq&lt;/a&gt; のアプローチを便器ょした。
そこから &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.linq.parallelenumerable?view=net-8.0&quot; title=&quot;ParallelEnumerable&quot;&gt;ParallelEnumerable&lt;/a&gt; を使って、 pocof に足る範囲の並列可能な F# 風 sequence (追加順維持)をこしらえてみた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/207&quot; title=&quot;#207&quot;&gt;#207&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;pocof の用途に合わせて、必要な用途に絞った最小の実装にした。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.linq.parallelenumerable.where?view=net-8.0&quot; title=&quot;ParallelEnumerable.Where Method&quot;&gt;ParallelEnumerable.Where Method&lt;/a&gt; で &lt;code&gt;filter&lt;/code&gt; 、
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.linq.parallelenumerable.count?view=net-8.0#system-linq-parallelenumerable-count-1(system-linq-parallelquery((-0)))&quot; title=&quot;ParallelEnumerable.Count Method&quot;&gt;ParallelEnumerable.Count Method&lt;/a&gt; で &lt;code&gt;length&lt;/code&gt; を作った。
pocof では追加順を維持するのが重要なので、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.linq.parallelenumerable.asordered?view=net-8.0#system-linq-parallelenumerable-asordered(system-linq-parallelquery)&quot; title=&quot;ParallelEnumerable.AsOrdered&quot;&gt;ParallelEnumerable.AsOrdered&lt;/a&gt; を使ってる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AsOrdered&lt;/code&gt; にしたので通常の ParallelEnumerable よりパフォ劣化するせいと思うが 100 万 ~ 1000 万件位のデータ量で確認した限り普通の seq と比べて速いわけでもなく、むしろ少し遅い。
それでも CPU ゴリゴリに使って頑張ってくれるのはわかるが、そこまで速くなく更に CPU 使いすぎるのもどうかな～と思えてきた。
大量データのときだけ CPU 頑張ってくれるだけなのでこれは main branch へ投入したけど、あまり良くなければ戻すかも。&lt;/p&gt;
&lt;p&gt;CPU で殴っても効果がないとなるとあとやれることはロジック自体の改善。
ということで、いまは &lt;code&gt;Query&lt;/code&gt; module の対象 object か調べる処理自体を末尾再帰で書き直して速くならんか見ている。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/208&quot; title=&quot;#208&quot;&gt;#208&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;元々は 1 object 毎にクエリの list から filter 条件の list を作り、それに対して &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-listmodule.html#exists&quot; title=&quot;List.exists&quot;&gt;List.exists&lt;/a&gt; か &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-listmodule.html#forall&quot; title=&quot;List.forall&quot;&gt;List.forall&lt;/a&gt; する形だった。
そこを末尾再帰で書き換えたことで、 list の生成処理が丸ごとなくなるのもあってちょっと効果出ている。
ただ結構コードの循環的複雑度が高まったので、清書する必要がある。&lt;/p&gt;
&lt;p&gt;この 1 objects あたりの処理量を減らす方向性は間違ってないっぽいので(爆発的な効果は出てないが)、他にもできることがないか検討してみる。
機能維持しつつ爆発的に速くなる方法があればよかったけど現実的にそういうのはまず起こらないので、地道に改善重ねていくしかないかな。
AND 検索しかなかったらドンドン母数を絞り込めるからクソチョロなんやけど、 pocof は親切なことに OR 検索があるから...コツコツやるかデータ構造変更しかない。
非同期描画のときは結局 alpha で出さなかったので、今回の並列＆最適化こそは prerelease するタイミングなのではないかと思っている(やるかはわからん)。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 28 Jul 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-07-21-workaround-for-broken-chocolatey-install.html</guid><link>https://krymtkts.github.io/posts/2024-07-21-workaround-for-broken-chocolatey-install.html</link><title>Chocolatey の chocolateyInstall.ps1 が壊れている場合の workaround</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;わたしは長らく Windows のパッケージ管理に &lt;a href=&quot;https://chocolatey.org/&quot; title=&quot;Chocolatey&quot;&gt;Chocolatey&lt;/a&gt; を使ってるのだけど、壊れたパッケージを無理やり直してインストールする機会があった。
これはもう直ってる問題に対して「こうしましたよ」という記録を残すものだ。&lt;/p&gt;
&lt;p&gt;壊れたパッケージというのはわたしのお気に入りの &lt;a href=&quot;https://community.chocolatey.org/packages/powertoys&quot; title=&quot;PowerToys&quot;&gt;PowerToys&lt;/a&gt; だ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mkevenaar/chocolatey-packages/pull/253&quot; title=&quot;Update PowerToys script to newer tag by jaimecbernardo · Pull Request #253 · mkevenaar/chocolatey-packages&quot;&gt;Update PowerToys script to newer tag by jaimecbernardo · Pull Request #253 · mkevenaar/chocolatey-packages&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上記は PowerToys 開発チームの dev lead の人が chocolatey package の repo に作ってくれた PR だ。親切極まりない。
PR によれば次のようにして壊れたらしい。&lt;/p&gt;
&lt;p&gt;先日 PowerToys 開発チームでリリース時に tag を &lt;code&gt;v0.82.1&lt;/code&gt; が正しいところ &lt;code&gt;V0.82.1&lt;/code&gt; とつけてしまったらしい(tag は &lt;code&gt;v0.82.1&lt;/code&gt; につけ直されてた)。
その影響を受けて、 &lt;a href=&quot;https://github.com/mkevenaar/chocolatey-packages&quot; title=&quot;PowerToy の chocolatey package を作ってくれてる人の package&quot;&gt;PowerToy の chocolatey package を作ってくれてる人の package&lt;/a&gt; が自動更新なのか知らんが壊れたっぽい。&lt;/p&gt;
&lt;p&gt;どう壊れたかというと、 &lt;a href=&quot;https://docs.chocolatey.org/en-us/chocolatey-install-ps1/&quot; title=&quot;&lt;code&gt;chocolateyInstall.ps1&lt;/code&gt;&quot;&gt;&lt;code&gt;chocolateyInstall.ps1&lt;/code&gt;&lt;/a&gt; が存在しなくなったタグ &lt;code&gt;V0.82.1&lt;/code&gt; を指したままになった。
&lt;code&gt;chocolateyInstall.ps1&lt;/code&gt; は &lt;code&gt;choco upgrade powertoys -y&lt;/code&gt; で download されてくる。
要は download したホヤホヤの &lt;code&gt;chocolateyInstall.ps1&lt;/code&gt; が存在しない URL からバイナリを download しようとするので、常に 404 でエラーするようになった。&lt;/p&gt;
&lt;p&gt;これだと修正が merge されないと chocolatey package が更新できない。
直し方はわかってるし、自力で力技の解決できないか試したら、できた。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;事前に &lt;code&gt;chocolateInstall.ps1&lt;/code&gt; を新しいバージョンの URL と checksum に変えておき、クリップボードにコピーしておく。 checksum は GitHub の Release ページから取れる&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/PowerToys/releases/tag/v0.82.1&quot; title=&quot;Release Release v0.82.1 · microsoft/PowerToys&quot;&gt;Release Release v0.82.1 · microsoft/PowerToys&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;chocolateInstall.ps1&lt;/code&gt; をエディタで開きっぱなしにしておく&lt;/li&gt;&lt;li&gt;&lt;code&gt;choco upgrade powertoys -y&lt;/code&gt; を実行する&lt;/li&gt;&lt;li&gt;&lt;code&gt;chocolateInstall.ps1&lt;/code&gt; がダウンロードされ次第(≒ エディタで表示してる内容が変わったら)変更内容をコピペして即座に保存する&lt;/li&gt;&lt;li&gt;うまくいったらコピペで変更されたファイルを使ってバイナリのダウンロードが始まる&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;はじめこれでうまくいくかわからんかったので手でやったけど、これなら &lt;a href=&quot;https://fake.build/reference/fake-io-changewatcher.html&quot; title=&quot;FAKE の ChangeWatcher&quot;&gt;FAKE の ChangeWatcher&lt;/a&gt; や素の &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.io.filesystemwatcher?view=net-8.0&quot; title=&quot;FileSystemWatcher&quot;&gt;FileSystemWatcher&lt;/a&gt; で自動化できそう。
こんなもん自動化してどうすねんというのはあるけど。&lt;/p&gt;
&lt;p&gt;今回は Chocolatey の正当な仕組み全く理解せずとも、ログを追ったらこのような力技ができた。
ちゃんとした仕組みに乗ったもっとマシな patch 方法ないのかなとか、この仕組みはインジェクション可能ということで危なくないのかなと思ったりした。
一度 Chocolatey の流儀を学んでちゃんとした方法を調べるかー？
いい加減 Chocolatey にフリーライドし続けてきたのでちゃんと仕組みを理解して貢献できたらいい気もするしな。
積みタスク行き。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 21 Jul 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-07-14-memos-for-powershell-gallery.html</guid><link>https://krymtkts.github.io/posts/2024-07-14-memos-for-powershell-gallery.html</link><title>PowerShell Gallery に関する備忘録</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;先日 &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; のメンテをしてるときに、 &lt;a href=&quot;https://github.com/PowerShell/PSResourceGet&quot; title=&quot;PSResourceGet&quot;&gt;PSResourceGet&lt;/a&gt; で response status code 999 を受け取ってびっくりした。
おおよその原因がわかれば大した話ではないが、また忘れてびっくりしないように備忘のメモを残す。&lt;/p&gt;
&lt;p&gt;2024-07-12 06:00 JST 過ぎに Dependable version updates で自動作成された PR を処理しようとした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/actions/runs/9899237786/job/27349382236&quot; title=&quot;Merge pull request #201 from krymtkts/dependabot/nuget/test-lib-8e312… · krymtkts/pocof@95be938&quot;&gt;Merge pull request #201 from krymtkts/dependabot/nuget/test-lib-8e312… · krymtkts/pocof@95be938&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;特に問題なかったので自動作成された PR を merge したらなんと GitHub Actions workflow がコケた。んなあほな。
ログを見てみたら &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/install-psresource?view=powershellget-3.x&quot; title=&quot;&lt;code&gt;Install-PSResource&lt;/code&gt;&quot;&gt;&lt;code&gt;Install-PSResource&lt;/code&gt;&lt;/a&gt; で response status code 999 を受け取ってるようだった。
銀河鉄道かよ。
わたしの浅い経験では 999 を見たのはこのときが初めてだ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Prepare all required actions&lt;br /&gt;Getting action download info&lt;br /&gt;Download action repository &amp;#x27;actions/setup-dotnet@v4&amp;#x27; (SHA:6bd8b7f7774af54e05809fcc5431931b3eb1ddee)&lt;br /&gt;Download action repository &amp;#x27;codecov/codecov-action@v4&amp;#x27; (SHA:e28ff129e5465c2c0dcc6f003fc735cb6ae0c673)&lt;br /&gt;Run ./.github/actions/test&lt;br /&gt;Run actions/setup-dotnet@v4&lt;br /&gt;/home/runner/work/_actions/actions/setup-dotnet/v4/externals/install-dotnet.sh --skip-non-versioned-files --runtime dotnet --channel LTS&lt;br /&gt;dotnet-install: Attempting to download using aka.ms link https://dotnetcli.azureedge.net/dotnet/Runtime/8.0.7/dotnet-runtime-8.0.7-linux-x64.tar.gz&lt;br /&gt;dotnet-install: Remote file https://dotnetcli.azureedge.net/dotnet/Runtime/8.0.7/dotnet-runtime-8.0.7-linux-x64.tar.gz size is 31272597 bytes.&lt;br /&gt;dotnet-install: Extracting archive from https://dotnetcli.azureedge.net/dotnet/Runtime/8.0.7/dotnet-runtime-8.0.7-linux-x64.tar.gz&lt;br /&gt;dotnet-install: Downloaded file size is 31272597 bytes.&lt;br /&gt;dotnet-install: The remote and local file sizes are equal.&lt;br /&gt;dotnet-install: Installed version is 8.0.7&lt;br /&gt;dotnet-install: Adding to current process PATH: `/usr/share/dotnet`. Note: This change will be visible only when sourcing script.&lt;br /&gt;dotnet-install: Note that the script does not resolve dependencies during installation.&lt;br /&gt;dotnet-install: To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install, select your operating system and check the &amp;quot;Dependencies&amp;quot; section.&lt;br /&gt;dotnet-install: Installation finished successfully.&lt;br /&gt;/home/runner/work/_actions/actions/setup-dotnet/v4/externals/install-dotnet.sh --skip-non-versioned-files --version 8.0.100&lt;br /&gt;dotnet-install: Attempting to download using primary link https://dotnetcli.azureedge.net/dotnet/Sdk/8.0.100/dotnet-sdk-8.0.100-linux-x64.tar.gz&lt;br /&gt;dotnet-install: Remote file https://dotnetcli.azureedge.net/dotnet/Sdk/8.0.100/dotnet-sdk-8.0.100-linux-x64.tar.gz size is 214395068 bytes.&lt;br /&gt;dotnet-install: Extracting archive from https://dotnetcli.azureedge.net/dotnet/Sdk/8.0.100/dotnet-sdk-8.0.100-linux-x64.tar.gz&lt;br /&gt;dotnet-install: Downloaded file size is 214395068 bytes.&lt;br /&gt;dotnet-install: The remote and local file sizes are equal.&lt;br /&gt;dotnet-install: Installed version is 8.0.100&lt;br /&gt;dotnet-install: Adding to current process PATH: `/usr/share/dotnet`. Note: This change will be visible only when sourcing script.&lt;br /&gt;dotnet-install: Note that the script does not resolve dependencies during installation.&lt;br /&gt;dotnet-install: To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install, select your operating system and check the &amp;quot;Dependencies&amp;quot; section.&lt;br /&gt;dotnet-install: Installation finished successfully.&lt;br /&gt;Run Set-PSResourceRepository PSGallery -Trusted&lt;br /&gt;Install-PSResource: /home/runner/work/_temp/03b13c40-34d5-4152-b471-63d55ca095a9.ps1:3&lt;br /&gt;Line |&lt;br /&gt;   3 |  Install-PSResource Psake,Pester,PSScriptAnalyzer -Quiet -Reinstall -S …&lt;br /&gt;     |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;     | &amp;#x27;Response status code does not indicate success: 999.&amp;#x27; Request sent:&lt;br /&gt;     | &amp;#x27;https://www.powershellgallery.com/api/v2/FindPackagesById()?id=&amp;#x27;Psake&amp;#x27;&amp;amp;$inlinecount=allpages&amp;amp;$filter=IsLatestVersion%20and%20Id%20eq%20&amp;#x27;Psake&amp;#x27;&amp;#x27;&lt;br /&gt;Error: Process completed with exit code 1.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;999 について調べてみても「一般的じゃない response code」くらいしか情報が見つからない(当然)。
999 は未定義のため、一般的には内部 status code が漏れ出てるパターンぽい。
過去に LinkedIn をログインせず crawling しようとしたらが 999 返ったことがあるらしい。
&lt;a href=&quot;https://stackoverflow.com/questions/42910269/999-response-when-trying-to-crawl-linkedin-with-scrapy/45407138#45407138&quot; title=&quot;python - 999 response when trying to crawl LinkedIn with Scrapy - Stack Overflow&quot;&gt;python - 999 response when trying to crawl LinkedIn with Scrapy - Stack Overflow&lt;/a&gt;
これは GitHub Actions だけじゃなさそうと思い、ローカルで試してみたら同じだった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Install-PSResource&lt;/span&gt; Psake&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Install-PSResource&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Response status code does not indicate success: 999.&amp;#x27;&lt;/span&gt; Request sent: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/FindPackagesById()?id=&amp;#x27;&lt;/span&gt;Psake&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;amp;$inlinecount=allpages&amp;amp;$filter=IsLatestVersion%20and%20Id%20eq%20&amp;#x27;&lt;/span&gt;Psake&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Install-PSResource&lt;/span&gt;: Package(s) &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Psake&amp;#x27;&lt;/span&gt; could not be installed from repository &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;Install-PSResource&lt;/code&gt; だけでなく &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/find-psresource?view=powershellget-3.x&quot; title=&quot;&lt;code&gt;Find-PSResource&lt;/code&gt;&quot;&gt;&lt;code&gt;Find-PSResource&lt;/code&gt;&lt;/a&gt; も挙動が変だった。
&lt;code&gt;Find-PSResource -Name pocof&lt;/code&gt; で検索しても結果を取得できないけど &lt;code&gt;Find-PSResource -Name poco*&lt;/code&gt; だと取得できたり。なんでだよ。&lt;/p&gt;
&lt;p&gt;これ障害かなんかやなと漸くここで気づき &lt;a href=&quot;https://www.powershellgallery.com/&quot; title=&quot;PowerShell Gallery&quot;&gt;PowerShell Gallery&lt;/a&gt; を見に行ったら、ページトップに ↓ の通りの記載があった。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Individual package statistics are temporarily unavailable. More info: &lt;a href=&quot;https://aka.ms/psgallerystatus&quot; title=&quot;undefined&quot;&gt;https://aka.ms/psgallerystatus&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://aka.ms/psgallerystatus&quot; title=&quot;undefined&quot;&gt;https://aka.ms/psgallerystatus&lt;/a&gt; が ↓ に繋がってる&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PowerShellGallery/blob/master/psgallery_status.md#july-11th-2024-individual-package-statistics-will-be-temporarily-unavailable&quot; title=&quot;PowerShellGallery/psgallery_status.md at master · PowerShell/PowerShellGallery&quot;&gt;PowerShellGallery/psgallery_status.md at master · PowerShell/PowerShellGallery&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4 &gt;&lt;a name=&quot;July-11th-2024-Individual-package-statistics-will-be-temporarily-unavailable-&quot; href=&quot;#July-11th-2024-Individual-package-statistics-will-be-temporarily-unavailable-&quot;&gt;July 11th, 2024 Individual package statistics will be temporarily unavailable.&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Individual package statistics will be temporarily unavailable while we are making infrastructure changes. There will be no loss of information, however statistics numbers will temporarily not update.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Status: Ongoing&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;この文面からは PSResourceGet が影響を受けるような雰囲気は全く読み取れなかったのだけど、絶対これやろ。
2024-07-12 08:00 JST 時点でも 999 解消できなかったので、 PowerShell Gallery のインフラ変更中の間無理なんじゃないかなと不安になった。&lt;/p&gt;
&lt;p&gt;2024-07-12 09:10 JST にはローカルで &lt;code&gt;Install-PSResource&lt;/code&gt; が 999 することもなくなり、 &lt;code&gt;Find-PSResource&lt;/code&gt; もちゃんと結果を返すようになった。
その後 GitHub Actions を再実行したらうまくいった。
きょうこの記事をしたためてる最中も、↓ ままやけど。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;July 11th, 2024 Individual package statistics will be temporarily unavailable.
Status: Ongoing&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;いつだったか PowerShell Gallery の更新計画を &lt;a href=&quot;https://devblogs.microsoft.com/&quot; title=&quot;PowerShell の devblogs&quot;&gt;PowerShell の devblogs&lt;/a&gt; でみた気がするけど覚え違いかな？
調べてみても、最近の &lt;a href=&quot;https://devblogs.microsoft.com/powershell/powershell-and-openssh-team-investments-for-2024/&quot; title=&quot;PowerShell and OpenSSH team investments for 2024 - PowerShell Team&quot;&gt;PowerShell and OpenSSH team investments for 2024 - PowerShell Team&lt;/a&gt; で新しいタイプの PowerShell の repo に触れてる程度だった。
ただこう、なんやろ。もうちょっと計画的なメンテとかは開発者がわかりやすく把握できるようにならんのかなという気はする。
前から Markdown 直書きなのは知ってるけど、この更新を自動で受け取るのって PowerFighter(勝手に作った PowerShell ユーザの呼び名)のみんなは自前でシステム組んでるんかな？
気になる所あるが、次回似たような記事を書くときまでにはなんか進展があるといいな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 14 Jul 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-07-07-writing-cmdlet-in-fsharp-pt44.html</guid><link>https://krymtkts.github.io/posts/2024-07-07-writing-cmdlet-in-fsharp-pt44.html</link><title>F# でコマンドレットを書いてる pt.44</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-06-30-writing-cmdlet-in-fsharp-pt43.html&quot; title=&quot;前回の対応&quot;&gt;前回の対応&lt;/a&gt; で非同期のバグが云々言ってたやつは、普通に immutable なデータ構造に起因するバグだった。ショボ。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/197/commits/a9e5bab2564239239f80e3349a3bee897f699a82&quot; title=&quot;a9e5bab&quot;&gt;a9e5bab&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Prerelease 出すにあたり最後に解消しておきたいのが、 &lt;code&gt;-NonInteractive&lt;/code&gt; 時に結構な確率で &lt;a href=&quot;https://github.com/pester/Pester&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; のテスト ≒ end-to-end テストがコケるところだ。いわゆる flaky test 化してしまった。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;前に書いた ↑ は検討外れで、検索可能なプロパティの一覧を保持する際の内部データに F# の &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-fsharpmap-2.html&quot; title=&quot;&lt;code&gt;Map&lt;/code&gt;&quot;&gt;&lt;code&gt;Map&lt;/code&gt;&lt;/a&gt; を利用していたので、非同期で要素が追加された際に結果が反映されないというものだった。
要はただの凡ミスだったわけなので .NET の非同期コレクションで置き換えて解消した。
他データ読み込み中に操作がない場合の描画間隔を調整したり &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/198&quot; title=&quot;#198&quot;&gt;#198&lt;/a&gt; 細々とした修正を入れている。&lt;/p&gt;
&lt;p&gt;他にも試したいことがあったのだけど、うまくいかなくて頓挫した。
以下に記すのは思考の整理のためのその記録。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;まず code coverage の計測を &lt;a href=&quot;https://github.com/coverlet-coverage/coverlet&quot; title=&quot;coverlet&quot;&gt;coverlet&lt;/a&gt; から &lt;a href=&quot;https://github.com/SteveGilham/altcover&quot; title=&quot;altcover&quot;&gt;altcover&lt;/a&gt; に変えてみようと思い、試してみた。
coverlet は F# が生成する IL 向けにチューニングされてないので、コード上に現れない微妙な branches のせいで coverage を落とす。↓ これ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/coverlet-coverage/coverlet/issues/1208&quot; title=&quot;Multiple branch points created for F# string slice · Issue #1208 · coverlet-coverage/coverlet&quot;&gt;Multiple branch points created for F# string slice · Issue #1208 · coverlet-coverage/coverlet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;そのため F# らしく書けない事がある。
altcover でそれが解消せんかな的なことを考えて試してみた。
また F# の OSS を使うという点でも良い。
けどデフォルト設定で altcover で計測すると pocof 以外のバイナリも検査対象になり、そのせいか実行速度が 5 倍くらいになってしまった。
なんてこった。
対象のアセンブリを絞る設定が要るようだ。
でも設定してみても速くなったり F# の IL に最適化される確証ないなーと思ったのでこれは今のところナシとした。
sandbox で試してみてから pocof に導入できるか検討するのがまともな判断かな。&lt;/p&gt;
&lt;p&gt;次に &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/177&quot; title=&quot;pocof で大量データを操作すると遅い件&quot;&gt;pocof で大量データを操作すると遅い件&lt;/a&gt;に関する対応だ。
この対応として非同期で描画して遅く感じさせない改良を入れてきたけど、肝心の検索自体は速くなってない。
内部データの &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-seq-1.html&quot; title=&quot;seq&quot;&gt;seq&lt;/a&gt; (実際は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentqueue-1?view=net-8.0&quot; title=&quot;ConcurrentQueue&quot;&gt;ConcurrentQueue&lt;/a&gt;) に対して正規表現で検索し、件数を数えるので、時間計算量が O(N) かかってる。
もちろん件数を数えるときにも O(N) かかってる。&lt;/p&gt;
&lt;p&gt;コレクションを分割して &lt;code&gt;Task&lt;/code&gt; で並行処理したら速くならんかなと試してみたが更に遅くなった。
元々 CPU bound な処理だから並列じゃない限り速くならんのよな。
そもそも内部データの seq を分割する &lt;code&gt;Seq.chunkBySize&lt;/code&gt; や処理後の &lt;code&gt;Seq.concat&lt;/code&gt; で O(N) かかるし。
ただこの過程で &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-arraymodule-parallel.html&quot; title=&quot;Array.Parallel&quot;&gt;Array.Parallel&lt;/a&gt; や &lt;a href=&quot;https://fsprojects.github.io/FSharp.Collections.ParallelSeq/&quot; title=&quot;F# Parallel Sequences&quot;&gt;F# Parallel Sequences&lt;/a&gt; を知ったので、なんか参考にできるのかも知れない。&lt;/p&gt;
&lt;p&gt;他の方法として内部データ構造の変更が思いつくので、 ChatGPT や GitHub Copilot に相談してみた。
彼らは初め「&lt;a href=&quot;https://ja.wikipedia.org/wiki/%E3%83%88%E3%83%A9%E3%82%A4_(%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0)&quot; title=&quot;Trie&quot;&gt;Trie&lt;/a&gt; にしたらいいやん」って言ってきた。
プロパティ毎に Trie 作成するってことかあ？と思ったので、でも「 1 億要素あって &lt;code&gt;PSObject&lt;/code&gt; の任意のプロパティに対して正規表現の検索が可能でないとあかんねんけど...」と伝えたら「それはデータ構造だけやと理論的に難しいで」とのことだった。
そら難しくなかったらお前に相談せんやろ...とりあえず検索パターンごとの最適化みたいなのを先に試してみるべきなのかも知れん。&lt;/p&gt;
&lt;p&gt;例えば AND 検索であれば、クエリが追記されていく限りはそれより前の絞り込み結果に対して検索する方が少ない N 減で済むから速くなるとか。
でもこの方針だと、 OR 検索の場合や非同期コレクションが更新された場合は常に全体を検索せねばならず、どうにもならんけど。
pocof は無駄にリッチに AND 検索と OR 検索ができて、正規表現とワイルドカードのどちらでも検索もできるため、打つべき手段も色々ややこしいことになってる。
他に、検索機能を database なんかの外に出してみたらどうかとも思いつくが、なんか負けた気がするからそれは却下。 自前の何かで解決したい。
今のところ、全列に索引が貼られたテーブルみたいな如何にもメモリ食いそうな構造しか思いつかないので、なんか探求してみる。&lt;/p&gt;
&lt;p&gt;そもそもの話、生の seq や &lt;code&gt;ConcurrentQueue&lt;/code&gt; の件数を取ってみてもそんな爆発的に遅くないねんよな。
つまり pocof で入れてる実装に起因して遅い可能性も微レ存だと。
&lt;code&gt;PSObject&lt;/code&gt; を文字列にするあたりだとか、存在するかわからないプロパティに reflection でアクセスするあたりだとか、なんか &lt;code&gt;PSObject&lt;/code&gt; の取り扱いが難しいんじゃないのこれ。
前にプロパティ一覧取ってメモリ爆食いしてたやつを思い出した。&lt;/p&gt;
&lt;p&gt;まだまだ伸びしろがあるということで一旦の締めとする。
結構直してきたので、この初の非同期描画版になった pocof はもういい加減リリースしたいな(何度目)。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 07 Jul 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-06-30-writing-cmdlet-in-fsharp-pt43.html</guid><link>https://krymtkts.github.io/posts/2024-06-30-writing-cmdlet-in-fsharp-pt43.html</link><title>F# でコマンドレットを書いてる pt.43</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-06-09-writing-cmdlet-in-fsharp-pt42.html&quot; title=&quot;前回の対応&quot;&gt;前回の対応&lt;/a&gt; で非同期で読み込みながら即座に対話式 CLI を起動するようにはなったが、バグ・未対応や TODO が散見されるのでボチボチその対処をしていた。
Prerelease したいなといっていたが、自分で日常的に使うまでもなくなんかイマイチなところがあったので延期して、ちまちまと直している。
やることが多いので pull request も小分けに切らず、 このへん &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/191&quot; title=&quot;#191&quot;&gt;#191&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/192&quot; title=&quot;#192&quot;&gt;#192&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/195&quot; title=&quot;#195&quot;&gt;#195&lt;/a&gt; で大雑把に対応をしている。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.cmdlet.processrecord?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;ProcessRecord&lt;/code&gt;&quot;&gt;&lt;code&gt;ProcessRecord&lt;/code&gt;&lt;/a&gt; 中に操作がなくても描画をリフレッシュする実装も雑だが仕込んだ。
もうちょいで Prerelease 出せそうな気がする。&lt;/p&gt;
&lt;p&gt;Prerelease 出すにあたり最後に解消しておきたいのが、 &lt;code&gt;-NonInteractive&lt;/code&gt; 時に結構な確率で &lt;a href=&quot;https://github.com/pester/Pester&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; のテスト ≒ end-to-end テストがコケるところだ。いわゆる flaky test 化してしまった。
pocof はクロスプラットフォームを謳っておるのもあり、テストランナーが Mac, Linux, Windows だが、コケるのは大体 Mac か Windows だ。なんでだよ。
interactive mode を模倣した unit test はコケないので、非同期の対応で &lt;code&gt;-NonInteractive&lt;/code&gt; によるバグを生んでしまってるのはほぼ間違いないやろなとみている。
ただ調べるのめんどくさい上位に君臨する非同期系バグの可能性もあり、対処を後回しにしてきた。
だがついに対峙せなばならんときが来たのだろう。&lt;/p&gt;
&lt;p&gt;他はコツコツ課題を解消できてきた。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/195&quot; title=&quot;#195&quot;&gt;#195&lt;/a&gt; で &lt;a href=&quot;https://github.com/PowerShell/PowerShell/issues/3821&quot; title=&quot;&lt;code&gt;StopUpstreamCommandsException&lt;/code&gt;&quot;&gt;&lt;code&gt;StopUpstreamCommandsException&lt;/code&gt;&lt;/a&gt; を投げるあたりのコードを mock 可能にしてテストを通せるようにしたり。
&lt;a href=&quot;https://xunit.net/&quot; title=&quot;xUnit&quot;&gt;xUnit&lt;/a&gt; でテストしてると &lt;code&gt;StopUpstreamCommandsException&lt;/code&gt; を reflection で拾おうにも &lt;code&gt;null&lt;/code&gt; になりエラーでテストできなかった。
他にテストする方法がないか考えてたが、結局シンプルな挿げ替え方式を採用した。
&lt;code&gt;StopUpstreamCommandsException&lt;/code&gt; の代わりに &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.exception?view=net-8.0&quot; title=&quot;&lt;code&gt;Exception&lt;/code&gt;&quot;&gt;&lt;code&gt;Exception&lt;/code&gt;&lt;/a&gt; を継承した mock に挿げ替えてテストを通せる。
pocof は依存関係なしの縛りプレイなため DI のライブラリを持ってないので、テスト時に手動で挿げ替える。&lt;/p&gt;
&lt;p&gt;同様の方法で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.console.readkey?view=net-8.0&quot; title=&quot;&lt;code&gt;Console.ReadKey&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.ReadKey&lt;/code&gt;&lt;/a&gt; 等に依存していた箇所を挿げ替え方式にしたことで、
code coverage もステップレベルだと四捨五入 98 % まで引き上げた。
良い感じ。
いつか 100% 到達したいな。&lt;/p&gt;
&lt;p&gt;余談だが、よくビジネスのシステム開発の文脈に於いては「code coverage は 8 割強に落ち着く」という人が多いけど、個人プロジェクトにおいては当てはまらない。
好きでやってるから、コストとのバランスを度外視できる。
coverage も縛りプレイの追求ポイントなので、どこに落ち着くという概念は存在せず、ただ突き詰めるのみｗ&lt;/p&gt;
&lt;p&gt;閑話休題、テスト可能な構造にするにあたり、 Cmdlet を継承した型に abstract method を追加した。
元々使っていたテクニックだが、 default implementation を override で変えることで、テスト時に狙った挙動をさせられる。
今回対応範囲を増やしたことで、ほぼ Cmdlet の動作パターンを模倣できるようになった。
例えば以下は、 &lt;code&gt;StopUpstreamCommandsException&lt;/code&gt; で Cmdlet の record processing のフローを抜けるパターンを模倣している。便利や。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;SelectPocofCommandForTest&lt;/span&gt;() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;inherit&lt;/span&gt; SelectPocofCommand()&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; Host&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PSHost &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Mock.Host()&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.Invoke(input&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;seq&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; input &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Seq.map string&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.PSHost() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; __.Host&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.ConsoleInterface() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; MockConsoleInterface()&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.GetStopUpstreamCommandsExceptionType() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;MockException&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; emulate the Cmdlet record precessing flow.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.InvokeForTest2() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            __.BeginProcessing()&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;mutable&lt;/span&gt; loop &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; loop &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;&lt;br /&gt;                    Thread.Sleep &lt;span class=&quot;hljs-number&quot;&gt;50&lt;/span&gt;&lt;br /&gt;                    __.ProcessRecord()&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;:?&lt;/span&gt; MockException &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                    loop &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;いいことづくめのようだけど、これによって以前こしらえた interface が必要なくなったんじゃないかなとか、構造的に気になる点でてきたので、そこは新たな TODO として積まれた...&lt;/p&gt;
&lt;p&gt;何にせよ、早々に Prerelease 出したい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 30 Jun 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-06-23-add-search-with-pagefind-to-blog-fable.html</guid><link>https://krymtkts.github.io/posts/2024-06-23-add-search-with-pagefind-to-blog-fable.html</link><title>blog-fable に pagefind による検索を追加する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 放置気味だが、今日も &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; の話を書く。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/krymtkts.github.io&quot; title=&quot;このブログ&quot;&gt;このブログ&lt;/a&gt;は結構自身の備忘のために役立っている。
例えば &lt;a href=&quot;https://chocolatey.org/&quot; title=&quot;chocolatey&quot;&gt;chocolatey&lt;/a&gt; で OpenSSH をインストールするオプションを確認するときのような、たまにしかやらないことを探すのにとても役立つ。
ただ書くときは探しやすさに注意を払わずタイトルを書いてることもあって、どこに書いたか忘れて、あとからそういった情報を探すのにいちいち数記事読み返すときもある。
そんなときは検索機能が欲しくなるのだけど、あんまり日本語がいい感じで、軽量な静的コンテンツの検索ってなさそうだったので放置していた。&lt;/p&gt;
&lt;p&gt;でも最近 &lt;a href=&quot;https://pagefind.app/&quot; title=&quot;pagefind&quot;&gt;pagefind&lt;/a&gt; の日本語が良くなってきていると知り、また導入も簡単だということなのでやってみた。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;blog-fable に pagefind を導入するのに以下を行った。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;task runner に &lt;code&gt;pagefind&lt;/code&gt; の実行を追加する&lt;/li&gt;&lt;li&gt;検索を最適化するための設定を作成し、 metadata を追加する&lt;/li&gt;&lt;li&gt;pagefind UI の初期化コードを仕込む&lt;/li&gt;&lt;li&gt;pagefind UI のスタイル調整する&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;task-runner-code-pagefind-code-&quot; href=&quot;#task-runner-code-pagefind-code-&quot;&gt;task runner に &lt;code&gt;pagefind&lt;/code&gt; の実行を追加する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;まず &lt;code&gt;pagefind&lt;/code&gt; の実行だが、やり方は至極簡単。
概ね pagefind の文書に書いてあるとおりに index を構築して GitHub Pages に deploy したらいいだけ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pagefind.app/docs/running-pagefind/&quot; title=&quot;Running Pagefind | Pagefind — Static low-bandwidth search at scale&quot;&gt;Running Pagefind | Pagefind — Static low-bandwidth search at scale&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;当然静的コンテンツの作成後出ないといけないので、コマンドの実行順にだけ気をつけたらいい。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/5a82f1283aefdde9d8a98823a060a050ce1efef3/package.json#L4-L14&quot; title=&quot;こんなふう&quot;&gt;こんなふう&lt;/a&gt;にした。
元々 &lt;code&gt;build&lt;/code&gt; task に引数を渡して開発と本番を切り分けてたが、直接引数を渡すと最後尾の &lt;code&gt;build-index&lt;/code&gt; に適用されてしまうため、仕方なく分割した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;scripts&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;postinstall&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet tool restore&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;build-fable&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet fable src --test:MSBuildCracker --runScript&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;build-md&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;node ./src/App.fs.js&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;build-css&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;sass --style=compressed --no-source-map ./sass/style.scss ./docs/blog-fable/css/style.css&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;build-index&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;pagefind&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;build&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;npm run build-css &amp;amp;&amp;amp; npm run build-fable &amp;amp;&amp;amp; npm run build-index&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;build-dev&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;npm run build-css &amp;amp;&amp;amp; npm run build-fable dev &amp;amp;&amp;amp; npm run build-index&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;serve&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet fsi ./dev-server.fsx /blog-fable&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;dev&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;npm run build-dev &amp;amp;&amp;amp; npm run serve&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-metadata-&quot; href=&quot;#-metadata-&quot;&gt;検索を最適化するための設定を作成し、 metadata を追加する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;次は重要な点で、静的コンテンツからどう index 構築するかの設定する必要があった。
デフォルトだと何もかも indexing してしまうので、どの要素で構築すべきか、どのパスで構築すべきかの設定しないと検索のノイズがすごかった。
幸い &lt;a href=&quot;https://pagefind.app/docs/config-sources/&quot; title=&quot;pagefind は設定ファイルをサポートしている&quot;&gt;pagefind は設定ファイルをサポートしている&lt;/a&gt;ので、このような面倒な設定はすべてファイルにまとめられる。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/5a82f1283aefdde9d8a98823a060a050ce1efef3/pagefind.yaml#L1-L5&quot; title=&quot;こんなふう&quot;&gt;こんなふう&lt;/a&gt;にした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;site:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./docs/blog-fable&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;root_selector:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;.content&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;keep_index_url:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;glob:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{posts,pages}/*.html&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://pagefind.app/docs/config-options/#site&quot; title=&quot;&lt;code&gt;site&lt;/code&gt;&quot;&gt;&lt;code&gt;site&lt;/code&gt;&lt;/a&gt; は対象となる静的コンテンツのディレクトリ。
&lt;a href=&quot;https://pagefind.app/docs/config-options/#glob&quot; title=&quot;&lt;code&gt;glob&lt;/code&gt;&quot;&gt;&lt;code&gt;glob&lt;/code&gt;&lt;/a&gt; で指定するパターンと組み合わせて対象の静的コンテンツを指定できる。
blog-fable は &lt;code&gt;posts/&lt;/code&gt; &lt;code&gt;pages/&lt;/code&gt; 以外を対象にしたくない(404 だったり archives だったりは不要)のでこのオプションがなかったら終わってた。&lt;/p&gt;
&lt;p&gt;blog-fable では &lt;a href=&quot;https://pagefind.app/docs/config-options/#root-selector&quot; title=&quot;&lt;code&gt;root_selector&lt;/code&gt;&quot;&gt;&lt;code&gt;root_selector&lt;/code&gt;&lt;/a&gt; を使ったが、文書では &lt;code&gt;data-pagefind-body&lt;/code&gt; を使うべきで &lt;code&gt;root_selector&lt;/code&gt; は余り使う必要ないと書いてあった。
ただ blog-fable は Markdown から翻訳された HTML はすべて &lt;code&gt;.content&lt;/code&gt; 配下に出力されるので、むしろこのオプションの方がハマっていた。
一箇所だけ front matter なし page だと title 要素を拾えなかったので、しゃーなしで metadata &lt;a href=&quot;https://pagefind.app/docs/metadata/&quot; title=&quot;&lt;code&gt;data-pagefind-meta=&amp;quot;title&amp;quot;&lt;/code&gt;&quot;&gt;&lt;code&gt;data-pagefind-meta=&amp;quot;title&amp;quot;&lt;/code&gt;&lt;/a&gt; を追加した。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/5a82f1283aefdde9d8a98823a060a050ce1efef3/src/Common.fs#L49-L52&quot; title=&quot;こんなふうに&quot;&gt;こんなふうに&lt;/a&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; meta &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; l &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; data-pagefind-meta=\&amp;quot;title\&amp;quot; &amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;&amp;quot;&amp;quot;&amp;lt;h%d&lt;span class=&quot;hljs-subst&quot;&gt;{l}&lt;/span&gt; %s&lt;span class=&quot;hljs-subst&quot;&gt;{meta}&lt;/span&gt;&amp;gt;&amp;lt;a name=&amp;quot;%s&lt;span class=&quot;hljs-subst&quot;&gt;{escapedText}&lt;/span&gt;&amp;quot; href=&amp;quot;#%s&lt;span class=&quot;hljs-subst&quot;&gt;{escapedText}&lt;/span&gt;&amp;quot;&amp;gt;%s&lt;span class=&quot;hljs-subst&quot;&gt;{text}&lt;/span&gt;&amp;lt;/a&amp;gt;&amp;lt;/h%d&lt;span class=&quot;hljs-subst&quot;&gt;{l}&lt;/span&gt;&amp;gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://pagefind.app/docs/config-options/#keep-index-url&quot; title=&quot;&lt;code&gt;keep_index_url&lt;/code&gt;&quot;&gt;&lt;code&gt;keep_index_url&lt;/code&gt;&lt;/a&gt; は &lt;code&gt;index.html&lt;/code&gt; を取り除くかどうか。 blog-fable では top page 以外にないので不要だが、万が一当てはまるパターンが増えたときに加工されるのはかなんのでつけた。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;pagefind-UI-&quot; href=&quot;#pagefind-UI-&quot;&gt;pagefind UI の初期化コードを仕込む&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;次はサイトで検索を使うための初期化コードを仕込む。
オプションの指定で検索に表示される文言を変えたりするので、指定項目は多いが一通り指定するのが無難だろう。&lt;/p&gt;
&lt;p&gt;ここで注意すべき設定項目は &lt;a href=&quot;https://pagefind.app/docs/search-config/#base-url&quot; title=&quot;&lt;code&gt;baseUrl&lt;/code&gt;&quot;&gt;&lt;code&gt;baseUrl&lt;/code&gt;&lt;/a&gt; の指定だ。
blog-fable のような GitHub アカウントの page じゃない場合 URL が &lt;code&gt;https://${account}.github.io/${repo-name}/&lt;/code&gt; となる。
そのためそれに合わせて &lt;code&gt;baseUrl&lt;/code&gt; を設定する必要がある。
このブログなら GitHub アカウントの page なので &lt;code&gt;&amp;quot;/&amp;quot;&lt;/code&gt; で、 blog-fable は &lt;code&gt;&amp;quot;/blog-fable/&amp;quot;&lt;/code&gt; だ。&lt;/p&gt;
&lt;p&gt;あと blog-fable 固有の対応として、 初期化の JavaScript を F# に翻訳する必要がある。
&lt;a href=&quot;https://pagefind.app/docs/ui-usage/#adding-the-pagefind-ui-to-a-page&quot; title=&quot;Sample のコード&quot;&gt;Sample のコード&lt;/a&gt;を&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/5a82f1283aefdde9d8a98823a060a050ce1efef3/src/Handler.fs#L36-L66&quot; title=&quot;こんなふう&quot;&gt;こんなふう&lt;/a&gt; にした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;PagefindUI&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Emit &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;new $0($1, $2)&amp;quot;&lt;/span&gt;&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; Create&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;unit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Global&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; PagefindUI&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PagefindUI &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; jsNative&lt;br /&gt;&lt;br /&gt;window.addEventListener (&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;DOMContentLoaded&amp;quot;&lt;/span&gt;,&lt;br /&gt;    (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; elm &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; document.querySelector &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#search&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; isNull elm &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;            ()&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;            PagefindUI.Create(&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;!!&lt;/span&gt;{&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; element &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#search&amp;quot;&lt;/span&gt;&lt;br /&gt;                     baseUrl &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/blog-fable/&amp;quot;&lt;/span&gt;&lt;br /&gt;                     pageSize &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;&lt;br /&gt;                     translations &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                      &lt;span class=&quot;hljs-operator&quot;&gt;!!&lt;/span&gt;{&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; placeholder &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Search&amp;quot;&lt;/span&gt;&lt;br /&gt;                           clear_search &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Clear&amp;quot;&lt;/span&gt;&lt;br /&gt;                           load_more &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;More&amp;quot;&lt;/span&gt;&lt;br /&gt;                           search_label &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;                           zero_results &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\&amp;quot;[SEARCH_TERM]\&amp;quot; now found.&amp;quot;&lt;/span&gt;&lt;br /&gt;                           many_results &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\&amp;quot;[SEARCH_TERM]\&amp;quot; ([COUNT])&amp;quot;&lt;/span&gt;&lt;br /&gt;                           one_result &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\&amp;quot;[SEARCH_TERM]\&amp;quot; ([COUNT])&amp;quot;&lt;/span&gt;&lt;br /&gt;                           searching &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Searching \&amp;quot;[SEARCH_TERM]\&amp;quot;...&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;} &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;}&lt;br /&gt;            ))&lt;br /&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;new PagefindUI&lt;/code&gt; は &lt;code&gt;pagefind-ui.js&lt;/code&gt; を読み込んでいれば global に展開されているので、 Fable の &lt;a href=&quot;https://fable.io/docs/javascript/features.html#emit-when-f-is-not-enough&quot; title=&quot;Emit&quot;&gt;Emit&lt;/a&gt; で呼び出すのが多分いちばん楽。
&lt;code&gt;new PagefindUI&lt;/code&gt; の引数は本来なら型をちゃんと書いた方が良いが、どのオプションを使うべきか定かでなかったのもあり横着して匿名レコードをぶち込んでいる。
あと pagefind UI の埋め込み対象の要素は Archives ページにだけ作るようにしたので、その要素がない場合のエラー避けをした(これも横着)。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;pagefind-UI-&quot; href=&quot;#pagefind-UI-&quot;&gt;pagefind UI のスタイル調整する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;最後に pagefind UI のスタイルを調整する。
&lt;a href=&quot;https://pagefind.app/docs/ui-usage/#customising-the-styles&quot; title=&quot;CSS custom parameter が提供されている&quot;&gt;CSS custom parameter が提供されている&lt;/a&gt;ので基本それでスタイル調整する。
light と dark の 2 テーマあるので&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/5a82f1283aefdde9d8a98823a060a050ce1efef3/sass/style.scss#L92-L101&quot; title=&quot;ここ&quot;&gt;ここ&lt;/a&gt;と&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/5a82f1283aefdde9d8a98823a060a050ce1efef3/sass/style.scss#L145-L154&quot; title=&quot;ここ&quot;&gt;ここ&lt;/a&gt;にで CSS custom parameter を上書きしている。
当然、 &lt;code&gt;pagefind-ui.css&lt;/code&gt; の読み込み後じゃないと上書きできないので、読み込み順も注意する。&lt;/p&gt;
&lt;p&gt;ただ CSS custom parameter でできることが限定的で、あまり納得行く出来にならない。
なので必要に応じて独自に CSS を書くのが妥当だろう。いまはまだやってないけど。
検索結果の highlight が &lt;code&gt;mark&lt;/code&gt; 要素で囲まれたり、検索フィールドにフォーカスすると枠が太くなるのとか、デザインの調和が取れてないと個人的に感じる点は今後いじっておきたい。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;その他&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;あとこれ以外にも blog-fable 固有の問題があった。
それは開発サーバとして使ってる &lt;a href=&quot;https://github.com/SuaveIO/suave&quot; title=&quot;Suave&quot;&gt;Suave&lt;/a&gt; がデフォルトで未知の拡張子のファイルを配信できず 404 になるというものだ。
一度知ってしまったら簡単だけど、これは結構調べるのに時間がかかった。&lt;/p&gt;
&lt;p&gt;デフォの MIME type → &lt;a href=&quot;https://github.com/SuaveIO/suave/blob/d9deb5f4f973fd21d15bdd7e85ac9c0bee05baab/src/Suave/Combinators.fs#L87-L112&quot; title=&quot;suave/src/Suave/Combinators.fs&quot;&gt;suave/src/Suave/Combinators.fs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;拡張はこうやる。
&lt;a href=&quot;https://github.com/SuaveIO/suave/blob/d9deb5f4f973fd21d15bdd7e85ac9c0bee05baab/examples/Example/Program.fs#L79-L80&quot; title=&quot;suave/examples/Example/Program.fs&quot;&gt;suave/examples/Example/Program.fs&lt;/a&gt;
拡張した MIME type の設定を Suave の &lt;a href=&quot;https://github.com/SuaveIO/suave/blob/d9deb5f4f973fd21d15bdd7e85ac9c0bee05baab/src/Suave/Web.fs#L71&quot; title=&quot;&lt;code&gt;startWebServer&lt;/code&gt;&quot;&gt;&lt;code&gt;startWebServer&lt;/code&gt;&lt;/a&gt; に渡したらいい。&lt;/p&gt;
&lt;p&gt;pagefind は生成した Wasm に付与した 4 つ独自の拡張子を持っているので、それらを &lt;code&gt;application/octet-stream&lt;/code&gt; で配信するものだと明示してやらないといけない。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/5a82f1283aefdde9d8a98823a060a050ce1efef3/dev-server.fsx#L143-L158&quot; title=&quot;こんなふう&quot;&gt;こんなふう&lt;/a&gt;にした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; cfg &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    { defaultConfig &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;        homeFolder &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;(home)&lt;br /&gt;        compressedFilesFolder &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;(home)&lt;br /&gt;        bindings &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; [ HttpBinding.create HTTP IPAddress.Loopback port ]&lt;br /&gt;        listenTimeout &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; TimeSpan.FromMilliseconds &lt;span class=&quot;hljs-number&quot;&gt;3000.&lt;/span&gt;&lt;br /&gt;        mimeTypesMap &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            Writers.defaultMimeTypesMap&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Add custom mime types for pagefind to prevent 404 error.&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;@@&lt;/span&gt; ((&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.pagefind&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.pf_fragment&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.pf_index&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.pf_meta&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; Writers.createMimeType &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;application/octet-stream&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;)) }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(ちなみに Suave のページが不安定みたい)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;これで pagefind の設定は第 1 回戦終了って感じ。
まだ気に入らない点あるし検索の使い勝手も検証してないけど、ないよりいいやろ。
ちょくちょく改善入れていきたい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 23 Jun 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-06-16-update-for-marked-v13.html</guid><link>https://krymtkts.github.io/posts/2024-06-16-update-for-marked-v13.html</link><title>blog-fable を Marked v13 に対応する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今日は &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; の話を書く。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/krymtkts.github.io&quot; title=&quot;このブログ&quot;&gt;このブログ&lt;/a&gt;の基盤 krymtkts/blog-fable はコンテンツを Markdown で管理していて、 Markdown を HTML にコンパイルするのに &lt;a href=&quot;https://github.com/markedjs/marked&quot; title=&quot;markedjs/marked&quot;&gt;markedjs/marked&lt;/a&gt; を使っている。&lt;/p&gt;
&lt;p&gt;つい先日 marked が v13 になったらしく Dependabot が PR を投げてきたので merge したらブログ記事が壊れた 💥。
ちゃんと調べてなかったのだけど、 v13 では parser に破壊的な変更があって、仕込んでいる Marked Extension が壊れたようだった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/markedjs/marked/releases/tag/v13.0.0&quot; title=&quot;Release v13.0.0 · markedjs/marked&quot;&gt;Release v13.0.0 · markedjs/marked&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Marked v13.0.0 のリリースノートから変更前後のコードを拝借すると以下の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// v12 renderer extension&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; extension = {&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;renderer&lt;/span&gt;: {&lt;br /&gt;    &lt;span class=&quot;hljs-title function_&quot;&gt;heading&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;text, level&lt;/span&gt;) {&lt;br /&gt;      &lt;span class=&quot;hljs-comment&quot;&gt;// increase level by 1&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`&amp;lt;h&lt;span class=&quot;hljs-subst&quot;&gt;${level + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;}&lt;/span&gt;&amp;gt;&lt;span class=&quot;hljs-subst&quot;&gt;${text}&lt;/span&gt;&amp;lt;/h&lt;span class=&quot;hljs-subst&quot;&gt;${level + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;}&lt;/span&gt;&amp;gt;`&lt;/span&gt;;&lt;br /&gt;    },&lt;br /&gt;  },&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// v13 renderer extension&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; extension = {&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;useNewRenderer&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;renderer&lt;/span&gt;: {&lt;br /&gt;    &lt;span class=&quot;hljs-title function_&quot;&gt;heading&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;token&lt;/span&gt;) {&lt;br /&gt;      &lt;span class=&quot;hljs-comment&quot;&gt;// increase depth by 1&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; text = &lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;parser&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;parseInline&lt;/span&gt;(token.&lt;span class=&quot;hljs-property&quot;&gt;tokens&lt;/span&gt;);&lt;br /&gt;      &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; level = token.&lt;span class=&quot;hljs-property&quot;&gt;depth&lt;/span&gt;;&lt;br /&gt;      &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`&amp;lt;h&lt;span class=&quot;hljs-subst&quot;&gt;${level + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;}&lt;/span&gt;&amp;gt;&lt;span class=&quot;hljs-subst&quot;&gt;${text}&lt;/span&gt;&amp;lt;/h&lt;span class=&quot;hljs-subst&quot;&gt;${level + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;}&lt;/span&gt;&amp;gt;`&lt;/span&gt;;&lt;br /&gt;    },&lt;br /&gt;  },&lt;br /&gt;};
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;雑に言えば、 renderer の各要素に対応付く関数が parse 済み文字列を受け取っていたのが、 token を受け取って自身で parse するように変わった。&lt;/p&gt;
&lt;p&gt;blog-fable では Markdown を HTML に変換する際 &lt;code&gt;heading&lt;/code&gt; &lt;code&gt;link&lt;/code&gt; &lt;code&gt;listitem&lt;/code&gt; &lt;code&gt;checkbox&lt;/code&gt; &lt;code&gt;image&lt;/code&gt; の renderer を拡張している。
ここが壊れたわけだったので、関数の引数を変えたらいいだけと簡単に考えていた。
ただ結構手こずった。&lt;/p&gt;
&lt;p&gt;Marked の新しい renderer は引数に &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/variable-declarations.html#destructuring&quot; title=&quot;destructuring assignment&quot;&gt;destructuring assignment&lt;/a&gt; を使ってる。&lt;/p&gt;
&lt;p&gt;この辺。 &lt;a href=&quot;https://github.com/markedjs/marked/blob/70bb55e0af5128a657a14b8b25d7d406661e6936/src/Renderer.ts&quot; title=&quot;marked/src/Renderer.ts at 70bb55e0af5128a657a14b8b25d7d406661e6936 · markedjs/marked&quot;&gt;marked/src/Renderer.ts at 70bb55e0af5128a657a14b8b25d7d406661e6936 · markedjs/marked&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;型定義ファイルだとこの様になっていた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;/**&lt;br /&gt; * Renderer&lt;br /&gt; */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;declare&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;_Renderer&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;options&lt;/span&gt;: &lt;span class=&quot;hljs-title class_&quot;&gt;MarkedOptions&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;parser&lt;/span&gt;: _Parser;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;constructor&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;options&lt;/span&gt;?: &lt;span class=&quot;hljs-title class_&quot;&gt;MarkedOptions&lt;/span&gt;&lt;/span&gt;);&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;space&lt;/span&gt;(&lt;span class=&quot;hljs-attr&quot;&gt;token&lt;/span&gt;: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Space&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;code&lt;/span&gt;({ text, lang, escaped }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Code&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;blockquote&lt;/span&gt;({ tokens }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Blockquote&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;html&lt;/span&gt;({ text }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;HTML&lt;/span&gt; | &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Tag&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;heading&lt;/span&gt;({ tokens, depth }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Heading&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;hr&lt;/span&gt;(&lt;span class=&quot;hljs-attr&quot;&gt;token&lt;/span&gt;: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Hr&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-attr&quot;&gt;token&lt;/span&gt;: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;List&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;listitem&lt;/span&gt;(&lt;span class=&quot;hljs-attr&quot;&gt;item&lt;/span&gt;: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;ListItem&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;checkbox&lt;/span&gt;({ checked }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Checkbox&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;paragraph&lt;/span&gt;({ tokens }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Paragraph&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;table&lt;/span&gt;(&lt;span class=&quot;hljs-attr&quot;&gt;token&lt;/span&gt;: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Table&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;tablerow&lt;/span&gt;({ text }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;TableRow&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;tablecell&lt;/span&gt;(&lt;span class=&quot;hljs-attr&quot;&gt;token&lt;/span&gt;: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;TableCell&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;/**&lt;br /&gt;   * span level renderer&lt;br /&gt;   */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;strong&lt;/span&gt;({ tokens }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Strong&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;em&lt;/span&gt;({ tokens }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Em&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;codespan&lt;/span&gt;({ text }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Codespan&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;br&lt;/span&gt;(&lt;span class=&quot;hljs-attr&quot;&gt;token&lt;/span&gt;: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Br&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;del&lt;/span&gt;({ tokens }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Del&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;link&lt;/span&gt;({ href, title, tokens }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Link&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;image&lt;/span&gt;({ href, title, text }: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Image&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;text&lt;/span&gt;(&lt;span class=&quot;hljs-attr&quot;&gt;token&lt;/span&gt;: &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Text&lt;/span&gt; | &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Escape&lt;/span&gt; | &lt;span class=&quot;hljs-title class_&quot;&gt;Tokens&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;Tag&lt;/span&gt;): &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これらを Fable だとどうしたらいいのかわからなかった。
分解後のパラメータを受け取るのか？的な。
だが試しに動かして調べたら、結局のところ関数に渡ってくるのはすべて &lt;code&gt;Token.Xxx&lt;/code&gt; だった。
なので binding では destructuring assignment を無視したらいいみたい。
以下のように Marked の binding を調整したらうまくいった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Renderer&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Renderer&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;obj&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;AllowNullLiteral&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Renderer&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;T&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; options&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; MarkedOptions &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; code&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Code &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; blockquote&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Blockquote &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; html&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.HTML &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; heading&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Heading &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; hr&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Hr &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; list&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.List &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; listitem&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.ListItem &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; checkbox&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Checkbox &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; paragraph&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Paragraph &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; table&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Table &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; tablerow&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.TableRow &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; tablecell&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.TableCell &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; strong&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Strong &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; em&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Em &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; codespan&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Codespan &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; br&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Br &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; del&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Del &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; link&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Link &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; image&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Image &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; text&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt;  item&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Tokens.Text &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;いま blog-fable で使ってる Marked の binding は使ってない型もいっぱい入ってるからわかりにくいし、いつか整理したい。
今回はいくつかをコメントアウトするだけに留めた。
なんならこういう破壊的な変更によるメンテ作業避ける名目で Markdown の parser &amp;amp; compiler を Fable で書くのもいいのかも。
これはやりたいことに積んどこう。&lt;/p&gt;
&lt;p&gt;あと renderer 内で parser を呼び出す際の注意点もあった。
block 要素と inline 要素で parser method を使い分ける必要があって、例えば block の token を parseInline に渡すとエラーになってしまう。
エラーにしてるのはこの辺。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/markedjs/marked/blob/70bb55e0af5128a657a14b8b25d7d406661e6936/src/Parser.ts#L194-L202&quot; title=&quot;marked/src/Parser.ts at 70bb55e0af5128a657a14b8b25d7d406661e6936 · markedjs/marked&quot;&gt;marked/src/Parser.ts at 70bb55e0af5128a657a14b8b25d7d406661e6936 · markedjs/marked&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;blog-fable とこのブログでは、今のところ &lt;code&gt;listitem&lt;/code&gt; だけ block を含む可能性があるようだった。
そういう要素は &lt;a href=&quot;https://github.com/markedjs/marked/blob/70bb55e0af5128a657a14b8b25d7d406661e6936/src/Parser.ts#L135-L206&quot; title=&quot;&lt;code&gt;parseInline&lt;/code&gt;&quot;&gt;&lt;code&gt;parseInline&lt;/code&gt;&lt;/a&gt; の代わりに &lt;a href=&quot;https://github.com/markedjs/marked/blob/70bb55e0af5128a657a14b8b25d7d406661e6936/src/Parser.ts#L42-L130&quot; title=&quot;&lt;code&gt;parse&lt;/code&gt;&quot;&gt;&lt;code&gt;parse&lt;/code&gt;&lt;/a&gt; を使うことで対処できるが、 余計な &lt;code&gt;p&lt;/code&gt; で囲まれるのは少し気になった。&lt;/p&gt;
&lt;p&gt;これで多分ブログがそこそこ従来通りの表示をするようになったはずだ。
ぶっ壊れたまま気づいてない点とかあるだろうけど、今後見つけたら直すという方針でいこう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 16 Jun 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-06-09-writing-cmdlet-in-fsharp-pt42.html</guid><link>https://krymtkts.github.io/posts/2024-06-09-writing-cmdlet-in-fsharp-pt42.html</link><title>F# でコマンドレットを書いてる pt.42</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-06-02-writing-cmdlet-in-fsharp-pt41.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt; 考えた方針で基本実装できたので、諸々の TODO は残しているけど一旦 pull request を merge して区切りをつけた。
とはいえ結構直さないといけないところがいっぱいなので、 &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/177&quot; title=&quot;#177&quot;&gt;#177&lt;/a&gt; の issue に関連付ける形でいくつか pull request を積んでいっているところ。&lt;/p&gt;
&lt;p&gt;実装に関しては思ったよりも制御が難しかったが、以下に示すような延々と &lt;code&gt;WriteObject&lt;/code&gt; してくるような Cmdlet が上流にいても、即座に起動してユーザ入力を受け付けられるようになった。
これはつまりとんでもなくデータ量が多くても即座に起動できることを意味する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Invoke-InfiniteLoop&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;scriptblock&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$ScriptBlock&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;) {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$ScriptBlock&lt;/span&gt;) {&lt;br /&gt;                &amp;amp; &lt;span class=&quot;hljs-variable&quot;&gt;$ScriptBlock&lt;/span&gt;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 100 ms 毎に WriteObject するので Select-Object 以外の通常の Cmdlet は止まれない&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# pocof は Cancel action を使えば終了できる&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-InfiniteLoop&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ScriptBlock&lt;/span&gt; {&lt;span class=&quot;hljs-variable&quot;&gt;$global:a&lt;/span&gt; += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; &lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;Start-Sleep&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Milliseconds&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt;} | pocof
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;個人的に、ちょっとしたデータ量の通常利用時でも初回のレスポンス向上になった気がして、良いかもと感じている。
ただ現状ユーザ入力がないと再描画しないので、ユーザ入力 ≒ 操作がないと定期的に再描画する仕組みが必要で、それは TODO として積んでいる。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;最近の pocof 実装はそんなに悩むことなのだけど、今回の非同期レンダリングは比較的悩みごとが多かった。腕が不足してるんやろなと感じる。&lt;/p&gt;
&lt;p&gt;非同期コレクションを生で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pscmdlet?view=powershellsdk-7.4.0&quot; title=&quot;PSCmdlet&quot;&gt;PSCmdlet&lt;/a&gt; 継承クラスから使うのはいまいちかなと思って wrapped type を作ったのだけど、 F# 的にこのアプローチで良かったのかなと感じながらやってた。
でも &lt;a href=&quot;https://github.com/dotnet/fsharp/blob/main/src/FSharp.Core/mailbox.fs#L361-361&quot; title=&quot;FSharp.Core/mailbox&quot;&gt;FSharp.Core/mailbox&lt;/a&gt; みたいな非同期処理 utility も同じアプローチでカプセル化してるし、多分そんなに変ではないはず。&lt;/p&gt;
&lt;p&gt;他にも、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.cmdlet.endprocessing?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;Cmdlet.EndProcessing&lt;/code&gt;&quot;&gt;&lt;code&gt;Cmdlet.EndProcessing&lt;/code&gt;&lt;/a&gt; を &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-optionmodule#iter&quot; title=&quot;&lt;code&gt;Option.iter&lt;/code&gt;&quot;&gt;&lt;code&gt;Option.iter&lt;/code&gt;&lt;/a&gt; や &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/match-expressions&quot; title=&quot;Pattern matching function&quot;&gt;Pattern matching function&lt;/a&gt; の中で使おうとしてスコープが解決出来ないのを知ったり。 method 呼び出しの場合暗黙で第一引数に instance が渡されるから、スコープが違うと protected method は呼べないらしいな。初めて知った。
仕方ないので &lt;code&gt;EndProcessing&lt;/code&gt; を呼ぶだけの member method を作ってそれを &lt;code&gt;Option.iter&lt;/code&gt; の引数の関数に渡した。&lt;/p&gt;
&lt;p&gt;また先述の TODO 以外にもなんか怪しいところがチラホラある。
まだあまりテストできていないが、もともと直列で動くことが前提だったこともありユーザ入力と描画がかち合ってたまにカーソル位置がおかしくなるような。
内部状態の更新は直列で実行されるから問題ないと踏んでたけど、描画部分でなんかやらかしてるのか。
他にも開発中はたまに入力が hang up することもあったし、アレがまだ発生しうるのかもチェックしないと。&lt;/p&gt;
&lt;p&gt;あと、この変更によって Pester による E2E テストが flaky になってしまったぽいところ。今のところ開発環境では落ちたことがないが、 GitHub Actions の macOS の workflow がたまに落ちるのがわかっている。&lt;/p&gt;
&lt;p&gt;これらは &lt;a href=&quot;https://github.com/fsprojects/FsUnit&quot; title=&quot;FsUnit&quot;&gt;FsUnit&lt;/a&gt; や &lt;a href=&quot;https://github.com/pester/Pester&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; でのテストでは拾いきれない部分なので、マニュアルテストを日常的に実施するために久しぶりの Prerelease をしてもいいかもなーと考えている。
ただしバグが多いうちから出すのは流石に自身の日常使用に耐えないだろうから、 TODO はなるべく解消したうえで v0.14.0-alpha を出すのがいいかな。&lt;/p&gt;
&lt;p&gt;Cmdlet の機能を使う非同期プログラミング、けっこう大変だったけどいい経験になった。
まだ全くイケてるとは言い難い構造だし、もっとマシな実装ないんかとか、もう一度やりたいものではないなというのが本音だけど。
やりようによってはできるなというのがわかっただけでも良い。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 09 Jun 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-06-02-writing-cmdlet-in-fsharp-pt41.html</guid><link>https://krymtkts.github.io/posts/2024-06-02-writing-cmdlet-in-fsharp-pt41.html</link><title>F# でコマンドレットを書いてる pt.41</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;最近の &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 開発をまとめておく。&lt;/p&gt;
&lt;p&gt;大量データを処理する場合、描画までめちゃくちゃ遅くなる課題 &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/177&quot; title=&quot;#177&quot;&gt;#177&lt;/a&gt; の対処を試している。
対処法としては単純に、① 描画、② ユーザによるクエリ入力、③ &lt;code&gt;ProcessRecord&lt;/code&gt; からのデータ入力の 3 つが切り分けられて別々に動いたら良いだけ。
issue 起票したときから非同期にしたら余裕よな～という感触はあった。
①、② を非同期にし、③ が終了した後 &lt;code&gt;EndProcessing&lt;/code&gt; で ①② の終了を待ち受けるイメージ。
これが実装できない場合、 3 つに切り分ける数を 2 つに減らすとか、最悪のケースは全部直列で処理する。
最悪 ③ で特定の件数毎に ①、② は諦めて &lt;code&gt;EndProcessing&lt;/code&gt; で起動する、というイメージだった。&lt;/p&gt;
&lt;p&gt;ただこのアイデアを実装に移すにあたり、わたし自身事前に勉強しておく必要があった。
.NET や F# で並行/並列のような非同期プログラミングをほぼやったことなかった(意外とそういう機会なかった)し、 Cmdlet 内での非同期処理をどう扱えるか知らないのもあり。
アイデアの実現可能性を探る必要があったということ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/fsharp-cmdlet-sandbox&quot; title=&quot;krymtkts/fsharp-cmdlet-sandbox&quot;&gt;krymtkts/fsharp-cmdlet-sandbox&lt;/a&gt; で、お試しコードを書きつつドキュメントを見つつで try &amp;amp; error して、漸く感触を掴んできた。&lt;/p&gt;
&lt;p&gt;わかってきたのは以下の感じ。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pscmdlet?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;PSCmdlet&lt;/code&gt;&quot;&gt;&lt;code&gt;PSCmdlet&lt;/code&gt;&lt;/a&gt; 内で普通の処理を非同期にするのは .NET と F# の POWER もあり簡単。でも PowerShell 由来の機能を使うのは出来ないという印象だった。なかなかハードル高い。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;F# には &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/async-expressions&quot; title=&quot;&lt;code&gt;async&lt;/code&gt;&quot;&gt;&lt;code&gt;async&lt;/code&gt;&lt;/a&gt; &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/task-expressions&quot; title=&quot;&lt;code&gt;task&lt;/code&gt;&quot;&gt;&lt;code&gt;task&lt;/code&gt;&lt;/a&gt; computation 等の非同期のための準備が整っている&lt;/li&gt;&lt;li&gt;.NET には &lt;a href=&quot;https://learn.microsoft.com/en-us/archive/msdn-magazine/2011/february/msdn-magazine-parallel-computing-it-s-all-about-the-synchronizationcontext&quot; title=&quot;&lt;code&gt;SynchronizationContext&lt;/code&gt;&quot;&gt;&lt;code&gt;SynchronizationContext&lt;/code&gt;&lt;/a&gt; で特定の thread で処理を実行する下地があり、 &lt;code&gt;task&lt;/code&gt; や &lt;code&gt;async&lt;/code&gt; でそれが使える(&lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-control-fsharpasync.html#SwitchToContext&quot; title=&quot;&lt;code&gt;Async.SwitchToContext&lt;/code&gt;&quot;&gt;&lt;code&gt;Async.SwitchToContext&lt;/code&gt;&lt;/a&gt;)&lt;ul&gt;
&lt;li&gt;ただし &lt;code&gt;SynchronizationContext.Current&lt;/code&gt; は Windows.Form や WPF 等では提供されていても CLI Application ひいては Cmdlet には提供されてない&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;PowerShell の Cmdlet 実装は single thread を前提にしている&lt;ul&gt;
&lt;li&gt;これちょっと裏付けのドキュメントが見つけれてないから探したい&lt;/li&gt;&lt;li&gt;multi threading で操作したらこんな感じのエラーが出た&lt;ul&gt;
&lt;li&gt;&lt;blockquote&gt;
&lt;p&gt;Select-Pocof: The WriteObject and WriteError methods cannot be called from outside the overrides of the BeginProcessing, ProcessRecord, and EndProcessing methods, and they can only be called from within the same thread. Validate that the cmdlet makes these calls correctly, or contact Microsoft Customer Support Services.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;(余談だが) PowerShell では無限リストのような終わらないデータ構造をサポートしている Cmdlet はそんなにない。 &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/select-object?view=powershell-7.4&quot; title=&quot;&lt;code&gt;Select-Object -First&lt;/code&gt;&quot;&gt;&lt;code&gt;Select-Object -First&lt;/code&gt;&lt;/a&gt; が代表格&lt;ul&gt;
&lt;li&gt;基本 &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.management.automation.cmdlet.beginprocessing?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;BeginProcessing&lt;/code&gt;&quot;&gt;&lt;code&gt;BeginProcessing&lt;/code&gt;&lt;/a&gt; → &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.management.automation.cmdlet.processrecord?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;ProcessRecord&lt;/code&gt;&quot;&gt;&lt;code&gt;ProcessRecord&lt;/code&gt;&lt;/a&gt; → &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.management.automation.cmdlet.endprocessing?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;EndProcessing&lt;/code&gt;&quot;&gt;&lt;code&gt;EndProcessing&lt;/code&gt;&lt;/a&gt; のフローを抜けることはできない&lt;/li&gt;&lt;li&gt;&lt;code&gt;Select-Object&lt;/code&gt; は &lt;code&gt;StopUpstreamCommandsException&lt;/code&gt; という秘密の内部例外で以てフローを中断できる。 &lt;code&gt;ProcessRecord&lt;/code&gt; を中断させる方法は公式に提供されないので、みんな reflection でこの方法を流用して中断している&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PowerShell/PowerShell/issues/3821&quot; title=&quot;Allow user code to stop a pipeline on demand / to terminate upstream cmdlets. · Issue #3821 · PowerShell/PowerShell&quot;&gt;Allow user code to stop a pipeline on demand / to terminate upstream cmdlets. · Issue #3821 · PowerShell/PowerShell&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;pocof で非同期的に描画を始める場合、全部読み込み終わる前にキャンセルするケースを考えたらこれが必要だったので調べた&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;pocof では &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.cmdlet.writeobject?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;WriteObject&lt;/code&gt;&quot;&gt;&lt;code&gt;WriteObject&lt;/code&gt;&lt;/a&gt; 以外に PowerShell 由来の機能を使っている。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.commandinvocationintrinsics.invokescript?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;PSCmdlet.InvokeCommand.InvokeScript&lt;/code&gt;&quot;&gt;&lt;code&gt;PSCmdlet.InvokeCommand.InvokeScript&lt;/code&gt;&lt;/a&gt; で描画のフォーマットをしているのがそれだ。
multi threading でも &lt;code&gt;int&lt;/code&gt; とか &lt;code&gt;PSCustomObject&lt;/code&gt; を流す程度なら問題なかったのだけど、 &lt;code&gt;Get-ChildItem&lt;/code&gt; の結果を流すと描画後に処理が詰まるとわかった。
深く追えてないけど &lt;code&gt;FileInfo&lt;/code&gt; あたりがダメなんかな...？という感じ。回避できない。
マジか。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WriteObject&lt;/code&gt; を main thread に置くのは造作もない。 pocof の場合は最後の &lt;code&gt;EndProcessing&lt;/code&gt; で実行したらいいだけだからだ。
けど、 &lt;code&gt;PSCmdlet.InvokeCommand.InvokeScript&lt;/code&gt; を main thread に限定するのが難しい。常に描画する事があるためだ。&lt;/p&gt;
&lt;p&gt;これを解消する実装パターン的にまさに UI で求められてるのと同じなので &lt;code&gt;SynchronizationContext&lt;/code&gt; にハマるはずだった。
ただし CLI Application には提供されていない。
また自前でそれを作るとしても CLI Application に独自の &lt;code&gt;SynchronizationContext&lt;/code&gt; 実装を組み込むのは困難が伴う。
他の回避方法を探るために、例えば &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1?view=net-8.0&quot; title=&quot;&lt;code&gt;System.Collections.ObjectModel.ObservableCollection&lt;/code&gt;&quot;&gt;&lt;code&gt;System.Collections.ObjectModel.ObservableCollection&lt;/code&gt;&lt;/a&gt; なんかを使ってイベント駆動で描画しようとも試した。
けどコレクションに put した thread でイベントハンドラが実行されるので、先述の詰まりを回避できない。&lt;/p&gt;
&lt;p&gt;結局のところ、 main thread に自前の event loop もどきを構築する形で実現することにした。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/186&quot; title=&quot;#186&quot;&gt;#186&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ユーザ入力とクエリ結果生成を &lt;code&gt;async&lt;/code&gt; に逃して、 PowerShell 由来の機能を使う描画は main thread で地道に event loop を組む。
これには非同期コレクションを 2 つ用いた。 1 つは検索対象を保持する非同期コレクション ①、もう １ つはクエリ結果を格納する描画イベントと終了イベントを保持する非同期コレクション ②。実装イメージはこうだ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BeginProcessing&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;ユーザ入力待受やユーザ入力によるクエリ更新を &lt;code&gt;async&lt;/code&gt; で起動、ユーザ入力によるクエリ更新があれば非同期コレクション ② に描画イベントを発行する&lt;/li&gt;&lt;li&gt;画面の初期化はここで実行する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;ProcessRecord&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;逐次受け渡される &lt;code&gt;InputObject&lt;/code&gt; を非同期コレクション ① に追加する&lt;/li&gt;&lt;li&gt;非同期コレクション ② にから描画イベントを受け取ればそれで描画する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;EndProcessing&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;描画の event loop を開始し、非同期コレクション ② から描画イベントを受け取れば描画、終了イベントを受け取れば event loop を終了する&lt;/li&gt;&lt;li&gt;ユーザ入力の &lt;code&gt;async&lt;/code&gt; が完了するのを待つ&lt;/li&gt;&lt;li&gt;&lt;code&gt;async&lt;/code&gt; から結果を受け取ったら &lt;code&gt;WriteObject&lt;/code&gt; して終了する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;もっとマシな方法ないんかコラという感じではあるが...少なくともうまく実装出来そうな気配はしてきた。
まだ完成してなくて、上記の切り分けをしたうえで従来の処理フローを再現できた状態まできた。この後また詰まることあったら路線変更するかも。&lt;/p&gt;
&lt;p&gt;もしうまくいったら、大規模にリファクタリングしたい。
いま、先述の非同期コレクション ② に使ってる &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentstack-1?view=net-8.0&quot; title=&quot;&lt;code&gt;ConcurrentStack&lt;/code&gt;&quot;&gt;&lt;code&gt;ConcurrentStack&lt;/code&gt;&lt;/a&gt; が生で露出してるので、そこは抽象化出来たらかっこいいよねという気持ち。
それに既存のテストも結構モジュール構造に合わなくなってしまったので、新しい構造に寄り添わせないとカオスなテストがより手懐けられなくなる。
カバレッジもなんか落としてしまってるので改善できないか見る。&lt;/p&gt;
&lt;p&gt;あと今回 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/lazy-expressions&quot; title=&quot;&lt;code&gt;lazy&lt;/code&gt;&quot;&gt;&lt;code&gt;lazy&lt;/code&gt;&lt;/a&gt; は使わなかったが、クエリ結果とかまさにこのパターンにハマるような気配もするけど試せてない。&lt;/p&gt;
&lt;p&gt;Cmdlet に独自の処理フローを実装しようとしたら出来なくはないけどけっこう大変なんやなというのを身を以て知れて良かった。うまく非同期レンダリング実装できたら pocof 良くなりそう。
(そんなクソデカデータや無限リストを PowerShell で扱うやつがどこにおるねんというオーバースペック感)&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;p&gt;(なんか自ブログ執筆中の dev-server で websocket 通らなくなってるなんで)&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 02 Jun 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-05-26-refactor-powershell-profile-2.html</guid><link>https://krymtkts.github.io/posts/2024-05-26-refactor-powershell-profile-2.html</link><title>PowerShell の profile を再構成する pt.2</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2024-04-28-refactor-powershel-profile.html&quot; title=&quot;前に PowerShell の profile を再構成し始めたこと&quot;&gt;前に PowerShell の profile を再構成し始めたこと&lt;/a&gt;に触れた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;バグ修正の他に初期化の処理をカテゴリ毎に関数を分類してみたりしたが、これどこまでやるべきなんやろかというのは悩ましいところだ。
profile の処理を分類したかったら結局ファイルを分けることになって、ファイルを分けると profile のディレクトリ全体を履歴管理するのが定石。
でもそのような profile 全体を git の管理下に置くのは個人的には好きでないので、どうしたもんかな。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;結局関数に小分けしたとて 1 つのファイルんい書いてることから、使わない機能があっても丸ごとスクリプトに含まれてるし、スクリプトが長くなって見にくい。
もうこれはファイル分割せざるを得ないなと諦めて、ひとまず自分で決めたカテゴリ毎に野良 &lt;code&gt;psm1&lt;/code&gt; 二分割してモジュール化した。
それらを &lt;code&gt;Update-Profile&lt;/code&gt; という PowerShell の profile を GitHub から Download して読み込む関数に組み、最新化できるようにした。&lt;/p&gt;
&lt;p&gt;個人的に、多少しょぼいモジュールであっても、PowerShell Gallery に公開できるようなものについてはそちらに publish すべきだと考えている。
ニッチであれば世界のどこかの 10 人くらいは使ってくれるだろうってのは体感的に知っているし。
であるが profile に含まれるものの大半が、自分の局所的用途にしか使われないので、ここでは野良モジュールがふさわしい。&lt;/p&gt;
&lt;p&gt;まだ若干掃除しきれてないが、大体こんな構造になってる。
&lt;a href=&quot;https://github.com/krymtkts/pwsh-profile/blob/main/Microsoft.PowerShell_profile.ps1#L18-L72&quot; title=&quot;pwsh-profile/Microsoft.PowerShell_profile.ps1 at main · krymtkts/pwsh-profile&quot;&gt;pwsh-profile/Microsoft.PowerShell_profile.ps1 at main · krymtkts/pwsh-profile&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ③profile 読み込み時に野良モジュールを読み込む&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$PROFILE&lt;/span&gt; | Split-Path -Parent)/Scripts&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Filter&lt;/span&gt; *.psm1 | &lt;span class=&quot;hljs-built_in&quot;&gt;Import-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ②野良モジュールを GitHub repo から download する&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Update-ProfileScripts&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Autocomplete&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;AWS&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Functions&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Get-Hash&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Git&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Go&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Mod&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Nodejs&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;OpenAI&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Pocof&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Psake&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSResource&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Python&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;StandardNotes&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Strings&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Windows&amp;#x27;&lt;/span&gt;&lt;br /&gt;    ) | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$modulePath&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{_}/&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{_}.psm1&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$scriptPath&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{ProfileHome}/Scripts/&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{modulePath}&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Split-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$scriptPath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parent&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt;)) {&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;New-Item&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ItemType&lt;/span&gt; Directory &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Split-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$scriptPath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parent&lt;/span&gt;) &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$params&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;            Uri = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{baseUrl}/Scripts/&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{modulePath}&amp;quot;&lt;/span&gt;&lt;br /&gt;            OutFile = &lt;span class=&quot;hljs-variable&quot;&gt;$scriptPath&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; @params | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ① PowerShell profile を GitHub repo から download する&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Update-Profile&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$ProfileHome&lt;/span&gt; = (&lt;span class=&quot;hljs-variable&quot;&gt;$PROFILE&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Split-Path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parent&lt;/span&gt;)&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$ProfilePath&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{ProfileHome}/Microsoft.PowerShell_profile.ps1&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$baseUrl&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://raw.githubusercontent.com/krymtkts/pwsh-profile/main/&amp;#x27;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$params&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        Uri = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{baseUrl}/Microsoft.PowerShell_profile.ps1&amp;quot;&lt;/span&gt;&lt;br /&gt;        OutFile = &lt;span class=&quot;hljs-variable&quot;&gt;$ProfilePath&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; @params | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{ProfileHome}/Microsoft.VSCode_profile.ps1&amp;quot;&lt;/span&gt;)) {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;New-Item&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ItemType&lt;/span&gt; HardLink &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$ProfileHome&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Microsoft.VSCode_profile.ps1&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Value&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$ProfilePath&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# TODO: load the profile to prepare new psm1 files.&lt;/span&gt;&lt;br /&gt;    . &lt;span class=&quot;hljs-variable&quot;&gt;$ProfilePath&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Update-ProfileScripts&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# TODO: load the profile again to apply new psm1 files.&lt;/span&gt;&lt;br /&gt;    . &lt;span class=&quot;hljs-variable&quot;&gt;$ProfilePath&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;野良モジュールは &lt;code&gt;$PROFILE&lt;/code&gt; と同じディレクトリの &lt;code&gt;Scripts&lt;/code&gt; 配下へ配置するようにした。
野良モジュールといえど &lt;code&gt;Modules&lt;/code&gt; に配置するのが定石だろうが、パッと見だと見分けつかないし自分の用途だと &lt;code&gt;Scripts&lt;/code&gt; は遊んでて空いてるので。&lt;/p&gt;
&lt;p&gt;分割したモジュールを更新するのだけちょっとトリッキーになってる。
profile が更新されたときって &lt;code&gt;Update-ProfileScripts&lt;/code&gt; の中も更新されてる可能性があるが、それは最新の profile を download するまでわからない。
追加されたばかりの野良モジュールは、最新の profile を読み込んだ後の &lt;code&gt;Update-ProfileScripts&lt;/code&gt; が実行されて初めて取得できる。
どうにも解決法がわからなかったので、ここは力技で &lt;code&gt;Update-ProfileScripts&lt;/code&gt; 前に一度 profile を読み込んでいる。&lt;/p&gt;
&lt;p&gt;最初に &lt;code&gt;Update-Profile&lt;/code&gt; を実行して profile を download する(①)
そして最新化された &lt;code&gt;Update-ProfileScripts&lt;/code&gt; を実行して最新の野良モジュールを download (②)したら、最後に再度 profile を読み込めば最新化が完了する(③)。&lt;/p&gt;
&lt;p&gt;とはいえなんかもっといい方法ないのかという気もする。
あと、今見たら &lt;code&gt;Update-ProfileScripts&lt;/code&gt; が &lt;code&gt;Update-Profile&lt;/code&gt; で定義した global 変数を参照して dynamic scope もどきの挙動してるから危ない気もするけど、一旦このままかな。&lt;/p&gt;
&lt;p&gt;この profile を細かく野良モジュールに分解するスタイルは最初小さくいくつかのモジュールから導入した。
いまではほぼ profile の更新機能以外は野良モジュールに分割した。
まだ使ってみて 1,2 週くらい？だが、モジュール分割さえ済んでしまえば GistPad から更新も容易だし不都合はなさそう。
(モジュール分割は GistPad でやるには面倒なので repository を clone してやることが多い)&lt;/p&gt;
&lt;p&gt;今は野良モジュールとして腐らせてるけど、今後いい感じのやつが育って熟成したら正規のモジュールとして publish してやるのもありか。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 26 May 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-05-19-writing-cmdlet-in-fsharp-pt40.html</guid><link>https://krymtkts.github.io/posts/2024-05-19-writing-cmdlet-in-fsharp-pt40.html</link><title>F# でコマンドレットを書いてる pt.40</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-05-05-writing-cmdlet-in-fsharp-pt38.html&quot; title=&quot;はじめメモリ浪費に気付いたとき&quot;&gt;はじめメモリ浪費に気付いたとき&lt;/a&gt;の使い方は pocof の起動までにめちゃくちゃ時間がかかる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;global&lt;/span&gt;:&lt;span class=&quot;hljs-title&quot;&gt;Show-ReadLineHistory&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-PSReadLineOption&lt;/span&gt;).HistorySavePath | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Unique&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Pocof&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-CaseSensitive&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Layout&lt;/span&gt; TopDown&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Alias&lt;/span&gt; pghy &lt;span class=&quot;hljs-built_in&quot;&gt;Show-ReadLineHistory&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Option&lt;/span&gt; ReadOnly &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; Global
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こういう使い方をしてるのだけど、 &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/select-object?view=powershell-7.4#example-4-select-unique-characters-from-an-array&quot; title=&quot;&lt;code&gt;Select-Object -Unique&lt;/code&gt;&quot;&gt;&lt;code&gt;Select-Object -Unique&lt;/code&gt;&lt;/a&gt; がめちゃくちゃ遅い。
どういう実装をしてるかまでおってないが、順不同の要素中の他の重複を取り除くから遅いっぽい。
ここを &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-unique?view=powershell-7.4&quot; title=&quot;&lt;code&gt;Get-Unique&lt;/code&gt;&quot;&gt;&lt;code&gt;Get-Unique&lt;/code&gt;&lt;/a&gt; にしたら爆発的に速くなるのだけど、まず &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/sort-object?view=powershell-7.4&quot; title=&quot;&lt;code&gt;Sort-Object&lt;/code&gt;&quot;&gt;&lt;code&gt;Sort-Object&lt;/code&gt;&lt;/a&gt; で並び替えておく必要があり、それは期待した動作じゃない。元の順そのままで重複だけなくしたい。&lt;/p&gt;
&lt;p&gt;そこまできたらもう面倒なので pocof に &lt;code&gt;-Unique&lt;/code&gt; オプションつけた方が楽やろなということで、そういう機能を実装した。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/181&quot; title=&quot;#181&quot;&gt;#181&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PowerShell で言うところのこういうコードにしたら、とても速く重複が取り除ける。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-PSReadLineOption&lt;/span&gt;).HistorySavePath | % &lt;span class=&quot;hljs-literal&quot;&gt;-begin&lt;/span&gt; {&lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt;=[&lt;span class=&quot;hljs-type&quot;&gt;ordered&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{}} &lt;span class=&quot;hljs-literal&quot;&gt;-process&lt;/span&gt; {&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt;.Contains(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;)) {} &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt;.Add(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt;)}} &lt;span class=&quot;hljs-literal&quot;&gt;-end&lt;/span&gt; {&lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt;.Keys}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;[ordered]&lt;/code&gt; は pocof のコードだと &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.specialized.ordereddictionary?view=net-8.0&quot; title=&quot;&lt;code&gt;System.Collections.Specialized.OrderedDictionary&lt;/code&gt;&quot;&gt;&lt;code&gt;System.Collections.Specialized.OrderedDictionary&lt;/code&gt;&lt;/a&gt; になる。
pocof の&lt;code&gt;InputObject&lt;/code&gt; の並び順を維持しつつとなるとこいつを使うのが定石だろう。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;System.Collections.Specialized.OrderedDictionary&lt;/code&gt; では key の等価性を判定するのに &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.object.equals?view=net-8.0&quot; title=&quot;&lt;code&gt;Equals&lt;/code&gt;&quot;&gt;&lt;code&gt;Equals&lt;/code&gt;&lt;/a&gt; と &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=net-8.0&quot; title=&quot;&lt;code&gt;GetHashCode&lt;/code&gt;&quot;&gt;&lt;code&gt;GetHashCode&lt;/code&gt;&lt;/a&gt; が使われる。
なので &lt;code&gt;PSCustomObject&lt;/code&gt; の場合だと重複が取り除けない。 &lt;code&gt;PSCustomObject&lt;/code&gt; は &lt;code&gt;Object.Equals&lt;/code&gt; の再定義とかしてないから参照等価性しかチェックしてないみたい。
ちょっと残念だが、でも PowerShell の環境では大体の object はそれらを実装してるし、いったん &lt;code&gt;PSCustomObject&lt;/code&gt; 用の特別な比較関数を書かないでやった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-Unique&lt;/code&gt; オプション対応してみてわかったのだけど、 &lt;code&gt;hashtable&lt;/code&gt; の key-value の組み合わせが一致するエントリも除外できるし、こりゃなかなか便利な機能な気がしている。ぱぱっと思いついて作った割には。&lt;/p&gt;
&lt;p&gt;pocof の設計思想的に、 pocof の呼び出し前後で他の Cmdlet でできることはあまり実装しないことにしてる。
それが PowerShell らしいかなと(勝手に)と考えて &lt;code&gt;-Unique&lt;/code&gt; オプションは考えてこなかった。
でも今回の件は学びになった。
既存の Cmdlet で出来たとしても、長々とパイプラインを書かないといけないとかで複雑になったり、パフォーマンスが振るわないようであれば、機能に取り込んでも良さそうやなという感覚。&lt;/p&gt;
&lt;p&gt;この &lt;code&gt;-Unique&lt;/code&gt; は早速 &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.13.0&quot; title=&quot;0.13.0&quot;&gt;0.13.0&lt;/a&gt; でリリースして、自分の &lt;a href=&quot;https://github.com/krymtkts/pwsh-profile/blob/main/Scripts/Pocof/Pocof.psm1&quot; title=&quot;PowerShell profile&quot;&gt;PowerShell profile&lt;/a&gt; で新しいオプション使うように直した。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 19 May 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-05-12-writing-cmdlet-in-fsharp-pt39.html</guid><link>https://krymtkts.github.io/posts/2024-05-12-writing-cmdlet-in-fsharp-pt39.html</link><title>F# でコマンドレットを書いてる pt.39</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-05-05-writing-cmdlet-in-fsharp-pt38.html&quot; title=&quot;前に&quot;&gt;前に&lt;/a&gt; メモリ浪費について触れ、それがどうも &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.psobject.properties?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;PSObject.Properties&lt;/code&gt;&quot;&gt;&lt;code&gt;PSObject.Properties&lt;/code&gt;&lt;/a&gt; によるものだと書いた。&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;ひとまず Discriminated Union で wrap するときしないときのメモリ消費量を計測するためのサンプル Cmdlet でも書いてみて検証するしかないかな。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;多少はメモリ食うがだいぶ的外れっぽい。
ヤバいのは &lt;code&gt;PSObject.properties&lt;/code&gt; にアクセスして補完候補を集めてるところみたい...うーん。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;これイマイチ挙動がわからないのだが、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.cmdlet.processrecord?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;ProcessRecord&lt;/code&gt;&quot;&gt;&lt;code&gt;ProcessRecord&lt;/code&gt;&lt;/a&gt; の中で &lt;code&gt;PSObject.Properties&lt;/code&gt; にアクセスしたとき条件が揃うと、症状が悪化するぽいとわかった。
浪費する量は Discriminated Unions に包むことで増えるメモリ量の比でない。まさに爆増。&lt;/p&gt;
&lt;p&gt;あまりにわからなかったので宣言通り検証用モジュールを作り、こねくった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/fsharp-cmdlet-sandbox/blob/main/src/wrap-dus-or-not/Library.fs&quot; title=&quot;fsharp-cmdlet-sandbox/src/wrap-dus-or-not/Library.fs at main · krymtkts/fsharp-cmdlet-sandbox&quot;&gt;fsharp-cmdlet-sandbox/src/wrap-dus-or-not/Library.fs at main · krymtkts/fsharp-cmdlet-sandbox&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/fsharp-cmdlet-sandbox/blob/main/test-wrap-dus-or-not.ps1&quot; title=&quot;fsharp-cmdlet-sandbox/test-wrap-dus-or-not.ps1 at main · krymtkts/fsharp-cmdlet-sandbox&quot;&gt;fsharp-cmdlet-sandbox/test-wrap-dus-or-not.ps1 at main · krymtkts/fsharp-cmdlet-sandbox&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;100 万個の &lt;code&gt;int&lt;/code&gt; を流し込むパターンと 100 万個の &lt;code&gt;PSCustomObject&lt;/code&gt; を流し込むパターンを作ってみた。
そのそれぞれで、生か DUs でくるんで追加、プロパティアクセスの有無などの組み合わせでパターン分けして検証してみた。なるべく pocof の利用パターンに近い形で。&lt;/p&gt;
&lt;p&gt;わかったのは、100 万回 &lt;code&gt;ProcessRecord&lt;/code&gt; が呼ばれても、その中でただ &lt;code&gt;PSObject.Properties&lt;/code&gt; &lt;strong&gt;だけ&lt;/strong&gt;アクセスするのであればメモリを浪費しない。
&lt;code&gt;ProcessRecord&lt;/code&gt; の中で、 &lt;code&gt;PSObject&lt;/code&gt; 本体をコレクション (今の pocof では &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.collections.generic.list-1?view=net-8.0&quot; title=&quot;&lt;code&gt;System.Collection.Generic.List&lt;/code&gt;&quot;&gt;&lt;code&gt;System.Collection.Generic.List&lt;/code&gt;&lt;/a&gt;) に格納し、かつ &lt;code&gt;PSObject.Properties&lt;/code&gt; にアクセスすると延々メモリを浪費するのがわかった。
「アクセスする」と書いてるのは、言葉通り &lt;code&gt;PSObject.Properties&lt;/code&gt; を参照するだけでメモリ消費につながるからだ。↓ これもダメ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; throughProps (io&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PSObject) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; io.BaseObject &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; p &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; io.Properties &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-comment&quot;&gt;// p.Name |&amp;gt; ignore&lt;/span&gt;&lt;br /&gt;                ()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;なんだこれ。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ProcessRecord&lt;/code&gt; の中で &lt;code&gt;PSObject&lt;/code&gt; 本体を保存しない選択肢はないので、ならば &lt;code&gt;PSObject.Properties&lt;/code&gt; に都度アクセスしなければ良いと仮定し、 &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.management.automation.psobject.baseobject?view=powershellsdk-1.1.0&quot; title=&quot;&lt;code&gt;PSObject.BaseObject&lt;/code&gt;&quot;&gt;&lt;code&gt;PSObject.BaseObject&lt;/code&gt;&lt;/a&gt; で読み込み済み or not を判定してプロパティを収集するように変えたら、メモリ浪費を抑えられる事がわかった。
なので pocof では一旦それに倣ってメモリを消費しない形を実現できた。
でも &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pscustomobject?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;PSCustomObject&lt;/code&gt;&quot;&gt;&lt;code&gt;PSCustomObject&lt;/code&gt;&lt;/a&gt; の場合は依然メモリを食いまくることがわかり、これはどうすりゃいんだとなった。
が、これは &lt;a href=&quot;https://github.com/PowerShell/ConsoleGuiTools/blob/main/docs/Microsoft.PowerShell.ConsoleGuiTools/Out-ConsoleGridView.md&quot; title=&quot;&lt;code&gt;Out-ConsoleGridView&lt;/code&gt;&quot;&gt;&lt;code&gt;Out-ConsoleGridView&lt;/code&gt;&lt;/a&gt; でも浪費するのがわかった(し pocof の方が多少メモリ消費も低い)ので一旦放置した。&lt;/p&gt;
&lt;p&gt;これで一旦 pocof のメモリ浪費対策はそこそこに対応できたかなと。
あと今書いてて &lt;code&gt;hashtable&lt;/code&gt; のパターン見忘れてるの気づいたので、やっておこう。&lt;/p&gt;
&lt;p&gt;ただし当然のごとく、この &lt;code&gt;PSObject.Properties&lt;/code&gt; の挙動は不可解なので PowerShell の実装を見てみた。
が、残念ながらよくわからなかった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PowerShell/blob/d564d0fff95b6251dfb9e79d8243b319a7c0aecf/src/System.Management.Automation/engine/MshObject.cs#L751-L768&quot; title=&quot;PowerShell/src/System.Management.Automation/engine/MshObject.cs at d564d0fff95b6251dfb9e79d8243b319a7c0aecf · PowerShell/PowerShell&quot;&gt;PowerShell/src/System.Management.Automation/engine/MshObject.cs at d564d0fff95b6251dfb9e79d8243b319a7c0aecf · PowerShell/PowerShell&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; Gets the Property collection, or the members that are actually properties.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; PSMemberInfoCollection&amp;lt;PSPropertyInfo&amp;gt; Properties&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;get&lt;/span&gt;&lt;br /&gt;            {&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (_properties == &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;)&lt;br /&gt;                {&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;lock&lt;/span&gt; (_lockObject)&lt;br /&gt;                    {&lt;br /&gt;                        _properties ??= &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; PSMemberInfoIntegratingCollection&amp;lt;PSPropertyInfo&amp;gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;, s_propertyCollection);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; _properties;&lt;br /&gt;            }&lt;br /&gt;        }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;一度プロパティが読み込まれたら生成したコレクションをキャッシュをするようになってた。
同一 &lt;code&gt;PSObject&lt;/code&gt; から連続で読む限りはキャッシュが保持されるが、 &lt;code&gt;ProcessRecord&lt;/code&gt; のなかで呼ばれるのはそれぞれ別の &lt;code&gt;PSObject&lt;/code&gt; なので、 pocof の利用ケースではそもそもキャッシュは使われない。
別の &lt;code&gt;PSObject&lt;/code&gt; であれば &lt;code&gt;lock&lt;/code&gt; も関係ないし。
&lt;code&gt;new PSMemberInfoIntegratingCollection&amp;lt;PSPropertyInfo&amp;gt;(this, s_propertyCollection)&lt;/code&gt; の部分がメモリ消費しまくってると考えれば、アクセスするだけでダメなのも頷ける。
逆に何故 &lt;code&gt;PSObject.Properties&lt;/code&gt; &lt;strong&gt;だけ&lt;/strong&gt;アクセスする方のメモリ消費が低くなるのか気になってきた。
キャッシュが使われているとしか思えんが、最適化で暗黙的な使いまわしが発生してんのか...？
この挙動を追い詰めるのに今回は時間を使いたくなかったので、そのまま放置。これは将来の宿題とする。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;ひとまず pocof の patch version up でこの修正を release しておくかー。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 12 May 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-05-05-writing-cmdlet-in-fsharp-pt38.html</guid><link>https://krymtkts.github.io/posts/2024-05-05-writing-cmdlet-in-fsharp-pt38.html</link><title>F# でコマンドレットを書いてる pt.38</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 0.12.0 をリリースした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-04-21-writing-cmdlet-in-fsharp-pt37.html&quot; title=&quot;前に触れてた&quot;&gt;前に触れてた&lt;/a&gt; Active patterns の適用、あと key mapping の名称と割当の変更などのリファクタリング。
それと CPU 使用率が高くなるバグへの対応だ。これは速く対処して出したかった(それでも面倒で間が空いたが)。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-04-07-writing-cmdlet-in-fsharp-pt36.html&quot; title=&quot;先日 &lt;code&gt;KeyAvailable&lt;/code&gt; になるまで &lt;code&gt;ReadKey&lt;/code&gt; しなくした&quot;&gt;先日 &lt;code&gt;KeyAvailable&lt;/code&gt; になるまで &lt;code&gt;ReadKey&lt;/code&gt; しなくした&lt;/a&gt;ことでイベントループが回りまくって CPU 上げてた。
実はこれ pocof の初期実装では CPU load 下げるための &lt;code&gt;Thread.Sleep&lt;/code&gt; が仕込まれており、要は考慮済みだった。
だけどその後紆余曲折で await 使ったりして &lt;code&gt;KeyAvailable&lt;/code&gt; がなくなり、その後また復活して～ってなってその部分だけ忘れ去られてたという形。情けない。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと最近気づいたお困りポイントが、 pocof に大量のデータを食わせたときの応答の遅さ &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/177&quot; title=&quot;#177&quot;&gt;#177&lt;/a&gt; とメモリ使用量が多すぎる &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/176&quot; title=&quot;#176&quot;&gt;#176&lt;/a&gt; 問題だ。
単純に &lt;code&gt;1..1000000 | pocof&lt;/code&gt; のようなコマンドを実行してみたら起動も遅いし、キータイプごとに秒かかるし、 2GB 超メモリを食う。
やばすぎ。
キャンセルして終了したあと &lt;code&gt;[GC]::Collect()&lt;/code&gt; でもしないと確保したメモリが解放されない始末(それも全部が解放されないという)。&lt;/p&gt;
&lt;p&gt;これに気づいたのは以下のような関数を書いてるとめちゃくちゃ遅いので、その理由を調べたときのことだった。
この関数自体は pocof の遅さに由来して遅いのではなく、単に &lt;code&gt;Select-Object -Unique&lt;/code&gt; が脅威の遅さだったためだが。 12,000 件程度しかなかったので大して pocof は遅くなかった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;global&lt;/span&gt;:&lt;span class=&quot;hljs-title&quot;&gt;Show-ReadLineHistory&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-PSReadLineOption&lt;/span&gt;).HistorySavePath | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Unique&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Pocof&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-CaseSensitive&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Layout&lt;/span&gt; TopDown&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Alias&lt;/span&gt; pghy &lt;span class=&quot;hljs-built_in&quot;&gt;Show-ReadLineHistory&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Option&lt;/span&gt; ReadOnly &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; Global
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;応答が遅いのは 2 種類ある。&lt;/p&gt;
&lt;p&gt;まずは、都度 O(N) かけて要素を絞り込んだり件数を算出したりしてたため、フィルタリングが遅い。
内部でデータを保持するのに &lt;code&gt;list&lt;/code&gt; を使ってたのもあり、ひとまず &lt;code&gt;seq&lt;/code&gt; に変更した。
&lt;code&gt;seq&lt;/code&gt; は要素が必要なタイミングまで遅延評価される。
今のところ件数の表示がある限り遅延評価を活かせず速くならないが、件数の表示をなくせば表示範囲の件数だけ取れたら処理を終われる構造になった。
そういうオプションにすればいいのかもしれないが、とはいえこれも全件走査が必要な場合に効果がない。
根本的に内部のデータ構造を変えないと速くならんのではーと見ている。
でも pocof は依存関係基本なしの縛りがあるので、自前で効率化する方法やデータ構造の見直しを色々手探りしてみるしかないか。&lt;/p&gt;
&lt;p&gt;もう 1 つは &lt;code&gt;EndProcessing&lt;/code&gt; で描画を開始するので、 PowerShell の Cmdlet の仕組み上データ量が多いと &lt;code&gt;ProcessRecord&lt;/code&gt; が終わるまでの時間も長くなり、初動が遅い。
アイデアベースではこれの解決案は考えついていて、単に &lt;code&gt;ProcessRecord&lt;/code&gt; 中に画面描画開始できる件数が溜まったら描画し始めたらいいかなと考えている。
ただその際にキー入力を受け付け始めれるのか？とか、単に実装力の問題でアイデアをモノに落とし込めてない。
なのでこれも小さなサンプル Cmdlet でも作って手探りする必要がある。&lt;/p&gt;
&lt;p&gt;最後にメモリ使用量が多い件。
まだ一番でかい原因を追いきれてないが、おそらく &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions&quot; title=&quot;Discriminated Unions&quot;&gt;Discriminated Unions&lt;/a&gt; を各要素を wrap するのに使ってるからかと推測している。
というのも、まず &lt;code&gt;ProcessRecord&lt;/code&gt; 毎に &lt;code&gt;list&lt;/code&gt; が生成されるような構造だったので、試しに mutable な List を使って &lt;code&gt;for&lt;/code&gt; で追加していく形に最適化してみた。
ところがそんなに爆発的には効果がなかった(ゆーても 2.3GB 超 RAM 消費する状態で 1.9 GB にはなったが)。
であれば Discriminated Unions が濃厚かなと考えるが、 pocof のままだとちょっと試すのも色々変えないといけないので億劫だ。
ひとまず Discriminated Union で wrap するときしないときのメモリ消費量を計測するためのサンプル Cmdlet でも書いてみて検証するしかないかな。&lt;/p&gt;
&lt;p&gt;ちなみにこれらの点いずれも、 &lt;a href=&quot;https://github.com/PowerShell/ConsoleGuiTools&quot; title=&quot;PowerShell/ConsoleGuiTools&quot;&gt;PowerShell/ConsoleGuiTools&lt;/a&gt; のフィルタは初期ロードが死ぬほど遅いのを除けば&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;、省メモリで高速にキビキビと動く。
なんか参考になる要素あるかもな。&lt;/p&gt;
&lt;p&gt;2 年超の間のらりくらり F# で PowerShell の Cmdlet 書いてきてるが、(体系的な学習してないのもあって)知らないことに毎度のようにぶち当たる。
知るべきことを知ってない怠惰なのかも知れんが、ここは広範な知識の海で新たな発見が尽きないのだと、ポジティブに考えていきましょ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;今日は気になっている課題を書いたが、他にも pocof でやりたいことがちらほら残っている。
&lt;code&gt;Ctrl+LeftArrow&lt;/code&gt;, &lt;code&gt;Ctrl+RightArrow&lt;/code&gt; あたりで単語区切りの移動 &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/173&quot; title=&quot;#173&quot;&gt;#173&lt;/a&gt; したい気分になってきた。
また、よく考えると選択範囲がある状態でのプロパティ補完時の挙動も未定義なままだった。
パフォ系の問題を処置する前にするか、処置したあとにするか...思いつき駆動なのでちょっと悩ましい。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 &gt;&lt;a name=&quot;-2024-05-05&quot; href=&quot;#-2024-05-05&quot;&gt;追記 2024-05-05&lt;/a&gt;&lt;/h4&gt;&lt;blockquote&gt;
&lt;p&gt;ひとまず Discriminated Union で wrap するときしないときのメモリ消費量を計測するためのサンプル Cmdlet でも書いてみて検証するしかないかな。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;多少はメモリ食うがだいぶ的外れっぽい。
ヤバいのは &lt;code&gt;PSObject.properties&lt;/code&gt; にアクセスして補完候補を集めてるところみたい...うーん。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;わたしのいまや貧弱になった Razer Blade Stealth 2017 だと &lt;code&gt;1..1000000 | Out-ConsoleGridView&lt;/code&gt; でもしようものなら起動までに 7 分かかる。 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 05 May 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-04-28-refactor-powershell-profile.html</guid><link>https://krymtkts.github.io/posts/2024-04-28-refactor-powershell-profile.html</link><title>PowerShell の profile を再構成する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;長らく&lt;a href=&quot;https://gist.github.com/krymtkts/f8af667c32b16fc28a815243b316c5be&quot; title=&quot;自作 PowerShell の profile&quot;&gt;自作 PowerShell の profile&lt;/a&gt; を使ってる。
長年継ぎ足ししてきた謂わば秘伝のタレのようなもので、全体はかなりごちゃついている。
これを整理して再構成する必要が出てきたので、今日はそれを記す。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;再構成が必要だと思ったのは、毎週行う PowerShell module はじめとした諸々のモジュールの更新のときだった。
PowerShell module の更新は以下の関数で行うのだけど、違和感わかってもらえるだろうか？&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Update-InstalledModules&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;SupportsShouldProcess&lt;/span&gt;)]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Get-InstalledPSResource&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; AllUsers | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Repository &lt;span class=&quot;hljs-operator&quot;&gt;-EQ&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Prerelease&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name &lt;span class=&quot;hljs-operator&quot;&gt;-notin&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$pinStable&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name | &lt;span class=&quot;hljs-built_in&quot;&gt;Update-PSResource&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Prerelease&lt;/span&gt;:&lt;span class=&quot;hljs-variable&quot;&gt;$Prerelease&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; AllUsers&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;更新後にたまたま PowerShell Gallery を見たら妙に &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の download 数が増えてたのでなんでや？と思って見てみたら、犯人はこいつだった。
&lt;code&gt;Installed-PSResource&lt;/code&gt; は module name x version の組み合わせを返すので、インストールされている pocof の数だけ download が増えるという...
このバグが入り込んだタイミングは PowerShellGet -&amp;gt; Microsoft.PowerShell.PSResourceGet に変わったタイミングだろう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;global&lt;/span&gt;:&lt;span class=&quot;hljs-title&quot;&gt;Update-InstalledModules&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;SupportsShouldProcess&lt;/span&gt;)]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Uninstall-OutdatedPSResources&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Get-InstalledPSResource&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; AllUsers | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Repository &lt;span class=&quot;hljs-operator&quot;&gt;-EQ&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Group-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Prerelease&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name &lt;span class=&quot;hljs-operator&quot;&gt;-notin&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$global:pinStable&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Update &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name) &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(if (&lt;span class=&quot;hljs-variable&quot;&gt;$Prerelease&lt;/span&gt;) {&amp;#x27;Prerelease&amp;#x27;} else {&amp;#x27;&amp;#x27;})&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;# NOTE: -WhatIf is not work with Update-PSResource in some cases.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Update-PSResource&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name &lt;span class=&quot;hljs-literal&quot;&gt;-Prerelease&lt;/span&gt;:&lt;span class=&quot;hljs-variable&quot;&gt;$Prerelease&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; AllUsers&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;なのでこんな感じで &lt;code&gt;Group-Object&lt;/code&gt; で複数バージョンあっても折りたたむ形にした。&lt;/p&gt;
&lt;p&gt;余談だが、 &lt;code&gt;Update-PSResource&lt;/code&gt; を &lt;code&gt;WhatIf&lt;/code&gt; で動作確認してたら妙なエラーになってよくわからなかった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;&amp;gt; Update-PSResource pocof -Prerelease -WhatIf -Scope AllUsers&lt;br /&gt;What if: Performing the operation &amp;quot;Update-PSResource&amp;quot; on target &amp;quot;Package to install: &amp;#x27;pocof&amp;#x27;, version: &amp;#x27;0.11.0&amp;#x27;&amp;quot;.&lt;br /&gt;What if: Performing the operation &amp;quot;Update-PSResource&amp;quot; on target &amp;quot;Exit ShouldProcess&amp;quot;.&lt;br /&gt;&lt;br /&gt;Exception             :&lt;br /&gt;    Type    : Microsoft.PowerShell.PSResourceGet.UtilClasses.ResourceNotFoundException&lt;br /&gt;    Message : Package(s) &amp;#x27;pocof&amp;#x27; could not be installed from repository &amp;#x27;PSGallery&amp;#x27;.&lt;br /&gt;    HResult : -2146233088&lt;br /&gt;TargetObject          : Microsoft.PowerShell.PSResourceGet.Cmdlets.UpdatePSResource&lt;br /&gt;CategoryInfo          : InvalidData: (Microsoft.PowerShel…ts.UpdatePSResource:UpdatePSResource) [Update-PSResource], ResourceNotFoundException&lt;br /&gt;FullyQualifiedErrorId : InstallPackageFailure,Microsoft.PowerShell.PSResourceGet.Cmdlets.UpdatePSResource&lt;br /&gt;InvocationInfo        :&lt;br /&gt;    MyCommand        : Update-PSResource&lt;br /&gt;    ScriptLineNumber : 1&lt;br /&gt;    OffsetInLine     : 1&lt;br /&gt;    HistoryId        : 13&lt;br /&gt;    Line             : Update-PSResource pocof -Prerelease -WhatIf -Scope AllUsers&lt;br /&gt;    Statement        : Update-PSResource pocof -Prerelease -WhatIf -Scope AllUsers&lt;br /&gt;    PositionMessage  : At line:1 char:1&lt;br /&gt;                       + Update-PSResource pocof -Prerelease -WhatIf -Scope AllUsers&lt;br /&gt;                       + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;    InvocationName   : Update-PSResource&lt;br /&gt;    CommandOrigin    : Internal&lt;br /&gt;ScriptStackTrace      : at &amp;lt;ScriptBlock&amp;gt;, &amp;lt;No file&amp;gt;: line 1&lt;br /&gt;PipelineIterationInfo :&lt;br /&gt;      0&lt;br /&gt;      1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSResourceGet/issues/1541&quot; title=&quot;&lt;code&gt;-WhatIf&lt;/code&gt; results in extra, unwanted output and a spurious error · Issue #1541 · PowerShell/PSResourceGet&quot;&gt;&lt;code&gt;-WhatIf&lt;/code&gt; results in extra, unwanted output and a spurious error · Issue #1541 · PowerShell/PSResourceGet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cmdlet は違うがこれと同じっぽい。
アップデートできるモジュールがある場合に起こる。
パッと見の挙動は &lt;code&gt;-WhatIf&lt;/code&gt; 付きのときにインストール済み module 名を消せてないから「インストールできなかった」エラー判定されるようだった。焦らすなや～。
コード追ってみたがエラー発生箇所はわかったけどどうやったら解決するのかは追いきれなかった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSResourceGet/blob/bb4c0d0402a43cb561b33c681024ec6312a8474d/src/code/InstallHelper.cs#L333-L341&quot; title=&quot;PSResourceGet/src/code/InstallHelper.cs at bb4c0d0402a43cb561b33c681024ec6312a8474d · PowerShell/PSResourceGet&quot;&gt;PSResourceGet/src/code/InstallHelper.cs at bb4c0d0402a43cb561b33c681024ec6312a8474d · PowerShell/PSResourceGet&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと Gist でずっと管理してたやつを GitHub repo に移した。 &lt;a href=&quot;https://github.com/krymtkts/pwsh-profile&quot; title=&quot;krymtkts/pwsh-profile&quot;&gt;krymtkts/pwsh-profile&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Gist で最新版を管理するのが手軽であるのと、 snippet に対して直にコメントもらったりのコミュニケーションを取りやすいのが利点だと認識している。
ただわたしの PowerShell profile の場合そういう化学反応起こらないので、履歴管理の面倒さからも Gist をやめたくなった次第。
どうせ履歴の更新に関しては従来通り GistPad を使ってコピペしていくだけなので、何も変わらない。
移行は以下の手順で行った。びみょーに実際の手順と違って間違いあるかもしれんが大体こんな感じなはず。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# new repo.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;New-GitHubRepository&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-RepositoryName&lt;/span&gt; pwsh&lt;span class=&quot;hljs-literal&quot;&gt;-profile&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Private&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# mistake.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$r&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-GitHubRepository&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-OwnerName&lt;/span&gt; krymtkts &lt;span class=&quot;hljs-literal&quot;&gt;-RepositoryName&lt;/span&gt; pwsh&lt;span class=&quot;hljs-literal&quot;&gt;-profile&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# clone gist.&lt;/span&gt;&lt;br /&gt;ghq get https://gist.github.com/krymtkts/f8af667c32b16fc28a815243b316c5be&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# move to gist repo.&lt;/span&gt;&lt;br /&gt;gcd&lt;br /&gt;git remote add github &lt;span class=&quot;hljs-variable&quot;&gt;$r&lt;/span&gt;.ssh_url&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# change master to main.&lt;/span&gt;&lt;br /&gt;git &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--create&lt;/span&gt; main&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# push to the GitHub repo.&lt;/span&gt;&lt;br /&gt;git push &lt;span class=&quot;hljs-literal&quot;&gt;-u&lt;/span&gt; github main&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$remove&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;pwd&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# clone new repo.&lt;/span&gt;&lt;br /&gt;ghq get &lt;span class=&quot;hljs-literal&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$r&lt;/span&gt;.ssh_url&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# move to new repo.&lt;/span&gt;&lt;br /&gt;gcd&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# publish repo.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set-GitHubRepository&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-OwnerName&lt;/span&gt; krymtkts &lt;span class=&quot;hljs-literal&quot;&gt;-RepositoryName&lt;/span&gt; pwsh&lt;span class=&quot;hljs-literal&quot;&gt;-profile&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Private&lt;/span&gt;:&lt;span class=&quot;hljs-variable&quot;&gt;$false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# remove gist repo.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$remove&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Remove-GitHubGist&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Gist&lt;/span&gt; f8af667c32b16fc28a815243b316c5be &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;はじめ &lt;code&gt;Remove-GitHubGist&lt;/code&gt; が 404 Not Found で返ってきて何ぞ？と思ったが、 Access Token の権限足りないようだった。 403 とかじゃないんだ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;バグ修正の他に初期化の処理をカテゴリ毎に関数を分類してみたりしたが、これどこまでやるべきなんやろかというのは悩ましいところだ。
profile の処理を分類したかったら結局ファイルを分けることになって、ファイルを分けると profile のディレクトリ全体を履歴管理するのが定石。
でもそのような profile 全体を git の管理下に置くのは個人的には好きでないので、どうしたもんかな。&lt;/p&gt;
&lt;p&gt;つづく。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 28 Apr 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-04-21-writing-cmdlet-in-fsharp-pt37.html</guid><link>https://krymtkts.github.io/posts/2024-04-21-writing-cmdlet-in-fsharp-pt37.html</link><title>F# でコマンドレットを書いてる pt.37</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; ではあまり &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/active-patterns&quot; title=&quot;Active Patterns&quot;&gt;Active Patterns&lt;/a&gt; を使ってなかった。
特に理由があって避けてたわけじゃなく、わたしの F# 力が低いのもあるけどなんか大げさな感じがして使ってなかった。&lt;/p&gt;
&lt;p&gt;でもこの辺を読んでもっと気軽に使っても良さそうやな～という気になってきた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jindraivanek.hashnode.dev/f-tips-weekly-10-active-patterns-1&quot; title=&quot;F# tips weekly #10: Active patterns (1)&quot;&gt;F# tips weekly #10: Active patterns (1)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://jindraivanek.hashnode.dev/f-tips-weekly-11-active-patterns-2&quot; title=&quot;F# tips weekly #11: Active patterns (2)&quot;&gt;F# tips weekly #11: Active patterns (2)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;そこで可読性高めるのと汎用化を期待して使いはじめてみた。
Partial Active Patterns やら Complete Active Patterns やらあるけど、気に入ってるのは Single-case Active Pattern だ。
値を変換するパターンがこれに相当する。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/blob/8aefcad38295b5fa6e37d879b8b79b346a91d46e/src/pocof/Data.fs#L57-L58&quot; title=&quot;こんな感じ&quot;&gt;こんな感じ&lt;/a&gt;でタプルを照準に並び替えて返すものを作ってみたが、良さそう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;Ascending&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;) (x, y) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; x &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt; y &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; (x, y) &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; (y, x)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;pocof は範囲選択の実装の都合上、数値を並び替える場面がいくつかあった。
あるいは 2 つの数値のうち小さい方、大きい方を取るとか。
そういったケースにこれがバッチリハマる。&lt;/p&gt;
&lt;p&gt;並び替えるだけならこう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x, y &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; Ascending xy &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; xy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;大小どちらかを取る場合、例えば小さい方はこう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x, y &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; Ascending (x, _) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; x
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;既に 2 値のタプルがあるなら、こうするのがシンプルか。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    xy &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; Ascending xy &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; xy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この状態だと単に関数呼び出しでしかないけど、他のパターンと組み合わせていい塩梅にできる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; xy &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;-1&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; xy &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; x, y &lt;span class=&quot;hljs-keyword&quot;&gt;when&lt;/span&gt; x &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;||&lt;/span&gt; y &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Ascending xy &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;(xy)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;いいやん。
ボトムアッププログラミングが捗るな(ゆーても既にモノ出来てるからボトムアップしようがないけど)。&lt;/p&gt;
&lt;p&gt;あとは多少複雑なコードの人まとまりに意図を示すのにも向いてる。&lt;a href=&quot;https://github.com/krymtkts/pocof/blob/b7bbde9c273850d9a06fedfb72e9d8f34ca30106/src/pocof/Data.fs#L86-L90&quot; title=&quot;こことか&quot;&gt;こことか&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;Found&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;_&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;) aType excludes name &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        FSharpType.GetUnionCases aType&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Seq.filter (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; u &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; Set.contains u.Name excludes &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;not&lt;/span&gt;)&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Seq.tryFind (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; u &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; u.Name &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; String.lower &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; name)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; fromString&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; s &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; name &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; String.lower s&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; aType &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; name &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Found aType (&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; []) u &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; FSharpValue.MakeUnion(u, [&lt;span class=&quot;hljs-operator&quot;&gt;||&lt;/span&gt;]) &lt;span class=&quot;hljs-operator&quot;&gt;:?&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;failwithf&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;Unknown %s&lt;span class=&quot;hljs-subst&quot;&gt;{aType.Name}&lt;/span&gt; &amp;#x27;%s&lt;span class=&quot;hljs-subst&quot;&gt;{s}&lt;/span&gt;&amp;#x27;.&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Discriminated Union を文字列から作るとき(pocof のパラメータ変換で使う)にハマる。
元は &lt;code&gt;match ~ with&lt;/code&gt; のところに &lt;code&gt;Found&lt;/code&gt; active pattern 相当のコードを置いてたので、なおさら読みやすくなってる。
関数でもいいのだけど、 Match expression と組み合わせることでより文脈読みやすくなると、個人的に感じた。&lt;/p&gt;
&lt;p&gt;まだ引数のパターンを示すのに使うような尖った？使い方は出来てないが、徐々になじませていくか。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 21 Apr 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-04-14-how-to-check-coverage-for-inline-functions.html</guid><link>https://krymtkts.github.io/posts/2024-04-14-how-to-check-coverage-for-inline-functions.html</link><title>F# の Inline Functions のカバレッジを計測する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;最近あんま週末時間取れず開発できてないので小ネタ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dotnet/fsharp/issues/3579&quot; title=&quot;CI test coverage of F# unit tests · Issue #3579 · dotnet/fsharp&quot;&gt;CI test coverage of F# unit tests · Issue #3579 · dotnet/fsharp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この中で触れられてるのだけど、 F# の &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/inline-functions&quot; title=&quot;Inline Functions&quot;&gt;Inline Functions&lt;/a&gt; は code coverage を計測できない。
コンパイル時点で使われてる箇所に inline 展開され、展開前の情報を捨て去るので追えないみたい。
&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発でも Inline を使ってる箇所があって、そこは長らく code coverage 取れないので網羅率がちょっと低くなるという状態だった。&lt;/p&gt;
&lt;p&gt;ただ計測のためのちょっとした hack はある。
&lt;a href=&quot;https://github.com/dotnet/fsharp/issues/3579#issuecomment-329348683&quot; title=&quot;ここ&quot;&gt;ここ&lt;/a&gt;で触れられてる &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives#conditional-compilation&quot; title=&quot;&lt;code&gt;#if&lt;/code&gt; ディレクティブ&quot;&gt;&lt;code&gt;#if&lt;/code&gt; ディレクティブ&lt;/a&gt; を使って Debug モードのビルドのときだけ &lt;code&gt;inline&lt;/code&gt; を外す方法だ。
静的にジェネリック型が解決されるようなパターンだと使えないようだが、 pocof では使えた。
&lt;a href=&quot;https://github.com/krymtkts/pocof/blob/350cb39288f384d3123dd7f16275bb75bde276c9/src/pocof/Query.fs#L63-L74&quot; title=&quot;こんな感じ&quot;&gt;こんな感じ&lt;/a&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#if&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;!&lt;/span&gt;DEBUG&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;inline&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#endif&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;?-&amp;gt;&lt;/span&gt;)&lt;br /&gt;            (x&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PSObject)&lt;br /&gt;            (prop&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;)&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt; (x.Properties.Item prop).Value&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ただやっぱコード見た目意味わかんなくなるし Fantomas もフォーマットに困るみたい(ガタガタ)なので、あんま良くないなと。仕方なくやってる。&lt;/p&gt;
&lt;p&gt;F# は coverlet とあまり相性いい感じしない。個人的には以下が相性良くないと感じてる点だ。他にもあるんかな。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;match expression は可読性高くてあまり複雑にならないのだけど、コンパイル後の中間言語の循環的複雑度が高い&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/strings#string-indexing-and-slicing&quot; title=&quot;&lt;code&gt;string&lt;/code&gt; の slicing&quot;&gt;&lt;code&gt;string&lt;/code&gt; の slicing&lt;/a&gt; を使うと循環的複雑度が上がる&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/coverlet-coverage/coverlet/issues/1208&quot; title=&quot;Multiple branch points created for F# string slice · Issue #1208 · coverlet-coverage/coverlet&quot;&gt;Multiple branch points created for F# string slice · Issue #1208 · coverlet-coverage/coverlet&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;先述の Inline functions&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;ここまで来ると F# では code coverage や複雑度などのメトリクスはあまり意識しない方がいいのか？と思えてくる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fsprojects/FSharpLint&quot; title=&quot;FSharplint&quot;&gt;FSharplint&lt;/a&gt; の issue でも「みんな使ってないし手続き型ほど重要じゃない」という意見で、過去に循環的複雑度の計測をなくしたことがあるみたいだし(復活したようだが)。
&lt;a href=&quot;https://github.com/fsprojects/FSharpLint/issues/195&quot; title=&quot;cyclomatic complexity removed? · Issue #195 · fsprojects/FSharpLint&quot;&gt;cyclomatic complexity removed? · Issue #195 · fsprojects/FSharpLint&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;code coverage も、テスト書くならどのコードがテストされたかを計測したいのは当然だと思ったが...&lt;/p&gt;
&lt;p&gt;pocof の場合で考えたら、毎日連続的に開発してるわけじゃないし、品質を維持できる指標があると、すっぱり忘れてしまってても安心して取り組めるのであった方が良い。&lt;/p&gt;
&lt;p&gt;興味は尽きませんな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 14 Apr 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-04-07-writing-cmdlet-in-fsharp-pt36.html</guid><link>https://krymtkts.github.io/posts/2024-04-07-writing-cmdlet-in-fsharp-pt36.html</link><title>F# でコマンドレットを書いてる pt.36</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;最近の &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をまとめる。&lt;/p&gt;
&lt;p&gt;主だったものでいうと、&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/44&quot; title=&quot;クエリ文字列選択&quot;&gt;クエリ文字列選択&lt;/a&gt;のプロトタイプを実装した。
それと Windows Terminal で &lt;code&gt;Ctrl+S&lt;/code&gt; して出力を停止しているときに type すると pocof がエラーで落ちる様になってたので、その修正をした。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/160&quot; title=&quot;#160&quot;&gt;#160&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これらとカバレッジの改善などを含む 0.11.0 をリリースした。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;クエリ文字列選択は、以下の新しいショートカットで実装している。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Ctrl+A&lt;/code&gt; 全選択&lt;/li&gt;&lt;li&gt;&lt;code&gt;Shift+Home&lt;/code&gt; カーソル以前全ての文字列を選択&lt;/li&gt;&lt;li&gt;&lt;code&gt;Shift+End&lt;/code&gt; カーソル以降全ての文字列を選択&lt;/li&gt;&lt;li&gt;&lt;code&gt;Shift+LeftArrow&lt;/code&gt; カーソル前方の 1 文字を選択&lt;/li&gt;&lt;li&gt;&lt;code&gt;Shift+RightArrow&lt;/code&gt; カーソル後方の 1 文字を選択&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;あと削除系の操作に選択範囲がある場合の振る舞いを追加した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Backspace&lt;/code&gt; 選択範囲を削除&lt;/li&gt;&lt;li&gt;&lt;code&gt;Delete&lt;/code&gt; 選択範囲を削除&lt;/li&gt;&lt;li&gt;&lt;code&gt;Alt+K&lt;/code&gt; 選択範囲とカーソル以前全ての文字列を削除&lt;/li&gt;&lt;li&gt;&lt;code&gt;Alt+U&lt;/code&gt; 選択範囲とカーソル以降全ての文字列を削除&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;選択範囲がある場合のカーソル前後すべてを消すやつは、 &lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; でも見ない挙動だろうからちょっと変わり種だ。
(PSReadLine の &lt;code&gt;BackwardDeleteInput&lt;/code&gt; &lt;code&gt;ForwardDeleteInput&lt;/code&gt; は選択範囲を消さない)
ただ自分の感覚だと削除系の挙動が統一されてないと感じるので、選択範囲を消すような実装とした。
(余談だがショートカット割当を雑に決めてしまってるので、そこもそのうちデフォ設定を変えたい)&lt;/p&gt;
&lt;p&gt;あとプロトタイプと書いてるのは、選択モードでもプロパティ補完候補の振る舞いを決めてないからだ。
いまのところ通常のカーソル位置にあるプロパティ補完候補の表示が働いている。&lt;/p&gt;
&lt;p&gt;選択範囲があるときに Tab 補完したら、選択範囲を消して補完候補を出したらそれなりに便利な気がするが...そうしたら補完候補は常に表示しておきたいか。
逆に選択中で補完候補を出したくないときってどんなとき？まだちょっと利用想定を詰めるのが甘いか。もうちょっと煮詰まったら実装したい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/160&quot; title=&quot;#160&quot;&gt;#160&lt;/a&gt; のバグ修正は、 Windows Terminal で &lt;code&gt;Ctrl+S&lt;/code&gt; したあとで何か type したときに発生してたエラーを防ぐものだ。
この年まで知らなかったのだけど、昔は標準出力の印字を紙にしてたから、それを一時停止するための &lt;code&gt;Ctrl+S&lt;/code&gt; と再開するための &lt;code&gt;Ctrl+Q&lt;/code&gt; があったそうだ。
そのため伝統的に terminal emulator でも同機能を実装しており、しかも割と現代でもそれを使う人もいるということだった。
(なんか &lt;code&gt;tail -f&lt;/code&gt; で流しているようなとき気になる箇所で止めたりする使い方らしい)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://unix.stackexchange.com/questions/137842/what-is-the-point-of-ctrl-s&quot; title=&quot;terminal - What is the point of Ctrl-S? - Unix &amp;amp; Linux Stack Exchange&quot;&gt;terminal - What is the point of Ctrl-S? - Unix &amp;amp; Linux Stack Exchange&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://retrocomputing.stackexchange.com/questions/7263/history-of-ctrl-s-and-ctrl-q-for-flow-control&quot; title=&quot;terminal - History of Ctrl-S and Ctrl-Q for flow control - Retrocomputing Stack Exchange&quot;&gt;terminal - History of Ctrl-S and Ctrl-Q for flow control - Retrocomputing Stack Exchange&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Windows Terminal でもその実装があるみたいで、 &lt;code&gt;Ctrl+S&lt;/code&gt; で出力停止、何らかのキー押下で再開するらしい。
この振る舞いに詳しく触れている文書を見つけられなくて、以下で触れられてるのくらいしかなかった。
Windows Terminal の repo に PR があるからどっかで触れられてていいと思うが。
&lt;a href=&quot;https://github.com/microsoft/terminal/issues/809&quot; title=&quot;Re-investigate Ctrl+S pausing · Issue #809 · microsoft/terminal&quot;&gt;Re-investigate Ctrl+S pausing · Issue #809 · microsoft/terminal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;何にせよ &lt;code&gt;Ctrl+S&lt;/code&gt; 押下したあと &lt;code&gt;Console.ReadKey&lt;/code&gt; が呼ばれると &lt;code&gt;InvalidOperationException&lt;/code&gt; が発生する。ドキュメントにも書いてある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.console.readkey?view=net-8.0&quot; title=&quot;Console.ReadKey Method (System) | Microsoft Learn&quot;&gt;Console.ReadKey Method (System) | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;InvalidOperationException
The In property is redirected from some stream other than the console.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;これどうやったら防げるんや？と調べてたら、単純に pocof の実装がバグってるだけだったんがわかった ↓ &lt;a href=&quot;https://github.com/krymtkts/pocof/commit/60843b9dc7f44ee68cc845c235be8b321b1ca35e&quot; title=&quot;Fix Screen.read function to prevent an unhandled error when output is… · krymtkts/pocof@60843b9&quot;&gt;Fix Screen.read function to prevent an unhandled error when output is… · krymtkts/pocof@60843b9&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;        [&amp;lt;TailCall&amp;gt;]&lt;br /&gt;         let rec read (acc: ConsoleKeyInfo list) =&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            let acc = rui.ReadKey true :: acc&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            match rui.KeyAvailable() with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            | true -&amp;gt; read acc&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            | _ -&amp;gt; List.rev acc&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            rui.KeyAvailable()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            |&amp;gt; function&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                | true -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    let acc = rui.ReadKey true :: acc&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    read acc&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                | _ -&amp;gt; List.rev acc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;rui.ReadKey&lt;/code&gt; は &lt;code&gt;Console.ReadKey&lt;/code&gt; 、 &lt;code&gt;rui.KeyAvailable()&lt;/code&gt; は内部で &lt;code&gt;Console.KeyAvailable&lt;/code&gt; を呼んでる。
元のコードだと、初回は必ず &lt;code&gt;Console.KeyAvailable&lt;/code&gt; を見ずに &lt;code&gt;Console.ReadKey&lt;/code&gt; を呼んでしまうので、そこでエラーになってた。
修正したコードでは必ず &lt;code&gt;Console.KeyAvailable&lt;/code&gt; のチェックのあとで呼ばれるので、エラーにならない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Console.KeyAvailable&lt;/code&gt; を改めてみてみたら、ちゃんと標準入力でキーが有効かチェックしてて、そらそうやなという感じ...ただの実装ミスやったと。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.console.keyavailable?view=net-8.0&quot; title=&quot;Console.KeyAvailable Property (System) | Microsoft Learn&quot;&gt;Console.KeyAvailable Property (System) | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Gets a value indicating whether a key press is available in the input stream.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;しょぼバグを直せて良かった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;次にやるのは、ひとまず選択中のプロパティ補完の振る舞いを詰める。
その次は起票済みの機能よりも、 PSReadLine の Word 単位の移動や削除を模してみるか。
自分で起票したけど行選択やページ移動はあまり気乗りしない。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 07 Apr 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-03-31-control-auto-dark-mode-bulma-v1.html</guid><link>https://krymtkts.github.io/posts/2024-03-31-control-auto-dark-mode-bulma-v1.html</link><title>Bulma 1.0.0 の automatic Dark mode を制御する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今回も引き続き Bulma 1.0.0 ネタだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-03-24-migrate-bulma-to-v1.html&quot; title=&quot;前回 Bulma 1.0.0 に合わせてスタイル調整した&quot;&gt;前回 Bulma 1.0.0 に合わせてスタイル調整した&lt;/a&gt;話を書いた。
加えて Bulma 1.0.0 で &lt;a href=&quot;https://bulma.io/documentation/features/dark-mode/&quot; title=&quot;automatic Dark mode&quot;&gt;automatic Dark mode&lt;/a&gt; が導入されたのにも触れたが、これをうまく制御するのに多少のコツが必要だっので記しておく。&lt;/p&gt;
&lt;p&gt;ドキュメントにも記載あるが、 Bulma の automatic Dark mode は &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme&quot; title=&quot;&lt;code&gt;prefers-color-scheme&lt;/code&gt;&quot;&gt;&lt;code&gt;prefers-color-scheme&lt;/code&gt;&lt;/a&gt; の media query を使ってる。これが automatic Dark mode の automatic の正体だ。
手動で light/dark mode を使い分けるには &lt;code&gt;data-theme&lt;/code&gt; を指定する。この &lt;code&gt;data-theme=&amp;quot;light&lt;/code&gt; &lt;code&gt;data-theme=&amp;quot;dark&amp;quot;&lt;/code&gt; 属性を HTML に差し込んだり、 ユーザごとに設定を保存するのは、 JavaScript を書かないといけない。&lt;/p&gt;
&lt;p&gt;そういう仕組みなので light/dark mode に関する style は以下のようにするのが多分 Bulma の推奨パターンのはず。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/aa668a3e991a46e9b3b3d0302bdbc717d146665e/sass/style.scss&quot; title=&quot;blog-fable/sass/style.scss at aa668a3e991a46e9b3b3d0302bdbc717d146665e · krymtkts/blog-fable&quot;&gt;blog-fable/sass/style.scss at aa668a3e991a46e9b3b3d0302bdbc717d146665e · krymtkts/blog-fable&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-scss&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@media&lt;/span&gt; (&lt;span class=&quot;hljs-attribute&quot;&gt;prefers-color-scheme&lt;/span&gt;: light) {&lt;br /&gt;  &lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:root&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;@include&lt;/span&gt; light-theme();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-selector-attr&quot;&gt;[data-theme=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dark&amp;quot;&lt;/span&gt;]&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;@include&lt;/span&gt; dark-theme();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@media&lt;/span&gt; (&lt;span class=&quot;hljs-attribute&quot;&gt;prefers-color-scheme&lt;/span&gt;: dark) {&lt;br /&gt;  &lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:root&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;@include&lt;/span&gt; dark-theme();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-selector-attr&quot;&gt;[data-theme=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;light&amp;quot;&lt;/span&gt;]&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;@include&lt;/span&gt; light-theme();&lt;br /&gt;  }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このように &lt;code&gt;prefers-color-scheme&lt;/code&gt; の内側に逆の色の &lt;code&gt;[data-theme=&amp;quot;*&amp;quot;]&lt;/code&gt; を仕込むことで、システムのテーマ設定に関わらず指定のカラーテーマにできる。
システムにテーマを表明されないときは &lt;code&gt;prefers-color-scheme&lt;/code&gt; が &lt;code&gt;light&lt;/code&gt; になるらしい。
確認したことはないが、古い OS でカラーテーマが取れないときとか？ &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme&quot; title=&quot;prefers-color-scheme - CSS: Cascading Style Sheets | MDN&quot;&gt;prefers-color-scheme - CSS: Cascading Style Sheets | MDN&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ただ、この仕組みにしていると多少問題がある。
&lt;code&gt;prefers-color-scheme&lt;/code&gt; が取れるタイミングと &lt;code&gt;[data-theme=&amp;quot;*&amp;quot;]&lt;/code&gt; が取れるタイミングに差がある実装だと、ページ遷移時にスタイルの切り替わりで画面がちらつく。
「&lt;code&gt;prefers-color-scheme&lt;/code&gt; のカラースキーマ反映 -&amp;gt; JavaScript で &lt;code&gt;data-theme&lt;/code&gt; 設定される -&amp;gt; &lt;code&gt;data-theme&lt;/code&gt; のカラースキーマ反映」となるとダメ。
このチラつきは &lt;a href=&quot;https://bulma.io/&quot; title=&quot;Bulma の official page&quot;&gt;Bulma の official page&lt;/a&gt; でも起こってる。&lt;/p&gt;
&lt;p&gt;これを解消するには、HTML 文書で JavaScript → CSS の読み込み順になるよう調整し、かつ JavaScript 読み込み時にユーザ設定値を復元して &lt;code&gt;data-theme&lt;/code&gt; に設定する。
ただし注意点としては、 &lt;code&gt;data-theme&lt;/code&gt; の設定は JavaScript 読み込み時にやりたくても、テーマ切り替えのボタンに event を binding するのは後回しの方が良さそう。
blog-fable ではあまりに早過ぎて event を bind したい要素が準備されてなかったようで bind できなかったので、 &lt;code&gt;load&lt;/code&gt; event で binding するようにした。&lt;/p&gt;
&lt;p&gt;以下 blog-fable の例。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/cc19e2bdbe6b4fb7d802ca8772a53d17cd11156b/src/Handler.fs&quot; title=&quot;blog-fable/src/Handler.fs&quot;&gt;blog-fable/src/Handler.fs&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Handler&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Browser.Dom&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Browser.WebStorage&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Don&amp;#x27;t use Fable library in this file because it is directly bundled int HTML files.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//       This includes, discriminated union, List, etc.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; themeKey &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;theme-mode&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; themeAttributeName &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;data-theme&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; setThemeMode (t&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; t &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;light&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dark&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;        localStorage.setItem (themeKey, t)&lt;br /&gt;        document.documentElement.setAttribute (themeAttributeName, t)&lt;br /&gt;    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;        localStorage.removeItem themeKey&lt;br /&gt;        document.documentElement.removeAttribute themeAttributeName&lt;br /&gt;&lt;br /&gt;localStorage.getItem &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;theme-mode&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; setThemeMode&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; init _ &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; els &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; document.querySelectorAll (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.theme-toggle&amp;quot;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;to&lt;/span&gt; els.length &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; el &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; els.item (i)&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; themeMode &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; el.getAttribute &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;data-theme&amp;quot;&lt;/span&gt;&lt;br /&gt;        el.addEventListener (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;, (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; setThemeMode themeMode))&lt;br /&gt;&lt;br /&gt;window.addEventListener (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;load&amp;quot;&lt;/span&gt;, init)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;blog-fable は F# からトランスパイルした JavaScript を成果物にコピっているだけなので、 Fable のライブラリのインポートを必要とするコードは書けないという縛りがある。
なので discriminated union や &lt;code&gt;List.*&lt;/code&gt; といったものも使わない質素な実装になっている。
ここまでやったら、 blog-fable のページ遷移に限ってかも知れないがチラつきは一切起こらなくなり、マニュアルでのテーマ切り替えも動作するようになった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;他にもちまちまとスタイルの補正をしている箇所はあるが、これにて大体 Bulma 1.0.0 対応ができたもといえそう。
前より自作スタイルの CSS のサイズが 2 倍超デカくなってるのは気になるが、これも少しずつ改善重ねていけれたらよいか。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 31 Mar 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-03-24-migrate-bulma-to-v1.html</guid><link>https://krymtkts.github.io/posts/2024-03-24-migrate-bulma-to-v1.html</link><title>blog-fable を Bulma 1.0.0 に対応する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; に &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/44&quot; title=&quot;query string selection&quot;&gt;query string selection&lt;/a&gt; を実装するのはそれなりに進んだ。
一段落ついたらまた日記にまとめたいが、その前に &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt;(このブログ) へデカ目の変更が降りてきたので、今日はそっちを書く。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;デカ目の変更というのは、 &lt;a href=&quot;https://github.com/jgthms/bulma/releases/tag/1.0.0&quot; title=&quot;Bulma の 1.0.0&quot;&gt;Bulma の 1.0.0&lt;/a&gt; のリリースだ。
捕捉してなかったから、これには正直驚いた。
どうも 2024-01 頃から準備が進んでたらしい。 &lt;a href=&quot;https://github.com/jgthms/bulma/issues/3708&quot; title=&quot;v1 release date? · Issue #3708 · jgthms/bulma&quot;&gt;v1 release date? · Issue #3708 · jgthms/bulma&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;正直どこも賑わってなさそうなんやけど、 Hacker News にスレは立ってた。&lt;a href=&quot;https://news.ycombinator.com/item?id=39790365&quot; title=&quot;The Bulma CSS framework reaches 1.0 | Hacker News&quot;&gt;The Bulma CSS framework reaches 1.0 | Hacker News&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;blog-fable を作った(このブログを Fable で作り直した)のは 2023 で、当時の Bulma の最新は 0.9.4 だった。
0.9.4 が 2022-05 頃に&lt;a href=&quot;https://github.com/jgthms/bulma/commit/3e00a8e6d0d0e566d507328f0185ef84854effba&quot; title=&quot;Build 0.9.4 · jgthms/bulma@3e00a8e&quot;&gt;Build 0.9.4 · jgthms/bulma@3e00a8e&lt;/a&gt;リリースされて以降の Bulma は、リリースがなかったわけだ。
GitHub にアクティビティはあったけど、スポンサーのロゴを差し替えたりって変更とかが多くて、割と Issue, Pull Request も積んでた感じ。&lt;/p&gt;
&lt;p&gt;今どきはみんな &lt;a href=&quot;https://tailwindcss.com/&quot; title=&quot;Tailwind CSS&quot;&gt;Tailwind CSS&lt;/a&gt; を使うのだろうけど、 blog-fable では CSS を書く労力を減らしたかったから Bulma を使った。
Bulma なら class 指定しなくてもそこそこ default で style が利くので、構造自体に集中しやすい。
かつ JS 不要な CSS framework で、 Sass を使ってある程度 bundle を小さくできる余地があった。
Fable の Bulma wrapper である &lt;a href=&quot;https://fulma.github.io/Fulma/&quot; title=&quot;Fulma&quot;&gt;Fulma&lt;/a&gt; もあるけど、これは&lt;a href=&quot;/posts/2023-06-04-rebuild-blog-with-fable-pt5.html&quot; title=&quot;当時フィーリングが合わなかったみたい&quot;&gt;当時フィーリングが合わなかったみたい&lt;/a&gt;で採用しなかった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;昔話はこの程度にして、 Bulma 1.0.0 での変更点を見ていく。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bulma.io/documentation/start/migrating-to-v1/&quot; title=&quot;Migrating to Bulma v1 | Bulma: Free, open source, and modern CSS framework based on Flexbox&quot;&gt;Migrating to Bulma v1 | Bulma: Free, open source, and modern CSS framework based on Flexbox&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Bulma 1.0.0 は全面的に &lt;a href=&quot;https://sass-lang.com/dart-sass/&quot; title=&quot;Dart Sass&quot;&gt;Dart Sass&lt;/a&gt; で書き直されたらしい。
&lt;code&gt;@import&lt;/code&gt; も非推奨となり、 &lt;code&gt;@use&lt;/code&gt; がちゃんと使えるようになったのは喜ばしい。&lt;/p&gt;
&lt;p&gt;blog-fable ではカラースキームの変更と bundle 最小化のために、以下のように Sass を使ってスタイルを自作している。
カラースキームは Solarized で light/dark のモード切替なしで dark 固定だ。
Bulma 0.9.4 だと &lt;code&gt;@use&lt;/code&gt; を使った場合、必要な &lt;code&gt;*.sass&lt;/code&gt; だけインポートする方法だとエラーで使えなくて、古き良き &lt;code&gt;@import&lt;/code&gt; を使っていた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/b51df81f0ef32e3065c18a43248c6599f15d9da8/sass/style.scss&quot; title=&quot;blog-fable/sass/style.scss at b51df81f0ef32e3065c18a43248c6599f15d9da8 · krymtkts/blog-fable&quot;&gt;blog-fable/sass/style.scss at b51df81f0ef32e3065c18a43248c6599f15d9da8 · krymtkts/blog-fable&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-scss&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@charset&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; based on https://ethanschoonover.com/solarized/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$base03&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#002b36&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$base02&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#073642&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$base01&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#586e75&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$base00&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#657b83&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$base0&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#839496&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$base1&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#93a1a1&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$base2&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#eee8d5&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$base3&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#fdf6e3&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$yellow&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#b58900&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$orange&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#cb4b16&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$red&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#dc322f&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$magenta&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#d33682&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$violet&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#6c71c4&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$blue&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#268bd2&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$cyan&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#2aa198&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$green&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#859900&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// // &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Solarized Light.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $black: $base03,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $black-bis: $base02,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $black-ter: $base02,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $grey-darker: $base00,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $grey-dark: $base00,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $grey: $base01,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $grey-light: $base0,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $grey-lighter: $base1,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $grey-lightest: $base1,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $white-ter: $base2,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $white-bis: $base2,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $white: $base3,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $background: $base3,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $code: $base01,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// $tag-background-color: $base3,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Solarized Dark.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$black&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base3&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$black-bis&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base2&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$black-ter&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base2&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$grey-darker&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base1&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$grey-dark&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base1&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$grey&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base0&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$grey-light&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base00&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$grey-lighter&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base01&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$grey-lightest&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base01&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$white-ter&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base02&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$white-bis&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base02&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$white&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base03&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$background&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base03&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$code&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base0&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$tag-background-color&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base03&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$hr-background-color&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base01&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$orange&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$orange&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$yellow&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$yellow&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$green&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$green&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$turquoise&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$cyan&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$cyan&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$cyan&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$blue&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$blue&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$purple&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$violet&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$red&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$red&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$code-size&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1em&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$link-hover&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$violet&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$section-padding&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1.5rem&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$section-padding-desktop&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1.5rem&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$body-line-height&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1.7&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/utilities/_all.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/base/_all.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/components/navbar.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/components/tabs.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/elements/button.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/elements/container.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/elements/content.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/elements/image.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/elements/tag.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/elements/title.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/form/shared.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/form/checkbox-radio.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/layout/footer.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass/layout/section.sass&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; adjust non-parameterized styles.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.content&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;a&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-selector-tag&quot;&gt;text&lt;/span&gt;-decoration: underline;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:visited&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;color&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$purple&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.checkbox&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;margin-right&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;0.5em&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;main&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;padding-bottom&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1.5em&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;code&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;word-wrap&lt;/span&gt;: break-word;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;code&lt;/span&gt;,&lt;br /&gt;pre,&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.tag&lt;/span&gt;&lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:not&lt;/span&gt;(body) {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;border&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1px&lt;/span&gt; solid &lt;span class=&quot;hljs-variable&quot;&gt;$grey-lighter&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;border-radius&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$radius&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;pre &lt;span class=&quot;hljs-selector-tag&quot;&gt;code&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;border&lt;/span&gt;: none;&lt;br /&gt;  &lt;span class=&quot;hljs-selector-tag&quot;&gt;line&lt;/span&gt;-&lt;span class=&quot;hljs-attribute&quot;&gt;height&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1.5&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.content&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-selector-tag&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:first-child&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-attribute&quot;&gt;margin-top&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;0.25em&lt;/span&gt;;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.date&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;color&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$base01&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.prev&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:before&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;content&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\2190&amp;quot;&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.next&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:after&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;content&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\2192&amp;quot;&lt;/span&gt;;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Bulma 1.0.0 になったことで普通に使う分には非推奨のコンポーネントが出たくらいだろうが、昨日試してみた感じだと、先述したような独自のスタイルを構築している場合に結構影響を受ける感じだった。
なんか従来通りカラースキームを指定しても背景に使われないのよね。&lt;/p&gt;
&lt;p&gt;試行錯誤して、 &lt;a href=&quot;https://bulma.io/documentation/features/dark-mode/&quot; title=&quot;automatic Dark Mode&quot;&gt;automatic Dark Mode&lt;/a&gt; と &lt;a href=&quot;https://bulma.io/documentation/features/css-variables/&quot; title=&quot;CSS variables&quot;&gt;CSS variables&lt;/a&gt; の仕組みを理解してうまく使えば、ひとまずいい感じにできそうとわかってきた。&lt;/p&gt;
&lt;p&gt;automatic Dark Mode の場合、 light ↔ dark の色を &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl&quot; title=&quot;&lt;code&gt;hsl&lt;/code&gt;, &lt;code&gt;hsla&lt;/code&gt;&quot;&gt;&lt;code&gt;hsl&lt;/code&gt;, &lt;code&gt;hsla&lt;/code&gt;&lt;/a&gt; で計算して出してる。
そのベースとなる CSS variable に色を指定する必要があるみたい。
0.9.4 のときは単純に &lt;code&gt;$black&lt;/code&gt; とかの色の Sass の変数を変えるだけでいけた。
けど、 1.0.0 からは &lt;code&gt;--bulma-scheme-h&lt;/code&gt;, &lt;code&gt;--bulma-scheme-s&lt;/code&gt;, &lt;code&gt;--bulma-scheme-l&lt;/code&gt; 等で色相、彩度、輝度を指定しないといけないみたい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;button&lt;/code&gt; や &lt;code&gt;tag&lt;/code&gt; などのコンポーネントはそれで背景色が決まるので、ここを攻略しないとどうにもならん。
最悪彩度と輝度に無効な値を指定すれば無視できるのはわかったが、きちんと指定しておきたい。
でもまだドキュメント読んでもあんまわからん。ドキュメントではの変数を参照してるとか調べるのが難しい。&lt;/p&gt;
&lt;p&gt;ということで、開発者ツールで手探りして以下を設定してみたら、今のところほぼ同じにできた。
ほぼと書いたのは、箇条書きの line height が微妙に違いそうだからだ。
また、 &lt;code&gt;button&lt;/code&gt; の border の色が &lt;code&gt;hsl&lt;/code&gt; で勝手に定まるのだけ対処法わからなかったので style を上書きした。
light/dark の style を 2 箇所ずつ書かないといけないので、コピペしなくていいよう &lt;code&gt;@mixin&lt;/code&gt; にまとめてある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/aa668a3e991a46e9b3b3d0302bdbc717d146665e/sass/style.scss&quot; title=&quot;blog-fable/sass/style.scss at aa668a3e991a46e9b3b3d0302bdbc717d146665e · krymtkts/blog-fable&quot;&gt;blog-fable/sass/style.scss at aa668a3e991a46e9b3b3d0302bdbc717d146665e · krymtkts/blog-fable&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-scss&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@charset&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; based on https://ethanschoonover.com/solarized/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base03&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#002b36&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base02&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#073642&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base01&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#586e75&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base00&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#657b83&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base0&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#839496&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base1&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#93a1a1&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base2&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#eee8d5&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base3&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#fdf6e3&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-yellow&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#b58900&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-orange&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#cb4b16&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-red&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#dc322f&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-magenta&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#d33682&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-violet&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#6c71c4&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-blue&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#268bd2&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-cyan&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#2aa198&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$sl-green&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#859900&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@use&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../node_modules/bulma/sass&amp;quot;&lt;/span&gt; as * with (&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$orange&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$sl-orange&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$yellow&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$sl-yellow&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$green&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$sl-green&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$turquoise&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$sl-cyan&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$cyan&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$sl-cyan&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$blue&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$sl-blue&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$purple&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$sl-violet&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$red&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$sl-red&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$code-size&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1em&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$body-line-height&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1.7&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$section-padding&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1.5rem&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$section-padding-desktop&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1.5rem&lt;/span&gt;&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@mixin&lt;/span&gt; light-theme {&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Solarized Light.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-black&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base03&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-black-bis&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base02&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-black-ter&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base02&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey-darker&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base00&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey-dark&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base00&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base01&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey-light&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base0&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey-lighter&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base1&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey-lightest&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base1&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-white-ter&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base2&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-white-bis&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base2&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-white&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base3&lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-text&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base01&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-text-strong&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base01&lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base3&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-bis&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base2&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-ter&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base2&lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-h&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;44&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-s&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;87%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-l&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;94%&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-background-l&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;94%&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-s&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;87%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-bis-s&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;87%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-ter-s&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;87%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-l&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;94%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-bis-l&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;94%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-ter-l&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;94%&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-code&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base00&lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-hr-background-color&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base1&lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-border&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base1&lt;/span&gt;};&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@mixin&lt;/span&gt; dark-theme {&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; Solarized Dark.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-black&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base3&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-black-bis&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base2&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-black-ter&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base2&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey-darker&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base1&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey-dark&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base1&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base0&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey-light&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base00&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey-lighter&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base01&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-grey-lightest&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base01&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-white-ter&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base02&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-white-bis&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base02&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-white&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base03&lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-text&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base1&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-text-strong&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base1&lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base03&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-bis&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base02&lt;/span&gt;};&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-ter&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base02&lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-h&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;192&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-s&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;100%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-l&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;11%&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-background-l&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;11%&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-s&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;100%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-bis-s&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;100%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-ter-s&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;100%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-l&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;11%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-bis-l&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;11%&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-scheme-main-ter-l&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;11%&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-code&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base0&lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-hr-background-color&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base01&lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;--bulma-border&lt;/span&gt;: #{&lt;span class=&quot;hljs-variable&quot;&gt;$sl-base01&lt;/span&gt;};&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@media&lt;/span&gt; (&lt;span class=&quot;hljs-attribute&quot;&gt;prefers-color-scheme&lt;/span&gt;: light) {&lt;br /&gt;  &lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:root&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;@include&lt;/span&gt; light-theme();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-selector-attr&quot;&gt;[data-theme=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dark&amp;quot;&lt;/span&gt;]&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;@include&lt;/span&gt; dark-theme();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@media&lt;/span&gt; (&lt;span class=&quot;hljs-attribute&quot;&gt;prefers-color-scheme&lt;/span&gt;: dark) {&lt;br /&gt;  &lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:root&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;@include&lt;/span&gt; dark-theme();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-selector-attr&quot;&gt;[data-theme=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;light&amp;quot;&lt;/span&gt;]&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;@include&lt;/span&gt; light-theme();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; adjust non-parameterized styles.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.content&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;a&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-selector-tag&quot;&gt;text&lt;/span&gt;-decoration: underline;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:visited&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;color&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$purple&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.checkbox&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;margin-right&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;0.5em&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;main&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;padding-bottom&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1.5em&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;code&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;word-wrap&lt;/span&gt;: break-word;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;code&lt;/span&gt;,&lt;br /&gt;pre,&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.tag&lt;/span&gt;&lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:not&lt;/span&gt;(body),&lt;br /&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.button&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;border&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1px&lt;/span&gt; solid &lt;span class=&quot;hljs-variable&quot;&gt;$sl-base01&lt;/span&gt;;&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;border-radius&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$radius&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;pre &lt;span class=&quot;hljs-selector-tag&quot;&gt;code&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;border&lt;/span&gt;: none;&lt;br /&gt;  &lt;span class=&quot;hljs-selector-tag&quot;&gt;line&lt;/span&gt;-&lt;span class=&quot;hljs-attribute&quot;&gt;height&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1.5&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.content&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-selector-tag&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:first-child&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-attribute&quot;&gt;margin-top&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;0.25em&lt;/span&gt;;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.date&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;color&lt;/span&gt;: &lt;span class=&quot;hljs-variable&quot;&gt;$sl-base01&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.prev&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:before&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;content&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\2190&amp;quot;&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-selector-class&quot;&gt;.next&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:after&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-attribute&quot;&gt;content&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\2192&amp;quot;&lt;/span&gt;;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;とりまこっから個々の &lt;code&gt;*.scss&lt;/code&gt; を &lt;code&gt;@use&lt;/code&gt; するように変えてみて、 bundle を縮小したい。
いま 68.7kb もあってやっぱデカいなと思わせるものがある。&lt;/p&gt;
&lt;p&gt;あと手動で light/dark mode を切り替える実装について。&lt;/p&gt;
&lt;p&gt;ドキュメントにも記載あるが、 Bulma の automatic dark mode は &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme&quot; title=&quot;&lt;code&gt;prefers-color-scheme&lt;/code&gt;&quot;&gt;&lt;code&gt;prefers-color-scheme&lt;/code&gt;&lt;/a&gt; の media query を使ってる。
そこで利用者自身が light/dark mode を使い分けるには &lt;code&gt;data-theme=&amp;quot;dark&amp;quot;&lt;/code&gt; を指定するようにしないとダメっぽい。
先に挙げた SCSS で &lt;code&gt;[data-theme=&amp;quot;dark&amp;quot;] { ~ }&lt;/code&gt; 等としているのはそのためだ。
システムのカラースキームに合わせて反対の色を定義しないといけないのが、わかるまでちょっとつまづいた。&lt;/p&gt;
&lt;p&gt;このあと、 HTML に &lt;code&gt;data-theme=&amp;quot;dark&amp;quot;&lt;/code&gt; や &lt;code&gt;data-theme=&amp;quot;light&amp;quot;&lt;/code&gt; を差し込む機能を、画面のどっかに設ける必要がある。
↓ こういうのを Fable で作らないといけない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;documentElement&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;setAttribute&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;data-theme&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dark&amp;quot;&lt;/span&gt;);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;はじめはどうなるかと不安に思ったが、気合い入れたら終わり見えて良かった。&lt;/p&gt;
&lt;p&gt;Bulma も 1.0.0 が出たばかりだしちょっとの間は更新リリースが続くんじゃないかな。
テクノロジー的に「枯れる」というのは確かにあるが、取り巻く環境の変化に合わせて rewrite されていくのは良いことやな。素直に尊敬するわ。
blog-fable でも自力での対応を放置してた light/dark mode に棚ぼたであやかれて嬉しい限り。&lt;/p&gt;
&lt;p&gt;つづく。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 24 Mar 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-03-17-what-is-xplat-in-coverlet.html</guid><link>https://krymtkts.github.io/posts/2024-03-17-what-is-xplat-in-coverlet.html</link><title>Coverlet の XPlat て何だよ</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;久しぶりに大酒を飲んでボロボロの二日酔いになってしまったので、 &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をできなかった。&lt;/p&gt;
&lt;p&gt;代わりに、ずっと気になってた coverlet のキーワードの正体を調べた。
Coverlet を起動する &lt;code&gt;dotnet test --collect:&amp;quot;XPlat Code Coverage&amp;quot;&lt;/code&gt; の &lt;code&gt;&amp;quot;XPlat Code Coverage&amp;quot;&lt;/code&gt; が何なのかを知りたかった。
世の中は広いので、同じことを考えた人が先にいた。ありがたい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/coverlet-coverage/coverlet/issues/1065#issuecomment-765290037&quot; title=&quot;What is &amp;quot;XPlat Code Coverage&amp;quot; · Issue #1065 · coverlet-coverage/coverlet&quot;&gt;What is &amp;quot;XPlat Code Coverage&amp;quot; · Issue #1065 · coverlet-coverage/coverlet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/microsoft/vstest/blob/724f79b5f4fb4ad33c5c6411ea74b31aea6e8776/src/vstest.console/Processors/CollectArgumentProcessor.cs&quot; title=&quot;vstest/src/vstest.console/Processors/CollectArgumentProcessor.cs at 724f79b5f4fb4ad33c5c6411ea74b31aea6e8776 · microsoft/vstest&quot;&gt;vstest/src/vstest.console/Processors/CollectArgumentProcessor.cs at 724f79b5f4fb4ad33c5c6411ea74b31aea6e8776 · microsoft/vstest&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;CoverletConstants&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; Coverlet in-proc data collector friendly name&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; CoverletDataCollectorFriendlyName = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;XPlat Code Coverage&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; Coverlet in-proc data collector assembly qualified name&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; CoverletDataCollectorAssemblyQualifiedName = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Coverlet.Collector.DataCollection.CoverletInProcDataCollector, coverlet.collector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; Coverlet in-proc data collector code base&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; CoverletDataCollectorCodebase = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;coverlet.collector.dll&amp;quot;&lt;/span&gt;;&lt;br /&gt;    }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ふーむ、 VSTest が決め打ちしている &lt;code&gt;coverlet.collector&lt;/code&gt; を起動するキーワードなのはわかったが、結局 &lt;code&gt;XPlat&lt;/code&gt; て何？&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-code-coverage?tabs=windows#integrate-with-net-test&quot; title=&quot;Use code coverage for unit testing - .NET | Microsoft Learn&quot;&gt;Use code coverage for unit testing - .NET | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &amp;quot;XPlat Code Coverage&amp;quot; argument is a friendly name that corresponds to the data collectors from Coverlet. This name is required but is case insensitive. To use .NET&amp;#39;s built-in Code Coverage data collector, use &amp;quot;Code Coverage&amp;quot;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;フレンドリーな名前とは...&lt;/p&gt;
&lt;p&gt;それはおそらくこちらが答えなんだろうなと思っている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/microsoft/vstest/blob/724f79b5f4fb4ad33c5c6411ea74b31aea6e8776/docs/contribute.md?plain=1#L63-L64&quot; title=&quot;vstest/docs/contribute.md at 724f79b5f4fb4ad33c5c6411ea74b31aea6e8776 · microsoft/vstest&quot;&gt;vstest/docs/contribute.md at 724f79b5f4fb4ad33c5c6411ea74b31aea6e8776 · microsoft/vstest&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; A portable &lt;span class=&quot;hljs-code&quot;&gt;`vstest.console`&lt;/span&gt; for desktop (net46 target) and xplat (netcoreapp)&lt;br /&gt;  target
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;.NET の Desktop と NETCoreApp の対比から考えて、結局 &lt;code&gt;XPlat&lt;/code&gt; て cross platform てことやねんな。
そう思って検索してみたら cross platform て意味で使ってる例がいくつか見つかる。一般的なキーワードなんだろうか。
こんなん不惑超えるまで知らんかったわ...&lt;/p&gt;
&lt;p&gt;おわり。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 17 Mar 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-03-10-writing-cmdlet-in-fsharp-pt35.html</guid><link>https://krymtkts.github.io/posts/2024-03-10-writing-cmdlet-in-fsharp-pt35.html</link><title>F# でコマンドレットを書いてる pt.35</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;ちょっと今週末は忙しかったので&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/44&quot; title=&quot;クエリ文字列選択&quot;&gt;クエリ文字列選択&lt;/a&gt;の開発をあまりできてない。&lt;/p&gt;
&lt;p&gt;時間が取れなかったので車の後部座席に乗りながら pocof 開発を 2 時間ほどやってみたのだけど、それなりに準備しないといけないが、思ったよりできるなという感触を得た。
助手席のヘッドレストにリュックの背中の部分が上になるようリュックを片方かける。そこに laptop を置き、下から膝でサポートすれば割りと安定する。
ケチってテザリングしなかったので GitHub Copilot の支援は受けれなかったが、支援なくなったてもまだ割と書けるなという感じも得た。&lt;/p&gt;
&lt;p&gt;ただし高速に乗ってるときくらいじゃないと揺れでとてもタイピングできないし、
あと夜間はわたしの目が悪いのもあって、結構しんどい感じだった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;という感じで進捗あまりないが、 &lt;a href=&quot;https://en.wikipedia.org/wiki/ANSI_escape_code&quot; title=&quot;ANSI escape sequences&quot;&gt;ANSI escape sequences&lt;/a&gt; 対応の前準備として、手軽にできるレンダリングの改善だけしたのでそれに触れる。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/149&quot; title=&quot;#149&quot;&gt;#149&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSReadLine/blob/5efe2ef55f85bbac9c8a8f39825ad62b3049b0a5/PSReadLine/ReadLine.cs#L1004-L1041&quot; title=&quot;PSReadLine/PSReadLine/ReadLine.cs&quot;&gt;PSReadLine/PSReadLine/ReadLine.cs&lt;/a&gt; を見てて気づいたのだけど、描画中は &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.console.cursorvisible?view=net-8.0&quot; title=&quot;&lt;code&gt;Console.CursorVisible&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.CursorVisible&lt;/code&gt;&lt;/a&gt; を &lt;code&gt;false&lt;/code&gt; にしてる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; console = _singleton._console;&lt;br /&gt;            console.CursorVisible = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// 略&lt;/span&gt;&lt;br /&gt;            _singleton.Render();&lt;br /&gt;            console.CursorVisible = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;&lt;br /&gt;        }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;GUI アプリケーションなんかでもよくある手法で、描画の状態が決定するまで描画停止するアレと同じ手法だこれ。
CUI アプリケーションの場合だと、カーソルのチラつき(flicking と表現するぽい)を抑えるために同じ手法が使えるみたい。
CPU 負荷が高い時にノロノロとカーソルが移動することでチラつき(flicking)が目に付きやすくなるので、カーソルを見えなくすることでチラつき(flicking)をなくす効果があると。
なるほどなー、すっかり忘れてたわ。&lt;/p&gt;
&lt;p&gt;実際に pocof の CPU 高負荷時のもっさり挙動でチラつきが目立つので、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.idisposable?view=net-7.0&quot; title=&quot;&lt;code&gt;IDisposable&lt;/code&gt;&quot;&gt;&lt;code&gt;IDisposable&lt;/code&gt;&lt;/a&gt; 実装を使って以下の様に対処した。目立つチラつき(flicking)は抑えれそう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;RawUI&lt;/span&gt;(rui) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// Console.CursorVisible を一時的に無効にする&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; IRawUI &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.HideCursorWhileRendering() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                Console.CursorVisible &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                { &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; IDisposable &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; _.Dispose() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Console.CursorVisible &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Buff&lt;/span&gt;(r, i, layout) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; rui&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; IRawUI &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; r&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// 使う方はこうする&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.WriteScreen&lt;br /&gt;            (layout&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Data.Layout)&lt;br /&gt;            (state&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Data.InternalState)&lt;br /&gt;            (entries&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Data.Entry &lt;span class=&quot;hljs-type&quot;&gt;list&lt;/span&gt;)&lt;br /&gt;            (props&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;list&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;)&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;use&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; rui.HideCursorWhileRendering()&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ちなみに実際のパフォに違いがあるのかというと、調べてみた感じだと微妙だった。
以下のようなテスト関数を作成しまして、 1 行ずつ書くパターン、 1 文字ずつ書くパターンを比較した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;test-rendering&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;switch&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$HideCursor&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;switch&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$HardMode&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$HideCursor&lt;/span&gt;) {&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::CursorVisible = &lt;span class=&quot;hljs-variable&quot;&gt;$false&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::SetCursorPosition(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$start&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt; | % {&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::SetCursorPosition(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;)&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$HardMode&lt;/span&gt;) {&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;# 1 文字ずつ描画する激遅モード&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; .. ([&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::WindowWidth - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) | % { [&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::&lt;span class=&quot;hljs-built_in&quot;&gt;Write&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x&amp;#x27;&lt;/span&gt;) }&lt;br /&gt;        }&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;# 1 行ずつ描画する普通モード&lt;/span&gt;&lt;br /&gt;            [&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::&lt;span class=&quot;hljs-built_in&quot;&gt;Write&lt;/span&gt;((&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x&amp;#x27;&lt;/span&gt; * ([&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::WindowWidth - &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;)))&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    ((&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt;) - &lt;span class=&quot;hljs-variable&quot;&gt;$start&lt;/span&gt;).Milliseconds&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$HideCursor&lt;/span&gt;) {&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::CursorVisible = &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# それぞれを無風状態のときに実行&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$a1&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; .. &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt; | % { &lt;span class=&quot;hljs-built_in&quot;&gt;test-rendering&lt;/span&gt; } | &lt;span class=&quot;hljs-built_in&quot;&gt;measure&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AllStats&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$a2&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; .. &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt; | % { &lt;span class=&quot;hljs-built_in&quot;&gt;test-rendering&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-HideCursor&lt;/span&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;measure&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AllStats&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$b1&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; .. &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt; | % { &lt;span class=&quot;hljs-built_in&quot;&gt;test-rendering&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-HardMode&lt;/span&gt; } | &lt;span class=&quot;hljs-built_in&quot;&gt;measure&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AllStats&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$b2&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; .. &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt; | % { &lt;span class=&quot;hljs-built_in&quot;&gt;test-rendering&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-HardMode&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-HideCursor&lt;/span&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;measure&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AllStats&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$a1&lt;/span&gt;;&lt;span class=&quot;hljs-variable&quot;&gt;$a2&lt;/span&gt;;&lt;span class=&quot;hljs-variable&quot;&gt;$b1&lt;/span&gt;;&lt;span class=&quot;hljs-variable&quot;&gt;$b2&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Count             : 100&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Average           : 5.05&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Sum               : 505&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Maximum           : 10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Minimum           : 3&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# StandardDeviation : 1.50671895859912&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Property          :&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Count             : 100&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Average           : 4.96&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Sum               : 496&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Maximum           : 10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Minimum           : 3&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# StandardDeviation : 1.43491808093351&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Property          :&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Count             : 100&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Average           : 216.31&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Sum               : 21631&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Maximum           : 283&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Minimum           : 196&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# StandardDeviation : 19.5596446023361&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Property          :&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Count             : 100&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Average           : 221.2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Sum               : 22120&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Maximum           : 297&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Minimum           : 196&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# StandardDeviation : 20.8810967628667&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Property          :&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;結果、カーソル非表示の有無で誤差レベルの差しかない。
実行したときの CPU 利用状況の影響のほうがでかい。
なので体感の改善って面が大きい。&lt;/p&gt;
&lt;p&gt;おわり。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 10 Mar 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-03-03-writing-cmdlet-in-fsharp-pt34.html</guid><link>https://krymtkts.github.io/posts/2024-03-03-writing-cmdlet-in-fsharp-pt34.html</link><title>F# でコマンドレットを書いてる pt.34</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の 0.10.0 をリリースした。&lt;/p&gt;
&lt;p&gt;pocof 史上初の全画面スタイルを廃止する Half モード(&lt;code&gt;TopDownHalf&lt;/code&gt;, &lt;code&gt;BottomUpHalf&lt;/code&gt;) の導入は、自分自身使ってみてやっぱいいなという感じがしてる。
挙動が &lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; チック過ぎて、わたしがやりたかったのは Feedback Providers&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; やったんかも...というのはあるかも。&lt;/p&gt;
&lt;p&gt;あと &lt;a href=&quot;https://fsprojects.github.io/FSharpLint/&quot; title=&quot;FSharpLint&quot;&gt;FSharpLint&lt;/a&gt;, &lt;a href=&quot;https://fsprojects.github.io/fantomas/&quot; title=&quot;Fantomas&quot;&gt;Fantomas&lt;/a&gt;, &lt;a href=&quot;https://github.com/PowerShell/PSScriptAnalyzer&quot; title=&quot;PSScriptAnalyzer&quot;&gt;PSScriptAnalyzer&lt;/a&gt; 諸々チェックするようにしたので開発の安心感も高まった。&lt;/p&gt;
&lt;p&gt;次に着手している開発は &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/44&quot; title=&quot;#44 Support query string selection&quot;&gt;#44 Support query string selection&lt;/a&gt; だ。
わたしのタイピングだと、変えたい箇所を選択して backspace, delete, あるいはそのままタイプして変えることが多い(あと Ctrl + Arrow で移動するのも多いけどこれは保留)。
いま pocof には文字列を選択する機能がないから、通常のエディタと pocof で編集の仕方が違うのでめんどい。
これも個人的に期待度の高い機能となっている(放置してたけど)。&lt;/p&gt;
&lt;p&gt;この機能を作るに当たり、 CUI の前景色と背景色を反転する必要がある。
そして PowerShell で CUI の色を操作する方法が 2 つあるのは理解している。
具体的なコードとかは雑な理解だったので今回見てみた。あと他の方法があるかも知れないが、それは調べてない。&lt;/p&gt;
&lt;p&gt;1 つは &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.console.foregroundcolor?view=net-8.0#system-console-foregroundcolor&quot; title=&quot;&lt;code&gt;Console.ForegroundColor&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.ForegroundColor&lt;/code&gt;&lt;/a&gt; &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.console.backgroundcolor?view=net-8.0#system-console-backgroundcolor&quot; title=&quot;&lt;code&gt;Console.BackgroundColor&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.BackgroundColor&lt;/code&gt;&lt;/a&gt; を直にいじる方法。
変えた色を戻すのに &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.console.resetcolor?view=net-8.0&quot; title=&quot;&lt;code&gt;Console.ResetColor&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.ResetColor&lt;/code&gt;&lt;/a&gt; を使う。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Powerline を使ってると動作確認困難なので繋げて実行する&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$tmp&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::BackgroundColor; `&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::BackgroundColor = [&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::ForegroundColor; `&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::ForegroundColor = &lt;span class=&quot;hljs-variable&quot;&gt;$tmp&lt;/span&gt;; `&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::&lt;span class=&quot;hljs-built_in&quot;&gt;Write&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;こんちはーっ!!`n&amp;quot;&lt;/span&gt;); `&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::ResetColor(); `&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::&lt;span class=&quot;hljs-built_in&quot;&gt;Write&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ザバーッ&amp;#x27;&lt;/span&gt;);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;もう 1 つは &lt;a href=&quot;https://en.wikipedia.org/wiki/ANSI_escape_code&quot; title=&quot;ANSI escape sequences&quot;&gt;ANSI escape sequences&lt;/a&gt; を直に使う方法。
PowerShell 直で使うと &lt;code&gt;`e&lt;/code&gt; が ANSI escape sequence 。
[Escape (`e) | about Special Characters - PowerShell | Microsoft Learn](&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_special_characters?view=powershell-7.4#escape-e&quot; title=&quot;undefined&quot;&gt;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_special_characters?view=powershell-7.4#escape-e&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;`e7m&lt;/code&gt; で反転、 &lt;code&gt;`e[27m&lt;/code&gt; で元に戻すらしい。
&lt;a href=&quot;https://duffney.io/usingansiescapesequencespowershell/&quot; title=&quot;Using ANSI Escape Sequences in PowerShell :: — duffney.io&quot;&gt;Using ANSI Escape Sequences in PowerShell :: — duffney.io&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;1 つ目と完全に同じではないが、よりできることが多い。その代わり先に挙げた個々の ANSI Escape Sequence を理解して使う必要があり、&lt;del&gt;めんどさ&lt;/del&gt;制御の煩雑さが伴う。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;]::&lt;span class=&quot;hljs-built_in&quot;&gt;Write&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`e[7mこんちはーっ!!`e[27m`nザバーッ&amp;quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;2 つ目の利点は ANSI Escape Sequence を組み込んだ文字列さえ組み立ててしまえば、一発で印字できるところ。
pocof での用途を鑑みると、クエリ文字列の部分選択をした箇所だけ前景背景を反転させる必要があるので、そのためだけに印字を分割しなければならない前者は採用できないかなーというのがでかい。&lt;/p&gt;
&lt;p&gt;(
現に今の pocof のもっさりレンダリングは書き込み回数が小分けされてることに因る...
PSReadLine パイセンは一気に印字スタイルぽいので、ふつーそっちに寄せるのが一般的なんやろな &lt;a href=&quot;https://github.com/PowerShell/PSReadLine/blob/5efe2ef55f85bbac9c8a8f39825ad62b3049b0a5/PSReadLine/Render.cs#L722&quot; title=&quot;PSReadLine/PSReadLine/Render.cs&quot;&gt;PSReadLine/PSReadLine/Render.cs&lt;/a&gt;
)&lt;/p&gt;
&lt;p&gt;ちょいと前例というか PSReadLine パイセンを調べたところ、こちらも ANSI Escape Sequence を使っていた。なので方向性は合ってる。
PSReadLine は &lt;a href=&quot;https://github.com/PowerShell/PSReadLine/blob/5efe2ef55f85bbac9c8a8f39825ad62b3049b0a5/PSReadLine/Cmdlets.cs#L1048&quot; title=&quot;VSColorUtils&quot;&gt;VSColorUtils&lt;/a&gt; というクラスにその辺こ ANSI escape sequences をまとめて使ってる。
pocof でもそんな多機能はいらんにしてもまとめる必要はあるかな。&lt;/p&gt;
&lt;p&gt;F# で書く場合、 ANSI Escape Sequence は PowerShell と違って C# と同じように &lt;code&gt;\x1b&lt;/code&gt; を送るのが一般的ぽい。
C# では &lt;code&gt;\e&lt;/code&gt; を ANSI escape sequence に使える機能が増えてる様子。
だが機能が新し過ぎるのもあってか、昔からやってる PSReadLine では直に ANSI escape sequence を送る &lt;code&gt;\x1b&lt;/code&gt; を使ってるようだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dotnet/csharplang/issues/7400&quot; title=&quot;[Proposal]: String/Character escape sequence &lt;code&gt;\e&lt;/code&gt; as a short-hand for &lt;code&gt;\u001b&lt;/code&gt; (&lt;code&gt;&amp;lt;ESCAPE&amp;gt;&lt;/code&gt;) · Issue #7400 · dotnet/csharplang&quot;&gt;[Proposal]: String/Character escape sequence &lt;code&gt;\e&lt;/code&gt; as a short-hand for &lt;code&gt;\u001b&lt;/code&gt; (&lt;code&gt;&amp;lt;ESCAPE&amp;gt;&lt;/code&gt;) · Issue #7400 · dotnet/csharplang&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これらを踏まえて F# でやるなら以下の形式の出力を、なんかの抽象化層を通してやる感じか。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;Console.Write(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\x1b[7mこんちはーっ!!\x1b[27m\nザバーッ&amp;quot;&lt;/span&gt;);;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あとはどっからどこまでを反転するかの選択範囲を pocof 内部の状態に追加して、 &lt;a href=&quot;https://github.com/krymtkts/pocof/blob/6383b3efcd812593f5110ea7fbf18ac834fabc67/src/pocof/Handle.fs&quot; title=&quot;&lt;code&gt;Handle.fs&lt;/code&gt;&quot;&gt;&lt;code&gt;Handle.fs&lt;/code&gt;&lt;/a&gt; でキーに応じてよしなに更新操作するってところかー。&lt;/p&gt;
&lt;p&gt;とりま方針は定まったな。
ついでにレンダリング効率悪いのも解決できたらなんか使い勝手良さそう(今クソ遅いし)。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://devblogs.microsoft.com/powershell/what-are-feedback-providers/&quot; title=&quot;What are Feedback Providers? - PowerShell Team&quot;&gt;What are Feedback Providers? - PowerShell Team&lt;/a&gt; &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 03 Mar 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-02-25-writing-cmdlet-in-fsharp-pt33.html</guid><link>https://krymtkts.github.io/posts/2024-02-25-writing-cmdlet-in-fsharp-pt33.html</link><title>F# でコマンドレットを書いてる pt.33</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fsprojects.github.io/FSharpLint/&quot; title=&quot;FSharpLint&quot;&gt;FSharpLint&lt;/a&gt; を入れたのでついでに &lt;a href=&quot;https://fsprojects.github.io/fantomas/&quot; title=&quot;Fantomas&quot;&gt;Fantomas&lt;/a&gt; も入れてみた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/145&quot; title=&quot;#145&quot;&gt;#145&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これまで VS Code の &lt;a href=&quot;https://ionide.io/&quot; title=&quot;Ionide&quot;&gt;Ionide&lt;/a&gt; での整形しかやってなかったが、それを機械的に CI でもチェックしようかなという考えだ。
実際 fantomas 入れてみたことで Ionide でファイル保存したときの整形も変わったので、なんか進化したのかも知れん。
pocof での fantomas の設定は以下の通りほとんどない(以下もデフォルト値でほぼ要らんレベル)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;hljs-section&quot;&gt;[*.{fs,fsx,fsi}]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;indent_size&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;end_of_line&lt;/span&gt; = lf
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;個人的にはあまりコードフォーマットに独自性をもたせることは興味がなく、誰が書いても同じになるのが考えることも減って楽でいいと思っている。
なので標準的な何かにさえ準拠してそれが自動的に適用されていればよい。&lt;/p&gt;
&lt;p&gt;F# のコードフォーマットに関しては以下のスタイルガイドのページがある。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting&quot; title=&quot;F# code formatting guidelines - .NET | Microsoft Learn&quot;&gt;F# code formatting guidelines - .NET | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Fantomas code formatter is the F# community standard tool for automatic code formatting. The default settings correspond to this style guide.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とのことなので、スタイルダイドのお墨付きがある fantomas を使えばそれを簡単に手に入れることができる。&lt;/p&gt;
&lt;p&gt;fantomas を導入したことで意外に「あ、そこの改行もなくなるわけ？」みたいな整形は結構あった。
が、それは気づかないうちに自己流の何かを入れてたわけであり、ある意味導入によってデトックスできたなという気がする。&lt;/p&gt;
&lt;p&gt;あと思わぬ収穫として Ionide の挙動が fantomas の有無で変わるのを確認できた。
具体的には先述した fantomas 導入前後で改行がなくなるようフォーマットされたケースだ。
1 行あたりの文字数が上限未満なら改行を取り払っている様子。
以前は Ionide 内臓の fantomas で整形されてると思ってたが、先述の通りインデントのサイズと改行コードの指定しかなくてそれが変わるのなら、なんかのエッセンスが入ってるのか？
これはちょっと気持ちが悪いので、後追いでも調べたいところ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;F# のフォーマットを入れたのもあって、ついでに &lt;a href=&quot;https://github.com/PowerShell/PSScriptAnalyzer&quot; title=&quot;PSScriptAnalyzer&quot;&gt;PSScriptAnalyzer&lt;/a&gt; で &lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;psake&quot;&gt;psake&lt;/a&gt; のファイルと &lt;a href=&quot;https://github.com/pester/Pester&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; のファイルも整形する気になった。
これらも普段は VS Code の PowerShell 拡張に任せっきりだったが、 CI で整形済みかチェックできるようにした。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/146&quot; title=&quot;#146&quot;&gt;#146&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PSScriptAnalyzer でちょっと面倒だったのが、 PowerShell 拡張が PSScriptAnalyzer のどのルールでチェック・整形されているか分からなかったところだ。
なんかのデフォルト + 追記した &lt;code&gt;powershell.codeFormatting.*&lt;/code&gt; 拡張機能のオプションが反映されてるっぽい。
あんまり真面目に使ったことなかった、すまん PSScriptAnalyzer ... でも今回色々調べたお陰でルールの作り方がわかった。&lt;/p&gt;
&lt;p&gt;PSScriptAnalyzer は、設定を指定しないデフォルトで全ルールのチェックをしてくれるのでそれが一番楽だが、ルールを調整したいときは設定を自前で用意しないといけない。
以下のドキュメントにルールの一覧があるが、その中から必要なものを 1 つずつコピるのは苦行すぎる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/utility-modules/psscriptanalyzer/rules/readme?view=ps-modules&quot; title=&quot;List of PSScriptAnalyzer rules - PowerShell | Microsoft Learn&quot;&gt;List of PSScriptAnalyzer rules - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;その場合に楽なのは、 PSScriptAnalyzer に見込みのデフォルトルールをコピって、必要な変更を加える方法だ。
pocof では v1.21.0 の &lt;code&gt;CodeFormatting.psd1&lt;/code&gt; ↓ を流用し、 &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/utility-modules/psscriptanalyzer/rules/alignassignmentstatement?view=ps-modules&quot; title=&quot;&lt;code&gt;AlignAssignmentStatement&lt;/code&gt;&quot;&gt;&lt;code&gt;AlignAssignmentStatement&lt;/code&gt;&lt;/a&gt; を無効化する等の調整をした。
&lt;a href=&quot;https://github.com/PowerShell/PSScriptAnalyzer/blob/1.21.0/Engine/Settings/CodeFormatting.psd1&quot; title=&quot;PSScriptAnalyzer/Engine/Settings/CodeFormatting.psd1 at 1.21.0 · PowerShell/PSScriptAnalyzer&quot;&gt;PSScriptAnalyzer/Engine/Settings/CodeFormatting.psd1 at 1.21.0 · PowerShell/PSScriptAnalyzer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AlignAssignmentStatement&lt;/code&gt; を有効化していたら ASCII ならキレイにフォーマットされるが、マルチバイト文字があるとその途端ぐちゃぐちゃになる。
これは PSScriptAnalyzer が悪いのではなく、 Go やその他の言語の alignment も同じなので、非英語圏の言語だけの問題なのかも知れない。
というわけで好きじゃないオプションなので、基本無効化する。 pocof でもそうした。
この件は昔ブログに書いた。
&lt;a href=&quot;/posts/2022-05-14-think-about-alignment-of-full-width-chars.html&quot; title=&quot;krymtkts - East Asian な全角文字をキーに使った場合のアラインメントについて考える&quot;&gt;krymtkts - East Asian な全角文字をキーに使った場合のアラインメントについて考える&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;このように作成した設定を読み込ませる方法は、明示的な方法と暗黙的な方法の 2 つある。
PSScriptAnalyzer は &lt;code&gt;Path&lt;/code&gt; オプションで検査対象のスクリプトを指定する。
その指定した &lt;code&gt;Path&lt;/code&gt; のディレクトリに &lt;code&gt;PSScriptAnalyzerSettings.psd1&lt;/code&gt; があれば暗黙的な設定として読み込まれる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/utility-modules/psscriptanalyzer/using-scriptanalyzer?view=ps-modules#implicit&quot; title=&quot;Using PSScriptAnalyzer - PowerShell | Microsoft Learn&quot;&gt;Using PSScriptAnalyzer - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you place a settings file named PSScriptAnalyzerSettings.psd1 in your project root, PSScriptAnalyzer discovers it when you pass the project root as the Path parameter.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;pocof では検査したいスクリプトは 2 つしかなく、しかも別の場所にあるので明示的に &lt;code&gt;Settings&lt;/code&gt; で設定を読み込ませるようにした。&lt;/p&gt;
&lt;p&gt;あと PSScriptAnalyzer の CI でのコケさせ方だが、チェック結果が 1 件以上あれば以上があると判定するようにした。
これはほんとにこれでいいのかよくわからないが、失格したチェックがあってもエラーコードが変わらないし。
少なくともチェックに失格したものがあれば結果が出力されるので、多分あってる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Task Lint {&lt;br /&gt;    dotnet fsharplint lint &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{ModuleName}.sln&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;?) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;dotnet fsharplint failed.&amp;#x27;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    dotnet fantomas ./src &lt;span class=&quot;hljs-literal&quot;&gt;--check&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;?) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;dotnet fantomas failed.&amp;#x27;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# これでいいのか...&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$warn&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-ScriptAnalyzer&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; .\psakefile.ps1 &lt;span class=&quot;hljs-literal&quot;&gt;-Settings&lt;/span&gt; .\PSScriptAnalyzerSettings.psd1&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$warn&lt;/span&gt;) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Invoke-ScriptAnalyzer for psakefile.ps1 failed.&amp;#x27;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$warn&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-ScriptAnalyzer&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; .\tests\pocof.Tests.ps1 &lt;span class=&quot;hljs-literal&quot;&gt;-Settings&lt;/span&gt; .\PSScriptAnalyzerSettings.psd1&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$warn&lt;/span&gt;) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Invoke-ScriptAnalyzer for pocof.Tests.ps1 failed.&amp;#x27;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これでもう機能開発以外の逃げ道はなくなったし、ほんとに pocof 0.10.0 リリースしよう。
あとはガチの未実装機能を実装していくだけ。もう寄り道はなしにしよう(どの口が言うか)。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 25 Feb 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-02-18-writing-cmdlet-in-fsharp-pt32.html</guid><link>https://krymtkts.github.io/posts/2024-02-18-writing-cmdlet-in-fsharp-pt32.html</link><title>F# でコマンドレットを書いてる pt.32</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-02-11-writing-cmdlet-in-fsharp-pt31.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt; 以降バグつぶしや更新漏れに対応した。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/138&quot; title=&quot;#138&quot;&gt;#138&lt;/a&gt; で &lt;code&gt;TopDownHalf&lt;/code&gt; の境界値バグ修正、 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/139&quot; title=&quot;#139&quot;&gt;#139&lt;/a&gt; で長らく放置してた日付のフィルタリングバグ修正をした。
そんでこれまた放置気味だったドキュメント更新を &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/140&quot; title=&quot;#140&quot;&gt;#140&lt;/a&gt; でやった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/139&quot; title=&quot;#139&quot;&gt;#139&lt;/a&gt; の原因は早い話ローカライズされるべきところがされてなかったことによる。
あんまり理解してなかったことなので、ここに改めてメモを残すことにする。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;事象としては、わたしの環境で &lt;code&gt;Get-ChildItem | pocof&lt;/code&gt; したときに、日付を表記通り絞り込めないというバグだった。
プロ .NETer なら多分コレだけで気づくのだろうけど、これは &lt;code&gt;System.DateTime.ToString&lt;/code&gt; がカルチャの書式情報を利用するためだった。&lt;/p&gt;
&lt;p&gt;F# の &lt;code&gt;string&lt;/code&gt; で &lt;code&gt;System.DateTime&lt;/code&gt; に対して使うとカルチャ情報に依存しない形で文字列に変換される。
&lt;a href=&quot;https://github.com/dotnet/fsharp/blob/fd321f3197981276b52b9fd4f16c912e2d5af8f7/src/FSharp.Core/prim-types.fs#L4950&quot; title=&quot;fsharp/src/FSharp.Core/prim-types.fs · dotnet/fsharp&quot;&gt;fsharp/src/FSharp.Core/prim-types.fs · dotnet/fsharp&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;             &lt;span class=&quot;hljs-keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;T&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; DateTime       &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; x &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; (# &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt; value &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; DateTime #) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; x.ToString(&lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;, CultureInfo.InvariantCulture)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;かたや PowerShell は通常カルチャ情報に依存した文字列を表示するので異なる結果になる。&lt;/p&gt;
&lt;p&gt;わたしの環境はちょっとしたこだわりのせいでカルチャ情報をいじっており、 &lt;code&gt;[System.Threading.Thread]::CurrentThread.CurrentCulture&lt;/code&gt; は &lt;code&gt;&amp;quot;en-US&amp;quot;&lt;/code&gt; 相当で、 &lt;code&gt;[System.Threading.Thread]::CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern&lt;/code&gt; を &lt;code&gt;yyyy-MM-dd&lt;/code&gt; に変えてある。
(&lt;code&gt;[System.Threading.Thread]::CurrentThread.CurrentCulture.DateTimeFormat.DateSeparator&lt;/code&gt; も &lt;code&gt;&amp;quot;-&amp;quot;&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;そのためわたしの環境では &lt;code&gt;System.DateTime.ToString&lt;/code&gt; と F# の &lt;code&gt;string System.DateTime&lt;/code&gt; はこんな感じで異なる結果になる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; System.DateTime.Now.ToString();;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; it&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;2024-02-12 17:15:15&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; string System.DateTime.Now;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; it&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;02/12/2024 17:15:22&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ふつーに理解してなかったので pocof では &lt;code&gt;string System.DateTime&lt;/code&gt; してたから、 PowerShell で想定される出力と全然違ってたわけだ。
コレを機にローカライズされた文字列でフィルタリングされるように直ったハズ。&lt;/p&gt;
&lt;p&gt;無知は怖いね。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと CI でも &lt;a href=&quot;https://fsprojects.github.io/FSharpLint/&quot; title=&quot;FSharpLint&quot;&gt;FSharpLint&lt;/a&gt; を使ってみたかったので試してみている。
普段は &lt;a href=&quot;https://ionide.io/&quot; title=&quot;Ionide&quot;&gt;Ionide&lt;/a&gt; で linting されるのを見てるがやはり自前でルールを用意した上で CI でも見たい。
早速試してみたところ、最新の 0.24.0 だと .NET 8 で実行できない issue があるようだった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fsprojects/FSharpLint/issues/687&quot; title=&quot;Execution fails when using dotnet 7.x or 8.x to target net6.0 project · Issue #687 · fsprojects/FSharpLint&quot;&gt;Execution fails when using dotnet 7.x or 8.x to target net6.0 project · Issue #687 · fsprojects/FSharpLint&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;issue にあるように prerelease の 0.24.1--date20240212-1103.git-08ceae7 どっちも試したがダメ。
これは導入諦めて様子見しかないか？と思ったが Ionide の方はなんでうまくいってんのかなと調べてみた。
どうも &lt;a href=&quot;https://github.com/fsharp/FsAutoComplete&quot; title=&quot;FsAutoComplete&quot;&gt;FsAutoComplete&lt;/a&gt; で使ってる &lt;a href=&quot;https://www.nuget.org/packages/FSharpLint.Core/&quot; title=&quot;FSharpLint.Core&quot;&gt;FSharpLint.Core&lt;/a&gt; の version がちょいと古い 0.21.2 なら大丈夫みたい。
packet の lockfile がそんな感じだった。 &lt;a href=&quot;https://github.com/fsharp/FsAutoComplete/blob/de453f7f6292f436e1af769bedef202b6d40930c/paket.lock#L87C22-L87C28&quot; title=&quot;FsAutoComplete/paket.lock · fsharp/FsAutoComplete&quot;&gt;FsAutoComplete/paket.lock · fsharp/FsAutoComplete&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;0.21.x 系なら行けるのかと思いきや 0.21.3 と 0.21.10 試してもエラー。 &lt;code&gt;System.Runtime&lt;/code&gt; 云々出ているので先述の issue に関連するんやろか。
ひとまず linter 導入が先なので、深追いせず一旦ここで留めておく。宿題ということで。&lt;/p&gt;
&lt;p&gt;0.24.0 で出るエラー。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Module: pocof ver0.9.0 root=C:\Users\takatoshi\dev\github.com\krymtkts\pocof\src\pocof\ publish=C:\Users\takatoshi\dev\github.com\krymtkts\pocof\publish\pocof\&lt;br /&gt;Executing Lint&lt;br /&gt;Unhandled exception. System.TypeInitializationException: The type initializer for &amp;#x27;FSharpLint.Console.Program&amp;#x27; threw an exception.&lt;br /&gt; ---&amp;gt; System.TypeInitializationException: The type initializer for &amp;#x27;&amp;lt;StartupCode$dotnet-fsharplint&amp;gt;.$FSharpLint.Console.Program&amp;#x27; threw an exception.&lt;br /&gt; ---&amp;gt; System.TypeInitializationException: The type initializer for &amp;#x27;&amp;lt;StartupCode$Ionide-ProjInfo&amp;gt;.$Library&amp;#x27; threw an exception.&lt;br /&gt; ---&amp;gt; System.ComponentModel.Win32Exception (2): An error occurred trying to start process &amp;#x27;C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe&amp;#x27; with working directory &amp;#x27;C:\Program Files (x86)\Microsoft Visual Studio\Installer&amp;#x27;. The system cannot find the file specified.&lt;br /&gt;...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;0.24.1--date20240212-1103.git-08ceae7 で出るエラー。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Module: pocof ver0.9.0 root=C:\Users\takatoshi\dev\github.com\krymtkts\pocof\src\pocof\ publish=C:\Users\takatoshi\dev\github.com\krymtkts\pocof\publish\pocof\&lt;br /&gt;Executing Lint&lt;br /&gt;Lint failed while analysing pocof.sln.&lt;br /&gt;Failed with: Could not load file or assembly &amp;#x27;System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&amp;#x27;. The system cannot find the file specified.&lt;br /&gt;Stack trace:    at Ionide.ProjInfo.ProjectLoader.loadProject(String path, BinaryLogGeneration binaryLogs, FSharpList`1 globalProperties)&lt;br /&gt;...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;0.21.3 で出るエラー。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Failed to parse file C:\Users\takatoshi\dev\github.com\krymtkts\pocof\src\pocof.Test\Pocof.fs&lt;br /&gt;Exception Message:&lt;br /&gt;The exception has been reported. This internal exception should now be caught at an error recovery point on the stack. Original message: A reference to the type &amp;#x27;System.Runtime.Serialization.ISerializable&amp;#x27; in assembly &amp;#x27;System.Runtime&amp;#x27; was found, but the type could not be found in that assembly)&lt;br /&gt;Exception Stack Trace:&lt;br /&gt;...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;0.21.2 を使う workaround がうまくいったので、 &lt;code&gt;dotnet fsharplint lint pocof.sln&lt;/code&gt; で実行してテストコード含めた全体をチェックすることにする。
ドキュメントに書いてた通りディレクトリは対応してないみたいで、 &lt;code&gt;pocof.sln&lt;/code&gt; を渡すことにした。間違った情報を渡してもエラーにならずサンプル的なのが出る。ちょっとわかりづらい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; dotnet fsharplint lint ./src/pocof&lt;br /&gt;========== Linting /home/user/Dog.Test.fsx ==========&lt;br /&gt;========== Finished: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; warnings ==========&lt;br /&gt;========== Summary: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; warnings ==========
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;warning があると return code が 0 じゃなくなるみたい。
&lt;code&gt;$? = False&lt;/code&gt; になるみたいなのでそういう &lt;code&gt;psakefile.ps1&lt;/code&gt; にしといたら task runner への組み込みも容易そう。
とりま GitHub Actions への組み込みまで目標にやってみるか。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 18 Feb 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-02-11-writing-cmdlet-in-fsharp-pt31.html</guid><link>https://krymtkts.github.io/posts/2024-02-11-writing-cmdlet-in-fsharp-pt31.html</link><title>F# でコマンドレットを書いてる pt.31</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-01-21-writing-cmdlet-in-fsharp-pt30.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;触れた &lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; スタイルのコンソールウィンドウ操作を実装したり、 query window の時間計算量を対数時間 O(logn) にしたり。
それらを含む &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.9.0&quot; title=&quot;pocof version 0.9&quot;&gt;pocof version 0.9&lt;/a&gt; をリリースした。&lt;/p&gt;
&lt;p&gt;いまは高さ半分サイズの UI を実装して、その後の調整や coverage を改善したりしてる。
高さ半分サイズの UI は &lt;code&gt;TopDownHalf&lt;/code&gt;, &lt;code&gt;BottomUpHalf&lt;/code&gt; という &lt;code&gt;Layout&lt;/code&gt; オプションで使えるようにした。
なかなか良いが、端末の高さが変わった場合のレンダリング崩れをどうするかが悩ましく、まだ 0.10.0 リリースはしてない。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;端末の高さが変わった場合のレンダリング崩れは半ば諦めてる。
PSReadLine でも似たようなレンダリング崩れは起こるしな。
ただ個人的に &lt;code&gt;TopDownHalf&lt;/code&gt;, &lt;code&gt;BottomUpHalf&lt;/code&gt; の実装してみて顕著に見えるようになったので気になりはじめた...&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Layout&lt;/code&gt; オプションが &lt;code&gt;TopDownHalf&lt;/code&gt; か &lt;code&gt;BottomUpHalf&lt;/code&gt; の場合、コンソールウィンドウの高さの半分に相当する空行をカーソル位置から挿入し、 pocof 用の UI を用意する。
この高さの半分というのが難しくて、初期表示から終了までにコンソールウィンドウのサイズが変更されて高さが違うこともある。
そのためいずれも現在のコンソールウィンドウの高さを基準に操作する必要がある。
例えば元々高さ 100 だった場合、コンソールウィンドウの高さを縮めて 50 にしたあと終了処理をしたら、残り 50 にはコンソールウィンドウ を縮める前に描画したコンテンツが残っている可能性がある。&lt;/p&gt;
&lt;p&gt;例えば Windows Terminal の場合だと、概ねカーソル位置を上端にして下方向に描画されたコンテンツが取り残される。
また pane を上限分割してサイズ変更するなどで下端からカーソル位置までの高さより縮めた場合にカーソル位置が移動されることがあって、その場合はカーソル位置より前(コンソールウィンドウの外)にコンテンツが取り残されることもある。
そうなると pocof は何も手出しできなくなる。
下方向の残骸は終了処理で画面下端までを初期化すればよいのでなんとかカバーできるが、カーソル位置が強制移動された場合はもうどうにもならん。&lt;/p&gt;
&lt;p&gt;長々と書いたが操作中にコンソールウィンドウのサイズ変更をそんなにするか？というのもあるし、いったんこのままかなあ。
閃きが訪れるまで座して待つか。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;coverage 改善についてはアプリケーションそれ自体の品質には寄与しないが、開発側の安心感やコンプ率欲求のような気持ちみたいなもんをアゲてくれる。
なのでひとまず 90 % 超えときたいなと言うのが最近の目標だった。
pocof は branch coverage についてはそれほど高くないけど line coverage に関してはなるべく網羅したくて取り組んできた。
でも &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pscmdlet?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;PSCmdlet&lt;/code&gt;&quot;&gt;&lt;code&gt;PSCmdlet&lt;/code&gt;&lt;/a&gt; の実装部分は難しくて放置してきた。
今回そこに手を入れようと考えた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.cmdlet?view=powershellsdk-7.4.0&quot; title=&quot;Cmdlet Class&quot;&gt;Cmdlet Class&lt;/a&gt; 実装の場合は、 自前の &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.icommandruntime?view=powershellsdk-7.4.0&quot; title=&quot;ICommandRuntime&quot;&gt;ICommandRuntime&lt;/a&gt; 実装を渡せさえしたら手軽に実行できるようだった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fgimian.github.io/unit-testing-powershell-cmdlets-in-c-sharp/&quot; title=&quot;Unit Testing Powershell Cmdlets in C# - Fotsies Technology Blog&quot;&gt;Unit Testing Powershell Cmdlets in C# - Fotsies Technology Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;でも &lt;code&gt;PSCmdlet&lt;/code&gt; はそう簡単にいかず、 &lt;code&gt;Invoke&lt;/code&gt; すれば &lt;code&gt;Cmdlets derived from PSCmdlet cannot be invoked directly.&lt;/code&gt; を返す。 PowerShell は一筋縄ではいかないんだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/invoking-cmdlets-and-scripts-within-a-cmdlet?view=powershell-7.4&quot; title=&quot;Invoking Cmdlets and Scripts Within a Cmdlet - PowerShell | Microsoft Learn&quot;&gt;Invoking Cmdlets and Scripts Within a Cmdlet - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All cmdlets can invoke an existing cmdlet by calling the System.Management.Automation.Cmdlet.Invoke method from within an input processing method, such as System.Management.Automation.Cmdlet.BeginProcessing, that is overridden by the cmdlet. However, you can invoke only those cmdlets that derive directly from the System.Management.Automation.Cmdlet class. You cannot invoke a cmdlet that derives from the System.Management.Automation.PSCmdlet class.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;であれば自前でテスト機構を作るしかないということで、考えてみた。&lt;/p&gt;
&lt;p&gt;まず以下を継承・実装して mock を作る。これらを &lt;code&gt;PSCmdlet&lt;/code&gt; 実装に差し込めばいい。
これらの実装は利用する箇所以外重要でないので雑でいい。コードが長いし退屈なので省略する。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.icommandruntime?view=powershellsdk-7.4.0&quot; title=&quot;ICommandRuntime Interface (System.Management.Automation) | Microsoft Learn&quot;&gt;ICommandRuntime Interface (System.Management.Automation) | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.host.pshost?view=powershellsdk-7.4.0&quot; title=&quot;PSHost Class (System.Management.Automation.Host) | Microsoft Learn&quot;&gt;PSHost Class (System.Management.Automation.Host) | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.host.pshostuserinterface?view=powershellsdk-7.4.0&quot; title=&quot;PSHostUserInterface Class (System.Management.Automation.Host) | Microsoft Learn&quot;&gt;PSHostUserInterface Class (System.Management.Automation.Host) | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.host.pshostrawuserinterface?view=powershellsdk-7.4.0&quot; title=&quot;PSHostRawUserInterface Class (System.Management.Automation.Host) | Microsoft Learn&quot;&gt;PSHostRawUserInterface Class (System.Management.Automation.Host) | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;次に &lt;code&gt;PSCmdlet&lt;/code&gt; 実装を継承してテスト用のメソッドを生やす。
Cmdlet の肝となる &lt;code&gt;BeginProcessing&lt;/code&gt;, &lt;code&gt;ProcessRecord&lt;/code&gt;, &lt;code&gt;EndProcessing&lt;/code&gt; は public にアクセスできないので、テスト用のメソッドでまとめて呼び出すようにする。
このやり方の場合 &lt;code&gt;ICommandRuntime&lt;/code&gt; 実装から &lt;code&gt;PSHost&lt;/code&gt; を &lt;code&gt;PSCmdlet&lt;/code&gt; 実装の &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pscmdlet.host?view=powershellsdk-7.4.0#system-management-automation-pscmdlet-host&quot; title=&quot;PSCmdlet.Host Property&quot;&gt;PSCmdlet.Host Property&lt;/a&gt; に渡せない。
&lt;code&gt;PSCmdlet.Host&lt;/code&gt; は get のみのプロパティなので、あとから set もできない。
なので自前でどうにかする術が必要になる。&lt;/p&gt;
&lt;p&gt;pocof の場合は &lt;code&gt;PSCmdlet.Host&lt;/code&gt; を &lt;code&gt;PSCmdlet&lt;/code&gt; の実装箇所で参照しているのと、あと PowerShell の処理を呼び出している箇所もある。
それらを mock できるようにするため &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/members/methods&quot; title=&quot;abstract と default&quot;&gt;abstract と default&lt;/a&gt; で再定義可能なメソッドに落とし込んでみた。&lt;/p&gt;
&lt;p&gt;以下のようになる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; SelectPocofCommand &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Xunit&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; FsUnitTyped&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; pocof&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System.Management.Automation&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System.Management.Automation.Host&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;SelectPocofCommandForTest&lt;/span&gt;() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;inherit&lt;/span&gt; SelectPocofCommand()&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// SelectPocofCommand で以下を定義しておく&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// abstract member invoke: &amp;#x27;a list -&amp;gt; string seq&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// abstract member host: unit -&amp;gt; PSHost&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; Host&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PSHost &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Mock.MyHost()&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.invoke(input&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;list&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; input &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Seq.map string&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.host() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; __.Host&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.InvokeForTest() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            __.BeginProcessing()&lt;br /&gt;            __.ProcessRecord()&lt;br /&gt;            __.EndProcessing()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Fact&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``invoke.``&lt;/span&gt; () &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; runtime &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Mock.CommandRuntime()&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; cmdlet &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; SelectPocofCommandForTest()&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; a &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; PowerShell.Create()&lt;br /&gt;&lt;br /&gt;        cmdlet.CommandRuntime &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; runtime &lt;span class=&quot;hljs-comment&quot;&gt;// ないと WriteObject 未実装のエラーになる&lt;/span&gt;&lt;br /&gt;        cmdlet.InputObject &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; PSObject.AsPSObject &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;a&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;]&lt;br /&gt;        cmdlet.NonInteractive &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;        cmdlet.InvokeForTest()&lt;br /&gt;&lt;br /&gt;        runtime.Output &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; shouldEqual [ &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;a&amp;quot;&lt;/span&gt; ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;なんやややこしい感じの実装をして、なおかつ暴力的な解決方法ではあるが、これでなかなかうまくテストできる。
結構手こずったが、 &lt;code&gt;PSCmdlet&lt;/code&gt; 実装の理解も深まった。
ずっと面倒で放置していた &lt;code&gt;PSHostRawUserInterface&lt;/code&gt; の mock 実装もやればできなくないなとわかり、結構手応えのある学びになった。&lt;/p&gt;
&lt;p&gt;そろそろ 0.10.0 リリースするかな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 11 Feb 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-02-04-standard-notes.html</guid><link>https://krymtkts.github.io/posts/2024-02-04-standard-notes.html</link><title>Standard Notes を使いはじめた</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;去年末頃から &lt;a href=&quot;https://standardnotes.com/&quot; title=&quot;Standard Notes&quot;&gt;Standard Notes&lt;/a&gt; を使いはじめた。&lt;/p&gt;
&lt;p&gt;長らく &lt;a href=&quot;https://evernote.com/&quot; title=&quot;Evernote&quot;&gt;Evernote&lt;/a&gt; を使ってたのだけど、 E2E Encryption 対応したメモサービスに乗り換えたいとずっと思ってた。思い立ったのは 2023 入った頃だったような記憶。&lt;/p&gt;
&lt;p&gt;Evernote をずっと使ってたのは、汎用的なテキストエディタからアクセスできる拡張機能があったからだ。
昔 SublimeText 2 ~ 3 を使ってた頃は Evernote の拡張機能があって(&lt;a href=&quot;https://github.com/bordaigorl/sublime-evernote&quot; title=&quot;bordaigorl/sublime-evernote&quot;&gt;bordaigorl/sublime-evernote&lt;/a&gt; かな？)とても優秀な拡張機能だった。
VS Code ではそこまで優秀じゃないが &lt;a href=&quot;https://github.com/michalyao/evermonkey&quot; title=&quot;michalyao/evermonkey&quot;&gt;michalyao/evermonkey&lt;/a&gt; があって、もうアクティブにメンテされてないが最近でもパッチを当てたら使えるので重宝してた。 &lt;a href=&quot;https://gist.github.com/krymtkts/8a5a3a5a7e1efe9db7f2c6bbda337571&quot; title=&quot;Patched version of converterplus.js of evermonkey.&quot;&gt;Patched version of converterplus.js of evermonkey.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;普段遣いするエディタからメモを探せたり書き足せたりできる体験は控えめに言っても最高で、とにかく便利なのだ。&lt;/p&gt;
&lt;p&gt;でもいい加減サービス乗り換え時かなと感じて色々調べていた。
&lt;a href=&quot;https://obsidian.md/&quot; title=&quot;Obsidian&quot;&gt;Obsidian&lt;/a&gt; は課金すれば E2E Encryption を得られるけど、 VS Code から利用できないので汎用的なエディタからのアクセスを諦める必要があった。
他に &lt;a href=&quot;https://skiff.com/&quot; title=&quot;Skiff&quot;&gt;Skiff&lt;/a&gt; は無課金で E2E Encryption が得られるが汎用的なエディタを持ってなかった。 OSS なので気合を入れたら CLI コマンド作ったり VS Code 拡張作れるかな？と思ったが結構重いタスクやなあと思って気が乗らず。
あとメモを置きたいだけなのに対してサービスが多いのも気になった(メールのエイリアス機能は超便利なので調査とかで使ったりする)。&lt;/p&gt;
&lt;p&gt;そうこうしているうちに 2023 後半頃、なんのきっかけか忘れたが Standard Notes を知った(スラドのコメントでかな？)。
無課金で E2E Encryption が得られるのと、 OSS で CLI が既にあって、これはいけそうやなと確信した。
&lt;a href=&quot;https://github.com/jonhadfield/sn-cli&quot; title=&quot;jonhadfield/sn-cli: a command line interface for standard notes&quot;&gt;jonhadfield/sn-cli: a command line interface for standard notes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;試しに sn-cli をちょっとの間使ってみたけど、結構いい感じがする。 CLI でデータが抜けさえすれば VS Code にそれを投げるのも容易いから、ひと手間増えるが便利なのには変わりない。
もっとこなれてきたら sn-cli に依存した VS Code 拡張を書くなんかも考えられる。全部フルで作るよりは重くないだろう。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;sn-cli の利用に際して、 README.md に書かれてるのとは違うインストール方法にしているのと、PowerShell で便利関数の提供をしている感じ。&lt;/p&gt;
&lt;p&gt;インストールはバイナリをダウンロードするのがだるいので、 &lt;code&gt;go install&lt;/code&gt; で &lt;code&gt;latest&lt;/code&gt; をビルドしている。
他にも Go 系のツールをまとめて install / update する関数を PowerShell にこさえていたので、そこにパスを足しただけ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Install-GoModules&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$mods&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;github.com/x-motemen/ghq@latest&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;mvdan.cc/sh/v3/cmd/shfmt@latest&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;github.com/jonhadfield/sn-cli/cmd/sncli@latest&amp;#x27;&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$mods&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$start&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.LastIndexOf(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;/&amp;#x27;&lt;/span&gt;) + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$name&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Substring(&lt;span class=&quot;hljs-variable&quot;&gt;$start&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Length - &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;@latest&amp;#x27;&lt;/span&gt;.Length - &lt;span class=&quot;hljs-variable&quot;&gt;$start&lt;/span&gt;)&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Command&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;*&lt;span class=&quot;hljs-variable&quot;&gt;$name&lt;/span&gt;*&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; SilentlyContinue)) {&lt;br /&gt;            go install &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Update-GoModules&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Command&lt;/span&gt; go &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; SilentlyContinue)) {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Error&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Install go with command below. &amp;#x27;choco install golang -y&amp;#x27;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    ll &lt;span class=&quot;hljs-variable&quot;&gt;$env:GOPATH&lt;/span&gt;/bin | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;        go version &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;br /&gt;    } | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-like&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;*path*&amp;#x27;&lt;/span&gt;&lt;br /&gt;    } | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-StringData&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Delimiter&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`t&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; Values | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;        go install &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{_}@latest&amp;quot;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この方法だとビルド後のコマンドの名前が変わってしまうので、そこは &lt;code&gt;Set-Alias&lt;/code&gt; で吸収する。
あと autocomplete を作っておいたのと、まだ貧弱だが Standard Notes の note を開くための関数を作成した。&lt;/p&gt;
&lt;p&gt;2023 末は bash の autocomplete しかなかった。依存パッケージの &lt;a href=&quot;https://github.com/urfave/cli&quot; title=&quot;urfave/cli&quot;&gt;urfave/cli&lt;/a&gt; が古いものを使ってたからだ。 PowerShell の autocomplete は bash のものをそのまま使えるから自分で書いた。
でも今日見たら PowerShell 版も提供されてた。 &lt;a href=&quot;https://github.com/jonhadfield/sn-cli/blob/24f49af4729c9f5e29b0cd27f94803018f12beea/autocomplete/powershell_autocomplete.ps1&quot; title=&quot;sn-cli/autocomplete/powershell_autocomplete.ps1&quot;&gt;sn-cli/autocomplete/powershell_autocomplete.ps1&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set-Alias&lt;/span&gt; sn &lt;span class=&quot;hljs-literal&quot;&gt;-Value&lt;/span&gt; sncli &lt;span class=&quot;hljs-literal&quot;&gt;-Option&lt;/span&gt; AllScope&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Command&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; sn &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; SilentlyContinue) {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Register-ArgumentCompleter&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Native&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Command&lt;/span&gt; sn &lt;span class=&quot;hljs-literal&quot;&gt;-ScriptBlock&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$wordToComplete&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$commandAst&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$cursorPosition&lt;/span&gt;)&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-Expression&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$commandAst&lt;/span&gt; --generate-bash-completion&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;            [&lt;span class=&quot;hljs-type&quot;&gt;System.Management.Automation.CompletionResult&lt;/span&gt;]::new(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ParameterValue&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;)&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# NOTE: require `sncli session --add` before use this.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Open-SnNotes&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;            [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;,&lt;br /&gt;                &lt;span class=&quot;hljs-type&quot;&gt;Position&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,&lt;br /&gt;                &lt;span class=&quot;hljs-type&quot;&gt;ValueFromPipeline&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;,&lt;br /&gt;                &lt;span class=&quot;hljs-type&quot;&gt;ValueFromPipelineByPropertyName&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;)]&lt;br /&gt;            [&lt;span class=&quot;hljs-type&quot;&gt;ValidateNotNullOrEmpty&lt;/span&gt;()]&lt;br /&gt;            [&lt;span class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;]&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$Title&lt;/span&gt;&lt;br /&gt;        )&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$n&lt;/span&gt; = sn &lt;span class=&quot;hljs-literal&quot;&gt;--use-session&lt;/span&gt; get note &lt;span class=&quot;hljs-literal&quot;&gt;--title&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Title&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$n&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-and&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$n&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-notlike&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;no matches*&amp;#x27;&lt;/span&gt;)) {&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$n&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-Json&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; items | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;                &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.content.text&lt;br /&gt;            } | code -&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この sn-cli の難点があるとしたら、それは検索ワードを入れないと全件ノートを取ってしまうところ。そのあたりは PowerShell の関数でカバーできるから、もうちょっと制限を入れていきたい。
考えてみたら複数ノートから対象を選ぶのは &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; と相性良さそう。
あとメモの追加と更新あたりの PowerShell 関数も書いていきたい。&lt;/p&gt;
&lt;p&gt;今は Evernote のメモの中でも重要なやつだけを Standard Notes に移行した段階で、まだ両方とも利用している。
移行ツールも OSS であるのでそれを使ってもいいのだけど、この際なのでメモの棚卸し兼ねていまは手動でちまちま移している感じ。
全部終わった暁には先に上げた関数を実装して、 VS Code での利用もこなれてきたら更にその先へ、って感じかなー。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 04 Feb 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-01-28-update-oh-my-posh-theme-2024.html</guid><link>https://krymtkts.github.io/posts/2024-01-28-update-oh-my-posh-theme-2024.html</link><title>Oh My Posh のテーマを更新する 2024</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://ohmyposh.dev/&quot; title=&quot;Oh My Posh&quot;&gt;Oh My Posh&lt;/a&gt; が PowerShell だけの v2 から multi shell な v3 になったあと、 PowerShell から JSON の設定に乗り換えた。
2 年ほど前に JSON の自分テーマを作って以降放置してた。
&lt;a href=&quot;https://gist.github.com/krymtkts/d320ff5ec30fa47b138c2df018f95423&quot; title=&quot;My own oh-my-posh v3 theme.&quot;&gt;My own oh-my-posh v3 theme.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;その後設定ファイルに JSON だけじゃなく &lt;a href=&quot;https://yaml.org/&quot; title=&quot;YAML&quot;&gt;YAML&lt;/a&gt; や &lt;a href=&quot;https://toml.io/en/&quot; title=&quot;TOML&quot;&gt;TOML&lt;/a&gt; のサポートもされたのから随分時間が経った。
JSON もシンプルで良いのだけど、いかんせん最後の要素のカンマ調整がめんどくて。個人用途ならまず避けたい。
この機会に設定が微妙な部分とか、 JSON を YAML か TOML のどっちかに変えようと思った次第。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;PowerShell はデフォで ConvertFrom-Json, ConvertTo-Json がある。
更に現時点の PowerShell Gallery には &lt;a href=&quot;https://www.powershellgallery.com/packages/powershell-yaml/0.4.7&quot; title=&quot;powershell-yaml 0.4.7&quot;&gt;powershell-yaml 0.4.7&lt;/a&gt; と &lt;a href=&quot;https://www.powershellgallery.com/packages/PSToml/0.1.0&quot; title=&quot;PSToml 0.1.0&quot;&gt;PSToml 0.1.0&lt;/a&gt; がある。
JSON を YAML や TOML に変換するのは容易い。&lt;/p&gt;
&lt;p&gt;Oh My Posh の設定ファイルを変換するには以下のようにする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# JSON to YAML.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$env:USERPROFILE&lt;/span&gt;/.oh-my-posh.omp.json&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-Json&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-Yaml&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$env:USERPROFILE&lt;/span&gt;/.oh-my-posh.omp.yaml&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# JSON to TOML. use Depth option to avoid truncated result.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$env:USERPROFILE&lt;/span&gt;/.oh-my-posh.omp.json&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-Json&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-Toml&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Depth&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$env:USERPROFILE&lt;/span&gt;/.oh-my-posh.omp.toml&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;個人的に TOML は ini ライクで結構好きなのだけど、こと Oh My Posh の設定ファイルに使うと読みにくすぎる気がした。
先に挙げた自作テーマ JSON は 150 行あるのだけど、 YAML だと 103 行、 TOML だと 134 行になった。
これらはすべて最終行の改行含む。 TOML の場合はヘッダーの前に空行を入れたいので TOML だけ行数での比較は不利な感じだけど。&lt;/p&gt;
&lt;p&gt;Oh My Posh の設定は &lt;a href=&quot;https://ohmyposh.dev/docs/configuration/block&quot; title=&quot;Block&quot;&gt;Block&lt;/a&gt; Array と各 block に入れ子構造の &lt;a href=&quot;https://ohmyposh.dev/docs/configuration/segment&quot; title=&quot;Segment&quot;&gt;Segment&lt;/a&gt; Array や更に入れ子になった &lt;a href=&quot;https://ohmyposh.dev/docs/configuration/segment#properties&quot; title=&quot;properties&quot;&gt;properties&lt;/a&gt; がいる。
これを TOML に置き換えたら &lt;a href=&quot;https://toml.io/en/v1.0.0#array-of-tables&quot; title=&quot;Array of Tables&quot;&gt;Array of Tables&lt;/a&gt; が頻出して、個人的にこれが見にくいと感じるところかな。
TOML が階層と繰り返し構造の組み合わせだとこんなに読みにくくなるとは気づかなかった。
新たな発見や。&lt;/p&gt;
&lt;p&gt;比較として、以下に部分的に一覽してみる。
JSON で &lt;a href=&quot;https://en.wikipedia.org/wiki/Private_Use_Areas&quot; title=&quot;PUA&quot;&gt;PUA&lt;/a&gt; に割り当てられた文字を直書きしてたところは、変換の際にキャラクターコードへと変換されてた。
(アイコングリフが同梱されたフォントを使ってなかったり、自分専用のコードポイントに当たってる箇所は豆腐で表示されるだろうがご了承いただきたい。)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;$schema&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;blocks&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;alignment&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;newline&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;segments&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;foreground&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#839496&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;style&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;plain&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;prompt&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;alignment&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;segments&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;background&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;foreground&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#839496&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;home_icon&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;🏠&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;style&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;mixed&amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;style&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;diamond&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;template&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ .Path }} &amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;background&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#859900&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;foreground&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;powerline_symbol&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\ue0bc&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;azure_devops_icon&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;󿴄 &amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;fetch_stash_count&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;fetch_status&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;fetch_upstream_icon&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;fetch_worktree_count&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;no_commits_icon&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;󿖕 &amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;style&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;powerline&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;template&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; {{ .HEAD }} {{ .BranchStatus }}{{ if .Working.Changed }} \uf044 {{ .Working.String }}{{ end }}{{ if and (.Staging.Changed) (.Working.Changed) }} |{{ end }}{{ if .Staging.Changed }} \uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0}}󿚓 {{ .StashCount }}{{ end }}{{ if gt .WorktreeCount 0}} \uf1bb {{ .WorktreeCount }}{{ end }} &amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;git&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;background&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;background_templates&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ if gt .Code 0 }}red{{ end }}&amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;foreground&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#d33682&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;powerline_symbol&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\ue0bc&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;always_enabled&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;style&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;powerline&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;template&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; {{ if gt .Code 0 }}󿮋  {{ .Meaning }}{{ else }}\uf004 {{ end }} &amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;exit&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;prompt&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-string&quot;&gt;$schema:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;blocks:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;alignment:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;left&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;newline:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;segments:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#839496&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;plain&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;text&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;prompt&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;alignment:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;left&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;segments:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;background:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#839496&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;home_icon:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\U0001F3E0&amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;mixed&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;diamond&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .Path }}&lt;/span&gt; &amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;path&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;background:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#859900&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;powerline_symbol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;azure_devops_icon:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\U000FFD04 &amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;fetch_stash_count:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;fetch_status:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;fetch_upstream_icon:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;fetch_worktree_count:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;no_commits_icon:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\U000FF595 &amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;powerline&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .HEAD }}&lt;/span&gt; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .BranchStatus }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if .Working.Changed }}&lt;/span&gt;  &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .Working.String }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if and (.Staging.Changed) (.Working.Changed) }}&lt;/span&gt; |&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if .Staging.Changed }}&lt;/span&gt;  &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .Staging.String }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if gt .StashCount 0}}&lt;/span&gt;\U000FF693 &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .StashCount }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if gt .WorktreeCount 0}}&lt;/span&gt;  &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .WorktreeCount }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt; &amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;background:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;background_templates:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if gt .Code 0 }}&lt;/span&gt;red&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#d33682&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;powerline_symbol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;always_enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;powerline&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if gt .Code 0 }}&lt;/span&gt;\U000FFB8B  &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .Meaning }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ else }}&lt;/span&gt; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt; &amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;exit&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;prompt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;$schema&amp;quot;&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;console_title_template&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{if .Root}}Admin: {{end}} {{.Folder}}&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;final_space&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;version&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-section&quot;&gt;[[blocks]]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;alignment&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;newline&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;prompt&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-section&quot;&gt;[[blocks.segments]]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;foreground&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#839496&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;style&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;plain&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-section&quot;&gt;[[blocks]]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;alignment&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;left&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;prompt&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-section&quot;&gt;[[blocks.segments]]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;background&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;foreground&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#839496&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;style&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;diamond&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;template&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ .Path }} &amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-section&quot;&gt;[blocks.segments.properties]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;home_icon&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;🏠&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;style&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;mixed&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-section&quot;&gt;[[blocks.segments]]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;background&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#859900&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;foreground&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;powerline_symbol&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;style&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;powerline&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;template&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; {{ .HEAD }} {{ .BranchStatus }}{{ if .Working.Changed }}  {{ .Working.String }}{{ end }}{{ if and (.Staging.Changed) (.Working.Changed) }} |{{ end }}{{ if .Staging.Changed }}  {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0}}󿚓 {{ .StashCount }}{{ end }}{{ if gt .WorktreeCount 0}}  {{ .WorktreeCount }}{{ end }} &amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;git&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-section&quot;&gt;[blocks.segments.properties]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;azure_devops_icon&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;󿴄 &amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;fetch_stash_count&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;fetch_status&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;fetch_upstream_icon&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;fetch_worktree_count&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;no_commits_icon&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;󿖕 &amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-section&quot;&gt;[[blocks.segments]]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;background&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;background_templates&lt;/span&gt; = [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ if gt .Code 0 }}red{{ end }}&amp;quot;&lt;/span&gt;]&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;foreground&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#d33682&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;powerline_symbol&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;style&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;powerline&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;template&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; {{ if gt .Code 0 }}󿮋  {{ .Meaning }}{{ else }} {{ end }} &amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;exit&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-section&quot;&gt;[blocks.segments.properties]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;always_enabled&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;個人的にはこの中なら YAML が一番ましかな...ということで YAML でいくことにした。&lt;/p&gt;
&lt;p&gt;インデントすれば TOML も見やすくなるだろうけど、 JSON や YAML で不要な table 名の繰り返しがきつい。&lt;/p&gt;
&lt;p&gt;あと VS Code だと保存時の format で好きな項目順に並べられないしインデントも消失する。
フォーマットなしで保存するようにしたらいいのかも知れんが、今どき自動フォーマットに従わないのもカッコ悪い。
YAML ならインデントが階層構造を示すし、保存時に項目が並び替わらなかったので、その点も良い。&lt;/p&gt;
&lt;p&gt;Oh My Posh の JSON はコメント書けたけど、 VS Code で編集する時いちいち言語を JSONC に変えないとエラー表示されて面倒だったが、 YAML ならこの悩みはない。&lt;/p&gt;
&lt;p&gt;ひとまず以下のようにした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-string&quot;&gt;$schema:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;console_title_template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if .Root }}&lt;/span&gt;Admin: &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .Folder }}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;final_space:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;blocks:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# First line left.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;prompt&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;newline:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;alignment:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;left&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;segments:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;text&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;plain&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;prompt&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;alignment:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;left&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;segments:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;os&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;background:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#2aa198&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;diamond&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;trailing_diamond:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if .WSL }}&lt;/span&gt;  at &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .Icon }}&lt;/span&gt; &amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;root&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;background:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#b58900&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;diamond&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;trailing_diamond:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;session&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;background:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#2aa198&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#073642&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;diamond&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;trailing_diamond:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;display_host:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .UserName }}&lt;/span&gt; &amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;path&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;background:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#839496&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;mixed&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;diamond&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .Path }}&lt;/span&gt; &amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;git&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;background:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#859900&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;powerline&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;powerline_symbol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;fetch_stash_count:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;fetch_status:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;fetch_upstream_icon:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;fetch_worktree_count:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;github_icon:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;bitbucket_icon:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;no_commits_icon:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;󿖕 &amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .UpstreamIcon }}&lt;/span&gt; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .HEAD }}&lt;/span&gt; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if .BranchStatus }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .BranchStatus }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if .Working.Changed }}&lt;/span&gt;  &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .Working.String }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if and (.Staging.Changed) (.Working.Changed) }}&lt;/span&gt; |&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if .Staging.Changed }}&lt;/span&gt;  &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .Staging.String }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if gt .StashCount 0}}&lt;/span&gt;󿚓 &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .StashCount }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if gt .WorktreeCount 0}}&lt;/span&gt;  &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .WorktreeCount }}&lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt; &amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;text&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;background:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#d33682&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;powerline&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;powerline_symbol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;background_templates:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if gt .Code 0 }}&lt;/span&gt;#dc322f&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground_templates:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if gt .Code 0 }}&lt;/span&gt;#002b36&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;always_enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ if gt .Code 0 }}&lt;/span&gt;󿮋 &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ else }}&lt;/span&gt; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ end }}&lt;/span&gt; &amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# First line right.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;prompt&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;alignment:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;right&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;segments:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;shell&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#93a1a1&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;diamond&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;󿚍 &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .Name }}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;time&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;background:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#002b36&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#839496&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;diamond&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;leading_diamond:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;trailing_diamond:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;time_format:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:04:05&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;MST&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .CurrentDate | date .Format }}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;executiontime&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;background:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#073642&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#839496&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;diamond&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;always_enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &lt;span class=&quot;hljs-template-variable&quot;&gt;{{ .FormattedMs }}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# Second line.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;prompt&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;newline:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;alignment:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;left&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;segments:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;text&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;foreground:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#b58900&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;style:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;plain&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;要らない設定を削り、 2 行レイアウトの 1 行目に情報を詰め込んでみた。
最近 Powerline じゃなくてもいいかもなと感じることあるのだけど、やはり視認性ではこちらに分があるので、情報表示する 1 行目は踏襲。
2 行目は限りなくシンプルに。&lt;/p&gt;
&lt;p&gt;2 行目に慣れてきたら背景色なくして、文字色やアイコングリフだけでも視認性よく感じるかもなー。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 28 Jan 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-01-21-writing-cmdlet-in-fsharp-pt30.html</guid><link>https://krymtkts.github.io/posts/2024-01-21-writing-cmdlet-in-fsharp-pt30.html</link><title>F# でコマンドレットを書いてる pt.30</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2024-01-07-writing-cmdlet-in-fsharp-pt29.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;触れた &lt;code&gt;PSHostRawUserInterface.LengthInBufferCells&lt;/code&gt; を使った full-width character の表示に対応した。
なので、&lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.8.0&quot; title=&quot;pocof version 0.8&quot;&gt;pocof version 0.8&lt;/a&gt; をリリースした。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PSHostRawUserInterface.LengthInBufferCells&lt;/code&gt; で query window の表示域に収まる長さを求めるのに再帰させた。
一発で長さを求められないあたり効率は良くない。
時間計算量が線形時間 O(n) なので、今後せめて二分探索で対数時間 O(logn) にできないか考える。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;pocof の積み Issues は今 4 つある。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/85&quot; title=&quot;#85 Linux support&quot;&gt;#85 Linux support&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/44&quot; title=&quot;#44 Support query string selection&quot;&gt;#44 Support query string selection&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/17&quot; title=&quot;#17 Selection support&quot;&gt;#17 Selection support&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/16&quot; title=&quot;#16 Page up/down support&quot;&gt;#16 Page up/down support&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;こいつはいらんかなと思いだした。 paging が必要なほど件数多いなら query 足して絞るし、なんか余計かなーと&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;今は &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/85&quot; title=&quot;#85 Linux support&quot;&gt;#85 Linux support&lt;/a&gt; を進めてる。&lt;/p&gt;
&lt;p&gt;pocof は &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-2-0&quot; title=&quot;.NET Standard 2.0&quot;&gt;.NET Standard 2.0&lt;/a&gt; をターゲットにしてるので、 Windows PowerShell でも PowerShell (Core 6 以降) でも動くはず。現在の dotnet はほんとすごいな。
でも PowerShell の &lt;code&gt;ConsoleHost&lt;/code&gt; の実装で Windows 以外では &lt;code&gt;NotImplementedException&lt;/code&gt; を投げる箇所がある。
以下に、 Ubuntu on Docker で確認したエラーを Issue から転記する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt; /src&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Pocof&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Select-Pocof&lt;/span&gt;: The method or operation is not implemented.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt; /src&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$ErrorView&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;DetailedView&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt; /src&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Error&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Exception             :&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Type&lt;/span&gt;       : System.NotImplementedException&lt;br /&gt;    TargetSite :&lt;br /&gt;        Name          : GetBufferContents&lt;br /&gt;        DeclaringType : Microsoft.PowerShell.ConsoleHostRawUserInterface, Microsoft.PowerShell.ConsoleHost, Version=&lt;span class=&quot;hljs-number&quot;&gt;7.3&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;10.500&lt;/span&gt;, Culture=neutral, PublicKeyToken=&lt;span class=&quot;hljs-number&quot;&gt;31&lt;/span&gt;bf3856ad364e35&lt;br /&gt;        MemberType    : Method&lt;br /&gt;        Module        : Microsoft.PowerShell.ConsoleHost.dll&lt;br /&gt;    Message    : The method or operation is not implemented.&lt;br /&gt;    Source     : Microsoft.PowerShell.ConsoleHost&lt;br /&gt;    HResult    : &lt;span class=&quot;hljs-literal&quot;&gt;-2147467263&lt;/span&gt;&lt;br /&gt;    StackTrace :&lt;br /&gt;   at Microsoft.PowerShell.ConsoleHostRawUserInterface.GetBufferContents(Rectangle rectangle)&lt;br /&gt;   at System.Management.Automation.Internal.Host.InternalHostRawUserInterface.GetBufferContents(Rectangle &lt;span class=&quot;hljs-built_in&quot;&gt;r&lt;/span&gt;)&lt;br /&gt;   at pocof.PocofScreen.RawUI..ctor(PSHostRawUserInterface rui) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; /src/src/pocof/UI.fs:line &lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;&lt;br /&gt;   at pocof.PocofScreen.init(PSHostRawUserInterface rui, String prompt, FSharpFunc`2 invoke) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; /src/src/pocof/UI.fs:line &lt;span class=&quot;hljs-number&quot;&gt;173&lt;/span&gt;&lt;br /&gt;   at pocof.SelectPocofCommand.interact(InternalConfig conf, InternalState state, Position pos, PSHostRawUserInterface rui, FSharpFunc`2 invoke) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; /src/src/pocof/Library.fs:line &lt;span class=&quot;hljs-number&quot;&gt;44&lt;/span&gt;&lt;br /&gt;   at pocof.SelectPocofCommand.EndProcessing() &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; /src/src/pocof/Library.fs:line &lt;span class=&quot;hljs-number&quot;&gt;191&lt;/span&gt;&lt;br /&gt;CategoryInfo          : NotImplemented: (:) [&lt;span class=&quot;hljs-built_in&quot;&gt;Select-Pocof&lt;/span&gt;], NotImplementedException&lt;br /&gt;FullyQualifiedErrorId : NotImplementedException,pocof.SelectPocofCommand&lt;br /&gt;InvocationInfo        :&lt;br /&gt;    MyCommand        : &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Pocof&lt;/span&gt;&lt;br /&gt;    ScriptLineNumber : &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;    OffsetInLine     : &lt;span class=&quot;hljs-number&quot;&gt;17&lt;/span&gt;&lt;br /&gt;    HistoryId        : &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;    Line             : &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; | pocof&lt;br /&gt;    PositionMessage  : At line:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; char:&lt;span class=&quot;hljs-number&quot;&gt;17&lt;/span&gt;&lt;br /&gt;                       + &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; | pocof&lt;br /&gt;                       +                 ~~~~~&lt;br /&gt;    InvocationName   : pocof&lt;br /&gt;    CommandOrigin    : Internal&lt;br /&gt;ScriptStackTrace      : at &amp;lt;ScriptBlock&amp;gt;, &amp;lt;No file&amp;gt;: line &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;PipelineIterationInfo :
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;NotImplementedException&lt;/code&gt; の発生源はここかなと思ってる。
&lt;a href=&quot;https://github.com/PowerShell/PowerShell/blob/f0076b9d883aa0ed07fb2a5c2be5f38f5d945e1e/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs#L1553-L1563&quot; title=&quot;PowerShell/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs&quot;&gt;PowerShell/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; This API returns a rectangular region of the screen buffer. In&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; this example this functionality is not needed so the method throws&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; a NotImplementException exception.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;param name=&amp;quot;rectangle&amp;quot;&amp;gt;&lt;/span&gt;Defines the size of the rectangle.&lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;///&lt;/span&gt; &lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;Throws a NotImplementedException exception.&lt;span class=&quot;hljs-doctag&quot;&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; BufferCell[,] GetBufferContents(Rectangle rectangle)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; NotImplementedException(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;The method or operation is not implemented.&amp;quot;&lt;/span&gt;);&lt;br /&gt;        }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;ConsoleHostRawUserInterface.cs&lt;/code&gt; の先頭に &lt;code&gt;#if !UNIX&lt;/code&gt; てプリプロセッサディレクティブがあって、前半 Windows 後半その他になってる。これはその他の方。&lt;/p&gt;
&lt;p&gt;そのため、 pocof では Linux の場合(厳密には Mac も含むが確認できない)に work around が必要だった。
今は &lt;code&gt;NotImplementedException&lt;/code&gt; を捕捉した場合は &lt;code&gt;GetBufferContents&lt;/code&gt; 未対応の platform とみなし、エラーを回避する。
この場合、コンソールに表示されているバッファのバックアップと復元はしない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;RawUI&lt;/span&gt;(rui) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; rui&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PSHostRawUserInterface &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; rui&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;TODO:&lt;/span&gt; replace backup/restore buffer contents with scrolling contents for Linux support.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; buf&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; BufferCell [,] &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;&lt;br /&gt;                rui.GetBufferContents(Rectangle(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, rui.WindowSize.Width, rui.CursorPosition.Y))&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; when running on Linux, this exception is thrown.&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;:?&lt;/span&gt; NotImplementedException &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;元々 Windows で動いてるバッファのバックアップと復元も、可視範囲しか対応しないのと復元結果が微妙に壊れるので、イマイチではあるけど。&lt;/p&gt;
&lt;p&gt;この課題を見つけて以降、 dotnet で cross-platform なコンソール操作どうなってんのやと調査を進めていた。
PowerShell で Windows 以外が未実装な機能もあれば、 dotnet 自体で Windows 以外の platform をサポートしないケースもある。
&lt;a href=&quot;https://github.com/dotnet/runtime/issues/23073&quot; title=&quot;Support for Console.MoveBufferArea() on Linux &amp;amp; Mac · Issue #23073 · dotnet/runtime&quot;&gt;Support for Console.MoveBufferArea() on Linux &amp;amp; Mac · Issue #23073 · dotnet/runtime&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;コンソール周りの cross-platform は結構難しくて、 Windows でできることをそのまま他所ではできないのがわかった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;じゃあ pocof では描画域を確保したりバッファを復元したりの操作をどう変えていくべきか、悩ましいところだった。
どう解消すべきかなと調査していたところ、先達の重要なコメントを見つけた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cspotcode/PS-GuiCompletion/issues/13#issuecomment-620084134&quot; title=&quot;PS-GuiCompletion does not work in PowerShell Core 7.0 on Linux · Issue #13 · cspotcode/PS-GuiCompletion&quot;&gt;PS-GuiCompletion does not work in PowerShell Core 7.0 on Linux · Issue #13 · cspotcode/PS-GuiCompletion&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Similar functionality, such as the Menucomplete feature of PSReadLine, work around this limitation by writing several blank lines to the terminal, scolling everything upward and creating an empty region at the bottom of the screen. They draw their &amp;quot;gui&amp;quot; into this empty region, knowing they can erase it entirely when they&amp;#39;re done.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSReadLine&quot; title=&quot;PSReadLine&quot;&gt;PSReadLine&lt;/a&gt; の補完機能で表示されるアレをパクれば良いと。なるほどーって感じ。
でも実装が大変なんでしょ？と思いコードを見に行ったところ、めちゃくちゃシンプルな仕組みだった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSReadLine/blob/e57f7d691d8df8c1121fddf47084f96aea74a688/PSReadLine/DisplayBlockBase.cs#L17-L24&quot; title=&quot;PSReadLine/PSReadLine/DisplayBlockBase.cs at e57f7d691d8df8c1121fddf47084f96aea74a688 · PowerShell/PSReadLine&quot;&gt;PSReadLine/PSReadLine/DisplayBlockBase.cs at e57f7d691d8df8c1121fddf47084f96aea74a688 · PowerShell/PSReadLine&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;            &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;MoveCursorDown&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; cnt&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;            {&lt;br /&gt;                IConsole console = Singleton._console;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (cnt-- &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;br /&gt;                {&lt;br /&gt;                    console.Write(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;);&lt;br /&gt;                }&lt;br /&gt;            }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;改行を印字したらカーソルが 1 行下に進むので、それを必要な高さ分行うだけで描画域を確保できると。
この方法であれば、コンソールのバッファを破壊することもない。&lt;/p&gt;
&lt;p&gt;一点マウススクロールを制限できないのがどうかなーと、はじめは思った。
が、それは今までの pocof が「全画面モーダル」的なアプリだったからそう感じたわけで、これからは「全画面ウィンドウ」的なアプリと捉えればいいだけなのではと思えてきた。
従来であれば可視範囲だけバッファをバックアップするのでスクロールを制限できる代わりに、見えない範囲のバッファを吹っ飛ばす制限があったし。
これが全画面ウィンドウであれば、全画面をやめてバッファと共存するような下半分だけの UI もアリやなというアイデアにつなげることもできる。これは良さそうや。
何ならタイリングレイアウト派なので、自分の用途だと半分 UI の方が向いてそう。&lt;/p&gt;
&lt;p&gt;ということで、 PSReadLine スタイルの描画をプロトタイプしてみた。
まず &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/85#issuecomment-1890919078&quot; title=&quot;PowerShell で雑に書いてみて&quot;&gt;PowerShell で雑に書いてみて&lt;/a&gt;、次に &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/85#issuecomment-1901918776&quot; title=&quot;F# で雑に書いてみた&quot;&gt;F# で雑に書いてみた&lt;/a&gt;。これらは &lt;a href=&quot;https://gist.github.com/krymtkts/52de8e9d4b864db7919d892795486978&quot; title=&quot;Gist&quot;&gt;Gist&lt;/a&gt; に置いた。&lt;/p&gt;
&lt;p&gt;以下は F# 版。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;TailCall&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;rec&lt;/span&gt; readAndDisplay h w arr &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; k &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Console.ReadKey(&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;)&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; arr &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; k &lt;span class=&quot;hljs-operator&quot;&gt;::&lt;/span&gt; arr&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; k.Key &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ConsoleKey.Enter &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;        ()&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; take &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; List.length arr &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt; h &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; List.length arr&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; h&lt;br /&gt;&lt;br /&gt;        arr&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.take take&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.map (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; k &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;[&lt;span class=&quot;hljs-subst&quot;&gt;{k.Key}&lt;/span&gt; - &lt;span class=&quot;hljs-subst&quot;&gt;{k.Modifiers}&lt;/span&gt;]&amp;quot;&lt;/span&gt;)&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.iteri (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; i s &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            Console.SetCursorPosition(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, i)&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; s &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;&lt;span class=&quot;hljs-subst&quot;&gt;{i}&lt;/span&gt; &lt;span class=&quot;hljs-subst&quot;&gt;{s}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            Console.Write(s &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; String.replicate (w &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; String.length s) &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;        readAndDisplay h w arr&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// test script for interactive console window.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// currently cannot prevent mouse scrolling.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; testConsoleWindowWithoutBufferCleaning () &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// backup cursor x position.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; x &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Console.CursorLeft&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// add lines to the end of the screen for scrolling using the PSReadLine method.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; h &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Console.WindowHeight&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; w &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Console.WindowWidth&lt;br /&gt;&lt;br /&gt;    String.replicate (h &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Console.Write&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// write contents.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; yy &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Console.CursorTop&lt;br /&gt;&lt;br /&gt;    Console.SetCursorPosition(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;    [ &lt;span class=&quot;hljs-number&quot;&gt;0.&lt;/span&gt;.yy ]&lt;br /&gt;    &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.map (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; i &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; s &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;Line: %d&lt;span class=&quot;hljs-subst&quot;&gt;{i}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        s &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; String.replicate (w &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; s.Length) &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;)&lt;br /&gt;    &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; String.concat &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Console.Write&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// read and display.&lt;/span&gt;&lt;br /&gt;    readAndDisplay h w []&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// clear contests.&lt;/span&gt;&lt;br /&gt;    [ &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;..&lt;/span&gt; (h &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) ]&lt;br /&gt;    &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.iter (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; i &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;        Console.SetCursorPosition(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, i)&lt;br /&gt;        Console.Write(String.replicate w &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// restore cursor position.&lt;/span&gt;&lt;br /&gt;    Console.SetCursorPosition(x, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;testConsoleWindowWithoutBufferCleaning ()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こんな感じに動く。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2024-01-21-poc\poc-fsharp.gif&quot; title=&quot;F# での PoC キャプチャ&quot; alt=&quot;F# での PoC キャプチャ&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Windows の他に Ubuntu on WSL でも動かしてみた(disk カツカツで Docker やめた)が、良さそう。
前方スクロールしてたとしても、入力をはじめたらカーソル位置の操作が行われて全画面位置に戻る。いい。
これを pocof に組み込んでみて、まずは使ってみる。
違和感なくいけそうなら 0.9 で出すかな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 21 Jan 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-01-14-bump-openssh-chocolatey.html</guid><link>https://krymtkts.github.io/posts/2024-01-14-bump-openssh-chocolatey.html</link><title>Chocolatey で Portable OpenSSH を更新する 2024</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;少し前の話。
2024 を目前にして、久しぶりに Chocolatey に OpenSSH の β が降ってきてた。
&lt;a href=&quot;https://community.chocolatey.org/packages/openssh/9.5.0-beta1&quot; title=&quot;Chocolatey Software | Win32 OpenSSH (Universal Installer) 9.5.0-beta1&quot;&gt;Chocolatey Software | Win32 OpenSSH (Universal Installer) 9.5.0-beta1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;前回は 2023-05 だった。 &lt;a href=&quot;/posts/2023-05-20-bump-openssh-chocolatey.html&quot; title=&quot;2023-05-20 - Chocolatey で Portable OpenSSH を更新する 2023&quot;&gt;2023-05-20 - Chocolatey で Portable OpenSSH を更新する 2023&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2023-05 に自分で bump したとき、 &lt;code&gt;/SSHServerFeature&lt;/code&gt; を使うって書いてた。
でも、これ &lt;code&gt;uninstall-sshd.ps1&lt;/code&gt; で sshd service を消しておいたら &lt;code&gt;/SSHAgentFeature&lt;/code&gt; でもエラーせずに更新できるわ、というのに今更気づいた。
そも sshd が立つのも、自分の PowerShell profile で &lt;code&gt;ssh-agent&lt;/code&gt; のサービスがいないときに &lt;code&gt;install-sshd.ps1&lt;/code&gt; してるからなので。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gitlab.com/DarwinJS/ChocoPackages/-/tree/master/openssh#-params-sshagentfeature&quot; title=&quot;openssh · master · DarwinJS / ChocoPackages · GitLab&quot;&gt;openssh · master · DarwinJS / ChocoPackages · GitLab&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;-params &amp;#39;&amp;quot;/SSHAgentFeature&amp;quot;&amp;#39;&lt;/p&gt;
&lt;p&gt;Installs SSH Agent Service even if SSHD Server is not being installed.
Requires admin rights to configure service.
IMPORTANT: ssh-agent is no longer required for sshd after version openssh 1.0.0.0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ちゃんとドキュメント読んでいこうぜ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 一度 uninstall しておく&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;uninstall-sshd&lt;/span&gt;.ps1&lt;br /&gt;choco uninstall openssh &lt;span class=&quot;hljs-literal&quot;&gt;-y&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 消えたの確認&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Service&lt;/span&gt; ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name,ServiceHandle,DisplayName,ServiceType,StartType&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 入れ直す&lt;/span&gt;&lt;br /&gt;choco install openssh &lt;span class=&quot;hljs-literal&quot;&gt;-params&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;quot;/SSHAgentFeature&amp;quot;&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-y&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Service&lt;/span&gt; ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name,ServiceHandle,DisplayName,ServiceType,StartType&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name          : ssh-agent&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ServiceHandle : Microsoft.Win32.SafeHandles.SafeServiceHandle&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# DisplayName   : ssh-agent&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ServiceType   : Win32OwnProcess&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# StartType     : Automatic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;install-sshd.ps1&lt;/code&gt; で &lt;code&gt;ssh-agent&lt;/code&gt; 入れると、 &lt;code&gt;StartType: Manual&lt;/code&gt; になるから別途 &lt;code&gt;Automatic&lt;/code&gt; に変更する必要があった。
正しい手順ならそのひと手間もいらないぽい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://krymtkts.github.io/posts/2019-03-31-win-openssh-is-gone.html&quot; title=&quot;2019-03-31 - Windows10 の更新で OpenSSH が逝った&quot;&gt;2019-03-31 - Windows10 の更新で OpenSSH が逝った&lt;/a&gt; ではちゃんと &lt;code&gt;/SSHAgentFeature&lt;/code&gt; 使ってた。
なのにその後 &lt;a href=&quot;https://krymtkts.github.io/posts/2019-06-29-season-of-openssh-error.html&quot; title=&quot;2019-06-29 - また OpenSSH が動かなくなる季節がやってきた&quot;&gt;2019-06-29 - また OpenSSH が動かなくなる季節がやってきた&lt;/a&gt; でそれを忘れて &lt;code&gt;install-sshd.ps1&lt;/code&gt; でサービス起動するように変えてた。これがことの発端ぽいな。&lt;/p&gt;
&lt;p&gt;その後 &lt;a href=&quot;/posts/2023-05-20-bump-openssh-chocolatey.html&quot; title=&quot;Chocolatey で Portable OpenSSH を更新する 2023&quot;&gt;Chocolatey で Portable OpenSSH を更新する 2023&lt;/a&gt; で判断を誤る。
&lt;code&gt;/SSHAgentFeature&lt;/code&gt; じゃなく &lt;code&gt;/SSHServerFeature&lt;/code&gt; を使うようになってしまった。
期間が開くと色々ノウハウが失われていく教科書的なパターン。&lt;/p&gt;
&lt;p&gt;今後はちゃんと &lt;code&gt;/SSHAgentService&lt;/code&gt; 使ってやるようにせなあかんな。
ひとまず profile で &lt;code&gt;ssh-agent&lt;/code&gt; サービス立ち上がってなかったら &lt;code&gt;install-sshd.ps1&lt;/code&gt; 流すような記述してたのを消した。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;にしてもわたしの profile も継ぎ足し守られた秘伝のタレ化して、管理が難しくなってきてる。
もう利用してないやつは消したり、必要な初期化は関数小分けにするとかして改善せなあかん時がきたか...&lt;/p&gt;
&lt;p&gt;Gist で 1 ファイルだけ管理してるのも download のやりやすさや更新のしやすさがあっていいけど、なんか他の方法考えなあかんかもな。
古くは VS Code の &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=kenhowardpdx.vscode-gist&quot; title=&quot;Gist&quot;&gt;Gist&lt;/a&gt; 、最近は &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=vsls-contrib.gistfs&quot; title=&quot;GistPad&quot;&gt;GistPad&lt;/a&gt; で編集してる。
楽に編集できて便利やからなー、他の方法としたら git repo があるけどやっぱ手軽さは劣るよな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 14 Jan 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-01-07-writing-cmdlet-in-fsharp-pt29.html</guid><link>https://krymtkts.github.io/posts/2024-01-07-writing-cmdlet-in-fsharp-pt29.html</link><title>F# でコマンドレットを書いてる pt.29</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;2023 年末に &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.7.0&quot; title=&quot;pocof version 0.7&quot;&gt;pocof version 0.7&lt;/a&gt; をリリースした。&lt;/p&gt;
&lt;p&gt;その流れというか冬休みの宿題的に、 2024 年初は積んでた TODO から「長いクエリの場合は描画範囲に収まるよう部分表示する機能」を作ってみた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/105&quot; title=&quot;#105&quot;&gt;#105&lt;/a&gt;
言うなれば、クエリ入力がテキストボックスに長ーいテキストを入れたときと同じ挙動になる機能なのだけど、 query window と名付けてひとまず実装してみた。
まだ &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.host.pshostrawuserinterface.lengthinbuffercells?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;PSHostRawUserInterface.LengthInBufferCells&lt;/code&gt;&quot;&gt;&lt;code&gt;PSHostRawUserInterface.LengthInBufferCells&lt;/code&gt;&lt;/a&gt; を使ってないから full-width character の場合に表示が崩れるのだけど、いい感じぽい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/105&quot; title=&quot;#105&quot;&gt;#105&lt;/a&gt; でざっくり query window を実装したあと、コードを小綺麗にすべく &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/109&quot; title=&quot;#109&quot;&gt;#109&lt;/a&gt; でかなり書き換えた。
他にも諸々のコミットを積んだ。
それもあって詳細な変更に関してまとめることはダルくてできないが、備忘のために要所をまとめておく。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;query window の実現のために最低限必要と判断した要素は以下で、いくつかは新しく追加する必要があった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;クエリ文字列の全長&lt;ul&gt;
&lt;li&gt;クエリの長さを取るだけ&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;クエリ文字列中のカーソル位置&lt;ul&gt;
&lt;li&gt;従来のコンソール上の X 座標を拡張する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;コンソールの幅&lt;ul&gt;
&lt;li&gt;持ってなかったから追加する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;クエリ文字列の描画開始インデックス&lt;ul&gt;
&lt;li&gt;持ってなかったから追加する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;描画域は、コンソールの幅からクエリの状態だとかのシステム情報表示の幅を減算して求める必要がある。&lt;/p&gt;
&lt;p&gt;クエリ文字列の描画開始インデックスは、クエリ文字列の全長から描画域を引いて求める。なのでクエリ文字列の全長が描画行の幅を超えない限りは 0 のままだ。&lt;/p&gt;
&lt;p&gt;クエリ文字列のうち描画するのが、描画開始インデックスから描画域の幅に収まる文字数だけとなる。&lt;/p&gt;
&lt;p&gt;画面上の X 座標は、クエリ文字列中のカーソル位置からクエリ文字列の描画開始インデックスを引いて求める。&lt;/p&gt;
&lt;p&gt;描画域はウィンドウサイズを変更したときのことを考えたらイベントで更新されるようにするのがベストだろうけど、今の pocof ではそのような機構がないので、キー入力後に幅を更新するようにした。&lt;/p&gt;
&lt;p&gt;描画域の変更が必要なのは、ウィンドウサイズの変更以外にもある。
それはクエリの一致方法やら case sensitive にしたりとかの条件を切り替えたとか、クエリを打ち込んで絞り込まれた件数の桁が変わったとか、多岐に渡る。
ほぼ全ての入力操作でそれが起こるので、こまめに描画域の調整をする必要があった。&lt;/p&gt;
&lt;p&gt;そんな感じに玉突きで状態の変更が発生しまくるので、レコードを書き換えて新しいレコードにするコードが大量発生した。&lt;/p&gt;
&lt;p&gt;なのでシンプルに実装したとはとても言えない感じがするけど、ややこしいレコード操作をまとめるためにこまめに module 分けしたので、あとから自分で見てもそこそこ困らなくなったはず。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと諸々のリファクタリングのついでに、計測していたコードカバレッジを &lt;a href=&quot;https://about.codecov.io/&quot; title=&quot;Codecov&quot;&gt;Codecov&lt;/a&gt; へ登録するようにしてみた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/111&quot; title=&quot;#111&quot;&gt;#111&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/codecov/codecov-action&quot; title=&quot;codecov/codecov-action&quot;&gt;codecov/codecov-action&lt;/a&gt; で cobertura の XML を送りつけるだけでいいので楽だ。
ただし composite action の中から secrets にアクセスできないため、以下のように composite action の input にしてやる必要だけあった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;index 01c3b6d..e75a80e 100644&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;--- a/.github/actions/test/action.yml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;+++ b/.github/actions/test/action.yml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -1,6 +1,11 @@&lt;/span&gt;&lt;br /&gt; name: Test&lt;br /&gt; description: Setup .NET, install PowerShell modules and run all tests.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+inputs:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+  codecov_token:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    description: &amp;quot;Codecov token&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    required: true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt; runs:&lt;br /&gt;   using: composite&lt;br /&gt;   steps:&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -16,3 +21,9 @@&lt;/span&gt; runs:&lt;br /&gt;     - name: Execute All Tests&lt;br /&gt;       shell: pwsh&lt;br /&gt;       run: Invoke-Psake -taskList TestAll&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    - name: Upload coverage reports to Codecov&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      uses: codecov/codecov-action@v3&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      with:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        file: ./src/pocof.Test/TestResults/coverage.cobertura.xml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      env:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        CODECOV_TOKEN: ${{ inputs.codecov_token }}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;index be56145..06f2b91 100644&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;--- a/.github/workflows/main.yml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;+++ b/.github/workflows/main.yml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -22,3 +22,5 @@&lt;/span&gt; jobs:&lt;br /&gt;         uses: actions/checkout@v4&lt;br /&gt;       - name: Test&lt;br /&gt;         uses: ./.github/actions/test&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        with:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          codecov_token: ${{ secrets.CODECOV_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;p&gt;他にも勉強がてら &lt;a href=&quot;https://snyk.io/&quot; title=&quot;Snyk&quot;&gt;Snyk&lt;/a&gt; に登録して脆弱性を検査するようにしてみた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/112&quot; title=&quot;#112&quot;&gt;#112&lt;/a&gt;
Codecov のような送りつけるだけに比べると、思ったよりも Snyk はサービスの理解が難しく感じた。&lt;/p&gt;
&lt;p&gt;めちゃくちゃ細かいところだと、例えば対応する package manager 的には dotnet は大丈夫だが、 badge は dotnet に対応してないとか。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://support.snyk.io/hc/en-us/articles/360003997277-Badge-Support-for-Repositories&quot; title=&quot;Badge Support for Repositories – Support Portal | Snyk&quot;&gt;Badge Support for Repositories – Support Portal | Snyk&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/snyk/cli/issues/489&quot; title=&quot;Unable to test GitHub repository-The repository doesn&amp;#39;t exist, or does not contain a relevant manifest file. · Issue #489 · snyk/cli&quot;&gt;Unable to test GitHub repository-The repository doesn&amp;#39;t exist, or does not contain a relevant manifest file. · Issue #489 · snyk/cli&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;まず &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; の方を実験台にしてたので、 dotnet と Node.js の複合プロジェクトだったから気づかなかった。&lt;/p&gt;
&lt;p&gt;あと言語別に分かれた &lt;a href=&quot;https://github.com/snyk/actions&quot; title=&quot;snyk/actions&quot;&gt;snyk/actions&lt;/a&gt; がなにやってるかもはじめは分からなかった。
snyk/actions は、どの言語の action も単に言語の環境を準備してから Snyk CLI を実行するだけ。それがわかったら、あとは Snyk CLI のドキュメントを見るだけなのでやりやすかった。
この仕組みは &lt;a href=&quot;https://github.com/snyk/actions/blob/3e2680e8df93a24b52d119b1305fb7cedc60ceae/dotnet/action.yml&quot; title=&quot;snyk/actions/dotnet/action.yml&quot;&gt;snyk/actions/dotnet/action.yml&lt;/a&gt; を見て理解した。&lt;/p&gt;
&lt;p&gt;特に blog-fable のような複数 package manager で構成される project なら &lt;a href=&quot;https://docs.snyk.io/snyk-cli/commands/test#all-projects&quot; title=&quot;&lt;code&gt;--all-projects&lt;/code&gt;&quot;&gt;&lt;code&gt;--all-projects&lt;/code&gt;&lt;/a&gt; と &lt;a href=&quot;https://docs.snyk.io/snyk-cli/commands/test#exclude-less-than-name-greater-than-less-than-name-greater-than-...greater-than&quot; title=&quot;&lt;code&gt;--exclude&lt;/code&gt;&quot;&gt;&lt;code&gt;--exclude&lt;/code&gt;&lt;/a&gt; を使うのが良さそう。
pocof でも &lt;code&gt;--all-projects&lt;/code&gt; を使った。
pocof は Linux での動作確認用の &lt;code&gt;Dockerfile&lt;/code&gt; を置いてたのもあって、意外に検査対象があったんも勉強になった。&lt;/p&gt;
&lt;p&gt;Snyk は GitHub の code scanning に upload する SARIF ファイルを &lt;a href=&quot;https://docs.snyk.io/snyk-cli/commands/test#sarif-file-output-less-than-output_file_path-greater-than&quot; title=&quot;&lt;code&gt;--sarif-file-output&lt;/code&gt;&quot;&gt;&lt;code&gt;--sarif-file-output&lt;/code&gt;&lt;/a&gt; で出力できる。
main branch への push でアップロードするようにしてみた。&lt;/p&gt;
&lt;p&gt;ほぼ Snyk の文書通りのコピーで良いが、 &lt;code&gt;security-events: write&lt;/code&gt; の permission を足さないといけない。それは GitHub 側の文書でわかった。めんど。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snyk.io/integrate-with-snyk/snyk-ci-cd-integrations/github-actions-for-snyk-setup-and-checking-for-vulnerabilities#github-code-scanning-support&quot; title=&quot;GitHub Actions for Snyk setup and checking for vulnerabilities - Snyk User Docs&quot;&gt;GitHub Actions for Snyk setup and checking for vulnerabilities - Snyk User Docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/enterprise-cloud@latest/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github#example-workflow-for-sarif-files-generated-outside-of-a-repository&quot; title=&quot;Uploading a SARIF file to GitHub - GitHub Enterprise Cloud Docs&quot;&gt;Uploading a SARIF file to GitHub - GitHub Enterprise Cloud Docs&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;pull request 時に脆弱性があったら snyk/actions はエラーにしたい。
でも main branch の push で SARIF ファイルをアップロードする方がエラーになっては困る。
なのでそういったケースでは別々に定義するのが良さそう。
ココまでで Snyk の面倒さが伝わるはずだ。&lt;/p&gt;
&lt;p&gt;あとコレは Snyk に関係ないけど xunit が依存してる &lt;code&gt;NetStandard.Library&lt;/code&gt; 1.6 の依存関係にある脆弱性のおかげで High な脆弱性が検知される。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/xunit/xunit/issues/2778&quot; title=&quot;xunit.runner.utility is still referencing NetStandard.Library 1.6.0 · Issue #2778 · xunit/xunit&quot;&gt;xunit.runner.utility is still referencing NetStandard.Library 1.6.0 · Issue #2778 · xunit/xunit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これを避けるには、 xunit を含む test project の検査をしないか、脆弱性を報告されている package の最新版への依存を追加するかの、どちらかしかない。
検査しないのもどうかなーと思ったので後者で対処した。&lt;/p&gt;
&lt;p&gt;結果は以下の通りになった。
(コメントで snyk を synk に typo してるのは後で直す)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt; .github/workflows/main.yml | 16 ++++++++++++++++&lt;br /&gt; 1 file changed, 16 insertions(+)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;index 06f2b91..deed645 100644&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;--- a/.github/workflows/main.yml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;+++ b/.github/workflows/main.yml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -7,6 +7,7 @@&lt;/span&gt; on:&lt;br /&gt;&lt;br /&gt; permissions:&lt;br /&gt;   contents: read&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+  security-events: write&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; jobs:&lt;br /&gt;   test:&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -24,3 +25,18 @@&lt;/span&gt; jobs:&lt;br /&gt;         uses: ./.github/actions/test&lt;br /&gt;         with:&lt;br /&gt;           codecov_token: ${{ secrets.CODECOV_TOKEN }}&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      - name: Run Snyk to check for vulnerabilities&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        uses: snyk/actions/dotnet@master&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        # synk/actions uses Container action that is only supported on Linux.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        if: runner.os == &amp;#x27;Linux&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        continue-on-error: true # To make sure that SARIF upload gets called&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        env:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        with:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          command: test&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          args: --all-projects --sarif-file-output=snyk.sarif&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      - name: Upload result to GitHub Code Scanning&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        if: runner.os == &amp;#x27;Linux&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        uses: github/codeql-action/upload-sarif@v2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        with:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          sarif_file: snyk.sarif&lt;/span&gt;&lt;br /&gt; .github/workflows/pr.yml | 9 +++++++++&lt;br /&gt; 1 file changed, 9 insertions(+)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;index 8fe46f9..e3305a1 100644&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;--- a/.github/workflows/pr.yml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;+++ b/.github/workflows/pr.yml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -23,3 +23,12 @@&lt;/span&gt; jobs:&lt;br /&gt;         uses: ./.github/actions/test&lt;br /&gt;         with:&lt;br /&gt;           codecov_token: ${{ secrets.CODECOV_TOKEN }}&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+      - name: Run Snyk to check for vulnerabilities&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        # synk/actions uses Container action that is only supported on Linux.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        if: runner.os == &amp;#x27;Linux&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        uses: snyk/actions/dotnet@master&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        env:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        with:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          command: test&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          args: --all-projects&lt;/span&gt;&lt;br /&gt; src/pocof.Test/pocof.Test.fsproj | 3 +++&lt;br /&gt; 1 file changed, 3 insertions(+)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;diff --git a/src/pocof.Test/pocof.Test.fsproj b/src/pocof.Test/pocof.Test.fsproj&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;index 8b56bb8..d7316ae 100644&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;--- a/src/pocof.Test/pocof.Test.fsproj&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;+++ b/src/pocof.Test/pocof.Test.fsproj&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -31,6 +31,9 @@&lt;/span&gt;&lt;br /&gt;     &amp;lt;/PackageReference&amp;gt;&lt;br /&gt;     &amp;lt;!-- NOTE: for creating mock PSObject --&amp;gt;&lt;br /&gt;     &amp;lt;PackageReference Include=&amp;quot;Microsoft.PowerShell.SDK&amp;quot; Version=&amp;quot;7.4.0&amp;quot; /&amp;gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    &amp;lt;!-- NOTE: NOTE: for suppressing vulnerability report the transient dependencies from xunit that depends .NET Standard 1.6. --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    &amp;lt;PackageReference Include=&amp;quot;System.Net.Http&amp;quot; Version=&amp;quot;4.3.4&amp;quot; /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    &amp;lt;PackageReference Include=&amp;quot;System.Text.RegularExpressions&amp;quot; Version=&amp;quot;4.3.1&amp;quot; /&amp;gt;&lt;/span&gt;&lt;br /&gt;   &amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;p&gt;Codecov と Snyk を使うことで 3rd party の token を secrets に保存して使う様になった。
わたしは全然知らなかったが、 &lt;code&gt;pull_request&lt;/code&gt; イベントだと Dependabot は secrets へアクセスできないらしい。この Dependabot が secrets を読めなくなった変更は結構なインパクトあったぽいな。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dependabot/dependabot-core/issues/3253&quot; title=&quot;Dependabot triggered Actions cant access secrets or use a writable token · Issue #3253 · dependabot/dependabot-core&quot;&gt;Dependabot triggered Actions cant access secrets or use a writable token · Issue #3253 · dependabot/dependabot-core&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;pocof のケースだと Dependabot secrets に secrets と同じ内容を定義するだけで済んだ。
この Dependabot が作成した PR で Dependabot secrets にアクセスできるのは文書に書いてないぽい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/working-with-dependabot/configuring-access-to-private-registries-for-dependabot&quot; title=&quot;Configuring access to private registries for Dependabot - GitHub Docs&quot;&gt;Configuring access to private registries for Dependabot - GitHub Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;唯一？この文書がそれっぽいか。でも &lt;code&gt;dependabot.yml&lt;/code&gt; で使えるとは書いてるけど GitHub Actions で使えるとは書いてない。
ただ Dependabot secrets のところには以下のような記載があり、使えそうな雰囲気に見える。いつ GitHub の気が変わって使えなくなるかわからないけど。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dependabot secrets
Secrets are credentials that are encrypted. Anyone with collaborator access to this repository can use these secrets for Dependabot.&lt;/p&gt;
&lt;p&gt;Secrets are not passed to forks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;こういう面倒なところを忌避して &lt;a href=&quot;https://github.com/apps/renovate&quot; title=&quot;Renovate&quot;&gt;Renovate&lt;/a&gt; を使う勢があるというのも理解した。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;なんか色々書いたが、冬休みに色々仕込んだものを早く 0.8 release にしたいところ。
&lt;code&gt;PSHostRawUserInterface.LengthInBufferCells&lt;/code&gt; を使って full-width character の表示に対応したら、 release するようにしようか。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 07 Jan 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2024-01-01-planning.html</guid><link>https://krymtkts.github.io/posts/2024-01-01-planning.html</link><title>2024</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;例年通り目標をたてる。週末まで待っても良かったが、 2024-01-01 の commit なかったのもありコレでまかなう。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;テーマ: 不惑&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;2023 年のテーマは不惑だった。 2024 年もそれでいく。
今後はこのテーマを継続していき、なんかピンポイントで攻略せねばならん障害が発生したら適宜変更することにする。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2024-&quot; href=&quot;#2024-&quot;&gt;2024 年の目標&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;テーマも継続することにしたので、基本的に目標も継続する。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;積読消化 0.5 冊/月を超える&lt;ul&gt;
&lt;li&gt;今年こそやる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;F# の開発&lt;ul&gt;
&lt;li&gt;メインは &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; 。クロスプラットフォーム対応はじめとして今ある Issues を回収したい。今 &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/27&quot; title=&quot;#27&quot;&gt;#27&lt;/a&gt; に着手してるが、クエリ全体の長さに対して表示域という今まで実装してなかった概念を導入することになり重めの修正となる。他の issues も同様に未実装の概念を導入するのでやっかいで、地道に取り組む&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;blog-fable&quot;&gt;blog-fable&lt;/a&gt; はやることがあったらスポットでやる&lt;/li&gt;&lt;li&gt;なんか他にも継続できるネタが有っていいかなと思っている。パッと思いつくネタないけど。もっと F# に突っ込んだなんかやりたいよな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;GitHub のストリークを継続する&lt;ul&gt;
&lt;li&gt;継続できたら 2024 年早々 500 達成できるから、そこの先をさらに狙う。 500 超えたら次の大きなゴールは 1000 よな。ベストを尽くしても達成できるのは来年 2025 年になるけどコツコツ取り組む&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;毎週ブログを書く&lt;ul&gt;
&lt;li&gt;2024 も継続する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;ギター練習を 4 / week&lt;ul&gt;
&lt;li&gt;頻度下げてゆるく継続する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;深酒で怪我をしない&lt;ul&gt;
&lt;li&gt;2023 に続き 0 を目指す&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;自分メンテナンス&lt;ul&gt;
&lt;li&gt;reps 多い筋トレメニューは強度マシで。体重には全然反映されないから強度が高いメニューをこなせるかに注目して取り組む&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;</description><pubDate>Mon, 01 Jan 2024 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-12-31-retrospective2023.html</guid><link>https://krymtkts.github.io/posts/2023-12-31-retrospective2023.html</link><title>振り返り 2023 年</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;2023 年を振り返る。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2023-01-08-planning.html&quot; title=&quot;2023 年のテーマ&quot;&gt;2023 年のテーマ&lt;/a&gt;は「不惑」だった。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2023-&quot; href=&quot;#2023-&quot;&gt;2023 年の目標と成果&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;完全達成とは行かなかったがそこそこいい。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ 転居先を決める&lt;ul&gt;
&lt;li&gt;この話題に触れる回数は増えたけど、わたしは田舎に住んで薪ストーブやりたいのだけど、妻は交通の利便性を確保したいらしくて折り合い付かない。田舎で交通の便いいとこないかな。タイミング的にももう気軽な転居しにくくなってきてるから、今後は目標たてなくて、機会とその必要に応じてやることにする。&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;❌ 積読消化 0.5 冊/月を超える&lt;ul&gt;
&lt;li&gt;年初の早い段階から、仕事で必要になった検索システムの知識を得るために小冊子含めて 2 冊読んだ。だけど、その後携わるテーマが所謂生成 AI に関するものになり読む本がなくなり(Web の文書は読むけど)機会も損失した&lt;/li&gt;&lt;li&gt;あいかわらず自分の読みたいものを積読していくのはほそぼそと続いているので、自分時間をうまく確保してそれを消化すればよいのだけど、できなかった&lt;/li&gt;&lt;li&gt;継続的・強制的な読書習慣の構築には着手した。友人の協力の下、輪読会をはじめた。まだはじめの一冊を終えられてないけど。来年 2024 年の早いうちには終わりそうなので着実に進める&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕ F# を学ぶ&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; と &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; を使った &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;blog-fable&quot;&gt;blog-fable&lt;/a&gt; に半分ずつ取り組めた感じ。なにか新しいチャンレンジしたいってのはこの Fable を使った自ブログの再構築でできたんじゃなかろうか&lt;/li&gt;&lt;li&gt;今年出た F# 8 の更新をすぐ試してみたり、 F# で開発される repo の動向を追ったりとかはできるようになってきた。コードクォートやコンピュテーション式で自前の DSL を書くようなシーンはまだ体験してない。単にまだあんま理解が染み込んでなくて機会を見逃してるのかな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕ GitHub のストリークを継続する&lt;ul&gt;
&lt;li&gt;今年は 365 ストリークを迎えて、きょうで 497 まできた。完全に習慣化されたといって良いだろう&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕ 毎週ブログを書く&lt;ul&gt;
&lt;li&gt;これも完全に習慣化されたと言える。書く頻度をもっと増やす努力をしてもいいかも知れんけど、今の感触だと日々のやることに追われ過ぎて疲れていきそうなので、ゆるく継続する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;❌ ギター練習を 30 分/毎日&lt;ul&gt;
&lt;li&gt;毎日となると気が向かなくてできないことがあった。でも Oura Ring の実績抜きにしても、週に数回仕事が行き詰まったとき頭を切り替えるために弾く習慣にはなった。こういうゆるい継続でいい気がする&lt;/li&gt;&lt;li&gt;だいぶ前にもらった 2000 年はじめ頃の Squire のストラトをちょっとだけレストアしてコーティング弦を張ったところ、他のいかにもメタルギターなラインナップに新鮮味を吹き込んでくれた感ある&lt;/li&gt;&lt;li&gt;ゴツいピックを使うようになってピッキングノイズを避けたくてブリッジ寄りで弾くようになり、 Floyd Rose のファインチューナーが邪魔になってきた(フォームの変更でカバーできるのかもだが)。最近出回ってる Non-Fine Tuner の Floyd Rose 搭載にカスタムしたいな...と思い出す程度には弾いてる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕ 深酒で怪我をしない&lt;ul&gt;
&lt;li&gt;外飲みの機会がそれほどなく、今年は無事故だった。一応 Oura Ring 効果もあるのかな。二日酔いだとスコアすこぶる悪くなるし抑制効果がある&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕ 自分メンテナンス開始&lt;ul&gt;
&lt;li&gt;肌のメンテはやらなかった。単に忙しくて外出しなかっただけ。やっぱやりたいかも&lt;/li&gt;&lt;li&gt;歯のメンテは上の親知らず 2 本を抜いた。抜いてしばらくして歯が減ると認知能力が下がるという話を聞き背筋が凍る思いをしたが...親知らず周りを怪我して口内炎になる機会はめちゃくちゃ減った。昔深酒してぶつけて神経抜いた歯がうずく気がするのでそろそろメンテの時期なのかも。&lt;/li&gt;&lt;li&gt;自重トレーニングは習慣化できて、メニュー偏ってるけど以下のメニューを週に 1,2 回ずつできる感じになった&lt;ul&gt;
&lt;li&gt;フルプッシュアップ 40 reps x 3&lt;/li&gt;&lt;li&gt;フルプルアップ 15 reps x 3&lt;/li&gt;&lt;li&gt;シシースクワット 15 reps x 2&lt;/li&gt;&lt;li&gt;腹筋ローラー 立ちコロ 5 reps x 2&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;いくつかは reps 多いからもっと強度の高いトレーニングに移していい気がする。長い在宅勤務歴によって膝が弱ってるからあまり足を追い込めてなくて、そこも改善したい&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;将来への投資、習慣化、無事故あたりが今年の目標の分類で、特に習慣化に関しては何か知らんがうまくなってる。
何故それができるようになりつつあるのか言語化できてないけど、いい傾向と捉える(あるいはマンネリ化なのかも知れんけど)。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;まとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;それといってビッグイベントなかったから淡々と進んだ感じ。この凪いでる感じがいいのよ。
運が良かったのもあろうけど、昨年からのテーマである「自分の人生は自分で決める」を実現できた上で今年のテーマに注力できたってことだろうから良かったわ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 31 Dec 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-12-24-writing-cmdlet-in-fsharp-pt28.html</guid><link>https://krymtkts.github.io/posts/2023-12-24-writing-cmdlet-in-fsharp-pt28.html</link><title>F# でコマンドレットを書いてる pt.28</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;今年最後の version 0.7 を release に向けて、これまでの TODOs を回収している最中。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/98&quot; title=&quot;#98&quot;&gt;#98&lt;/a&gt;
全部の TODOs を解消できるわけではないけど、前から直したかった 2 点を修正している。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;不正なキーマップの検査&lt;/li&gt;&lt;li&gt;キー入力ごとのクエリ構築を毎回無から構築するのでなくて、入力されたキーに合わせた差分更新をする&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;結構大幅な内部設計の変更を &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/98&quot; title=&quot;#98&quot;&gt;#98&lt;/a&gt; で行う感じ。
これを終えたら version 0.7 を来週の年末休み中にリリースする。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;不正なキーマップの検査は単に &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.cmdlet.endprocessing?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;EndProcessing&lt;/code&gt;&quot;&gt;&lt;code&gt;EndProcessing&lt;/code&gt;&lt;/a&gt; から &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.cmdlet.beginprocessing?view=powershellsdk-7.4.0&quot; title=&quot;&lt;code&gt;BeginProcessing&lt;/code&gt;&quot;&gt;&lt;code&gt;BeginProcessing&lt;/code&gt;&lt;/a&gt; にオプションからのキーマップ構築を移すだけだったけど面倒で放置してた。これを今回サクッと書けそうだったので対応した。&lt;/p&gt;
&lt;p&gt;失敗の可能性があるところは &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/results&quot; title=&quot;&lt;code&gt;Results&lt;/code&gt;&quot;&gt;&lt;code&gt;Results&lt;/code&gt;&lt;/a&gt; を用いて失敗の可能性を示すのが一般的だが、従来は手抜きで &lt;code&gt;failWith&lt;/code&gt; していたので、定石どおり関数の戻り値を &lt;code&gt;Results&lt;/code&gt; に変えた。
これを &lt;code&gt;BeginProcessing&lt;/code&gt; で &lt;code&gt;Error&lt;/code&gt; を捕捉したら &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.argumentexception?view=net-8.0&quot; title=&quot;&lt;code&gt;ArgumentException&lt;/code&gt;&quot;&gt;&lt;code&gt;ArgumentException&lt;/code&gt;&lt;/a&gt; を投げてパラメータの検査としている。&lt;/p&gt;
&lt;p&gt;恥ずかしながら理解してなかったのだけど &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-seqmodule.html#map&quot; title=&quot;&lt;code&gt;Seq.map&lt;/code&gt;&quot;&gt;&lt;code&gt;Seq.map&lt;/code&gt;&lt;/a&gt; や &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-seqmodule.html#fold&quot; title=&quot;&lt;code&gt;Seq.fold&lt;/code&gt;&quot;&gt;&lt;code&gt;Seq.fold&lt;/code&gt;&lt;/a&gt; は順序を保証しない。
&lt;code&gt;Hashtable&lt;/code&gt; を &lt;code&gt;Seq.cast&amp;lt;DictionaryEntry&amp;gt;&lt;/code&gt; して以降は &lt;code&gt;seq&lt;/code&gt; で取り回していたので、エラーメッセージのユニットテスト段階でそれに気づいた。
順序が変わったとて使用に問題はないけど、テストの都度エラーメッセージの順序が変わるのは気持ちが悪いしユニットテストで検査のしようがないから、 &lt;code&gt;Seq.toList&lt;/code&gt; して順序を固定化するようにしている。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -81,25 +81,34 @@&lt;/span&gt; module PocofAction =&lt;br /&gt;&lt;br /&gt;     let convertKeymaps (h: Hashtable) =&lt;br /&gt;         match h with&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        | null -&amp;gt; defaultKeymap&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        | null -&amp;gt; defaultKeymap |&amp;gt; Ok&lt;/span&gt;&lt;br /&gt;         | x -&amp;gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            let source = defaultKeymap |&amp;gt; Map.toSeq&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            let custom =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            let ok, ng =&lt;/span&gt;&lt;br /&gt;                 x&lt;br /&gt;                 |&amp;gt; Seq.cast&amp;lt;DictionaryEntry&amp;gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                |&amp;gt; Seq.map (fun e -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                |&amp;gt; Seq.toList&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                |&amp;gt; List.map (fun e -&amp;gt;&lt;/span&gt;&lt;br /&gt;                     let k = string e.Key |&amp;gt; toKeyPattern&lt;br /&gt;                     let v = string e.Value |&amp;gt; PocofData.Action.fromString&lt;br /&gt;&lt;br /&gt;                     match (k, v) with&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    | (Ok kv, Ok av) -&amp;gt; (kv, av)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    // TODO: enhance error handling.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    | (Error e1, Error e2) -&amp;gt; failwith &amp;lt;| e1 + e2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    | (Ok kv, Ok av) -&amp;gt; Ok(kv, av)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    | (Error e1, Error e2) -&amp;gt; e1 + e2 |&amp;gt; Error&lt;/span&gt;&lt;br /&gt;                     | (Error e, _)&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    | (_, Error e) -&amp;gt; failwith e)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    | (_, Error e) -&amp;gt; Error e)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                |&amp;gt; List.fold&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    (fun (fst, snd) o -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                        match o with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                        | Ok (o) -&amp;gt; (o :: fst, snd)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                        | Error e -&amp;gt; (fst, e :: snd))&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    ([], [])&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            match ok, ng with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            | c, [] -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                let source = defaultKeymap |&amp;gt; Map.toList&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                List.append source c |&amp;gt; Map.ofSeq |&amp;gt; Ok&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            | _, e -&amp;gt; e |&amp;gt; List.rev |&amp;gt; String.concat &amp;quot;\n&amp;quot; |&amp;gt; Error&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            Seq.append source custom |&amp;gt; Map.ofSeq&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;パフォ的にキーマップの入力が尋常に多いエントリ数を持つことも無いだろうし、 &lt;code&gt;List&lt;/code&gt; で問題ないかな。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;キー入力に合わせたクエリの差分更新は結構大改修になってる。
module の分割と関数シグネチャの変更、あと既存のユニットテストの大幅な書き換えが必要になってる。 &lt;code&gt;QueryContext&lt;/code&gt; という型を作って、そこに元々 &lt;code&gt;PocofQuery.run&lt;/code&gt; が内包していた関数などをパーツとして持たせておく。
それを &lt;code&gt;PocofAction&lt;/code&gt; から切り出した &lt;code&gt;PocofHandle.invokeAction&lt;/code&gt; の各入力キーに合わせた処理中で差分更新する。 &lt;code&gt;PocofQuery.run&lt;/code&gt; は渡ってきた &lt;code&gt;QueryContext&lt;/code&gt; を組み立てて実行するだけにした。
これで例えばカーソル移動の場合ならクエリ(&lt;code&gt;Queries&lt;/code&gt;)を初めとした大部分の再構築が不要なので、処理の軽量化になる。&lt;/p&gt;
&lt;p&gt;他の箇所は差分が多くて貼りきれない。あとから詳細を見るときは &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/98/files&quot; title=&quot;#98&quot;&gt;#98&lt;/a&gt; を参照するものとして、ここでは部分的にコードを抜粋しておく。
レコードはこんな感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;TesterType&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; bool) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; list&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; bool&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;QueryContext&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        { Queries&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Query &lt;span class=&quot;hljs-type&quot;&gt;list&lt;/span&gt;&lt;br /&gt;          Test&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; TesterType&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          Is&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;bool&lt;/span&gt;&lt;br /&gt;          Answer&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;bool&lt;/span&gt;&lt;br /&gt;          Notification&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;処理的には良くなってるのだけど、ユニットテストは &lt;code&gt;QueryContext&lt;/code&gt; レコードに関数を持ってる関係でテストしにくい点があって、一部ザルになってる。
before/after でレコードが持つ関数の実行結果を比較したらいいけど、これまただるいな...という感じ。そこを頑張るよりも &lt;code&gt;PocofQuery.run&lt;/code&gt; から個々に分解した関数自体のユニットテストをまだ書いてないから、そこで頑張る方がいいか。&lt;/p&gt;
&lt;p&gt;あと ↑ に貼って思ったけど、 &lt;code&gt;QueryContext.Notification&lt;/code&gt; て此処にあるべきではないな。これは &lt;code&gt;InternalState&lt;/code&gt; に直に書き込んでやったら良さそう。早速直さな。&lt;/p&gt;
&lt;p&gt;この対応によって、 &lt;code&gt;PocofHandle.invokeAction&lt;/code&gt; の戻り値が 3-tuple から 4-tuple になって、 &lt;code&gt;loop&lt;/code&gt; 関数の呼び出しがゴツくなってしまった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -52,8 +53,10 @@&lt;/span&gt; module Pocof =&lt;br /&gt;         |&amp;gt; function&lt;br /&gt;             | Cancel -&amp;gt; []&lt;br /&gt;             | Finish -&amp;gt; unwrap l&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            | Noop -&amp;gt; loop args l s pos NotRequired&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            | a -&amp;gt; invokeAction s pos args.props a |||&amp;gt; loop args l&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            | Noop -&amp;gt; loop args l s pos context NotRequired&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            | a -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                invokeAction s pos context a&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                |&amp;gt; fun (a, b, c, d) -&amp;gt; loop args l a b c d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これは流石にカッコ悪いので、 4-tuple 用のパイプライン演算子を定義してもいいのだけど...&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;inline&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;||||&amp;gt;&lt;/span&gt;) (arg1, arg2, arg3, arg4) func &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; func arg1 arg2 arg3 arg4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;素直に戻り値の構成を見直すのが良さそうと思ってる。
独自に演算子を作るよりは、元々 &lt;code&gt;InternalState&lt;/code&gt; にいても良さそうな &lt;code&gt;refresh&lt;/code&gt; を &lt;code&gt;loop&lt;/code&gt; の引数から削って &lt;code&gt;InternalState&lt;/code&gt; に移動する感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;     let rec loop&lt;br /&gt;         (args: LoopFixedArguments)&lt;br /&gt;         (results: Entry list)&lt;br /&gt;         (state: InternalState)&lt;br /&gt;         (pos: Position)&lt;br /&gt;         (context: QueryContext)&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        (refresh: Refresh)&lt;/span&gt;&lt;br /&gt;         =
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;     type InternalState =&lt;br /&gt;         { Query: string&lt;br /&gt;           QueryState: QueryState&lt;br /&gt;           PropertySearch: PropertySearch&lt;br /&gt;           Notification: string&lt;br /&gt;           SuppressProperties: bool&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-          Properties: string list }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          Properties: string list&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+          Refresh: Refresh }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;どうかな。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;この他にもクエリに利用可能なプロパティ一覧を &lt;code&gt;InternalState&lt;/code&gt; に移動して &lt;code&gt;invokeAction&lt;/code&gt; の引数をスリムにするとかやってる。
なるべく年内納得いく形にまとめて version 0.7 出したいのだけど、アレもコレもとなったら手に負えられないのでどっかで区切りをつけてリリース作業しよう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 24 Dec 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-12-17-writing-cmdlet-in-fsharp-pt27.html</guid><link>https://krymtkts.github.io/posts/2023-12-17-writing-cmdlet-in-fsharp-pt27.html</link><title>F# でコマンドレットを書いてる pt.27</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;ずっと積んでた property の入力補完機能を作った。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/93&quot; title=&quot;#93&quot;&gt;#93&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;まだあんま使えてないが結構お気に入りの機能になった。
だけど、今の実装は引数の取り回しだったり煩雑さが気に入ってなくて、どうにかリファクタリングできないものかと今も思ってる。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;pocof では以下の流れでキー入力から実行コマンドを得て処理を行う。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;入力キーを取得する&lt;/li&gt;&lt;li&gt;入力キーを文字入力・ショートカット・制御キーに選り分ける&lt;/li&gt;&lt;li&gt;選り分けたキーを実行コマンドに変換する&lt;/li&gt;&lt;li&gt;実行コマンドに引数を与えて実行する&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;今回の対応では、 4 のところでプロパティの一覧から候補のプロパティを導出するようにした。
なので ↓ のように 4 の関数にはプロパティ一覧の引数を持つのだけど、この引数を使うのがプロパティ補完コマンドのみのため、そこがモヤっている。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/93/files#diff-26d312725989d78a4a961c9534ee973d8f64f3acd92b1eae7077af806601a962R381-R402&quot; title=&quot;このへん&quot;&gt;このへん&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; invokeAction (state&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; InternalState) (pos&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; Position) (props&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;list&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この最後の引数がなあ...&lt;/p&gt;
&lt;p&gt;3 の実行コマンドへ変換するときに bind してもいいんじゃないかという気がせんでもない。
でも今度はそこにプロパティ一覧の引数が増えるだけで、問題を別の場所に押し付けただけになってしまう。
結局どっかのタイミングでプロパティ一覧を bind しないといけないし、 pocof 起動後はプロパティ一覧が変わることはないから起動したタイミングで bind すべきだったのかも...
bind したとて引数の数減らんけどな。&lt;/p&gt;
&lt;p&gt;悩みは多いが、プロパティ補完自体は上記でクリアした。&lt;/p&gt;
&lt;p&gt;プロパティを補完したあとは、補完前の入力キーワードにマッチする候補を TAB とかで切り替えられるのが一般的なので、その実装もしている。&lt;/p&gt;
&lt;p&gt;プロパティ補完の仕組み自体は大したことなくて、以下のような判別共用体を用意してそれぞれの状況に応じた処理を &lt;code&gt;match&lt;/code&gt; で行うだけにしている。
非補完時は &lt;code&gt;NonSearch&lt;/code&gt; &lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; 、 プロパティ検索時は &lt;code&gt;Search&lt;/code&gt; 、
候補切り替え用に &lt;code&gt;Rotate&lt;/code&gt; がある。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Search&lt;/code&gt; にはキーワードを保持していて、そのキーワードで始まるプロパティに絞り込んだ結果をクエリ入力の下の行に表示している。これは既存の実装。
&lt;code&gt;Rotate&lt;/code&gt; にはキーワード、選択中の index 、候補のリストを保持していて、これらを使えばマッチする候補を TAB 押下時に順繰り出力できる。これが今回追加した実装。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;PropertySearch&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; NonSearch&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Search &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; Rotate &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;文で書いたらシンプルだけど、この補完機能を担う関数がちょっとデカくて(&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/93/files#diff-26d312725989d78a4a961c9534ee973d8f64f3acd92b1eae7077af806601a962R339-R379&quot; title=&quot;これ&quot;&gt;これ&lt;/a&gt;)見た目にも分かりづらいかもなと思ってたりする。なんかスリムにしたい...
debug log を仕込んだ事もあって余計に見にくい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;前回 Linux 用ビルドができたら alpha 外したリリースしたいな～といってたけどもうあんま年内時間残ってないし、この補完機能が組めたのもあるから、今の状態でリリースしたいお気持ちに変わった。
コピペ時の動作が改善されておりかつ補完機能があるから、はよ自分の他の PC でも使いたい、という欲望に駆られての判断。&lt;/p&gt;
&lt;p&gt;ひとまず &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/95&quot; title=&quot;#95&quot;&gt;#95&lt;/a&gt; でリファクタリングはじめて、こまいバグも見つかってるから、いい感じに進めて 2023 年末リリースしよ。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;この名前も今思えばイマイチで &lt;code&gt;Noop&lt;/code&gt; か &lt;code&gt;Normal&lt;/code&gt; でいいんじゃないかな。 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 17 Dec 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-12-10-writing-cmdlet-in-fsharp-pt26.html</guid><link>https://krymtkts.github.io/posts/2023-12-10-writing-cmdlet-in-fsharp-pt26.html</link><title>F# でコマンドレットを書いてる pt.26</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;.NET 8 へ更新して、 F# 8 の機能を使ってみた。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;SDK の更新ちょっといい手順がよくわからんのよな。
pocof の場合は以下でやった。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/88&quot; title=&quot;#88&quot;&gt;#88&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet new globaljson &lt;span class=&quot;hljs-literal&quot;&gt;--sdk-version&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--roll-forward&lt;/span&gt; latestFeature &lt;span class=&quot;hljs-literal&quot;&gt;--force&lt;/span&gt;&lt;br /&gt;dotnet add ./src/pocof.Test package Microsoft.PowerShell.SDK &lt;span class=&quot;hljs-literal&quot;&gt;--version&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;7.4&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;test project の方は &lt;code&gt;TargetFramework&lt;/code&gt; も &lt;code&gt;net8.0&lt;/code&gt; にしたのだけど、本体の方はやめておいた。
なぜかというと &lt;code&gt;netstandard2.0&lt;/code&gt; にして Windows PowerShell もサポートしてみたいなという気持ちが突如湧き、そのようにしたからだ。&lt;/p&gt;
&lt;p&gt;参考までに、 lockfile を生成している blog-fable の場合だと以下の手順になった。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/120/files&quot; title=&quot;krymtkts/blog-fable#120&quot;&gt;krymtkts/blog-fable#120&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;hljs-code&quot;&gt;```powershell&lt;br /&gt;dotnet new globaljson --sdk-version 8.0.100 --roll-forward latestFeature --force&lt;br /&gt;```&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;remove these from &lt;span class=&quot;hljs-code&quot;&gt;`App.fsproj`&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-code&quot;&gt;```xml&lt;br /&gt;    &amp;lt;RestorePackagesWithLockFile&amp;gt;true&amp;lt;/RestorePackagesWithLockFile&amp;gt;&lt;br /&gt;    &amp;lt;RestoreLockedMode&amp;gt;true&amp;lt;/RestoreLockedMode&amp;gt;&lt;br /&gt;```&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-code&quot;&gt;```powershell&lt;br /&gt;dotnet clean&lt;br /&gt;fable clean&lt;br /&gt;npm run build&lt;br /&gt;# build success.&lt;br /&gt;```&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;restore &lt;span class=&quot;hljs-code&quot;&gt;`App.fsproj`&lt;/span&gt; configuration.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-code&quot;&gt;```powershell&lt;br /&gt;npm run build&lt;br /&gt;# lockfile regenerated successfully.&lt;br /&gt;```&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このように、まず &lt;code&gt;fsproj&lt;/code&gt; でロックしない設定にしてからビルドしないと、 F# の DLL の lockfile が期待のとおりにならなくてエラーを解消できなかった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;さて、ここまで来てようやく F# 8 の機能が使えるようになった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/announcing-fsharp-8/&quot; title=&quot;Announcing F# 8 - .NET Blog&quot;&gt;Announcing F# 8 - .NET Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上記のアナウンスを参考にして、 Nested record field update 、 &lt;code&gt;_.Property&lt;/code&gt; shorthand と `TailCall`` attribute を導入してみた。
&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/90&quot; title=&quot;#90&quot;&gt;#90&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;     let private switchMatcher (state: InternalState) =&lt;br /&gt;         { state with&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            QueryState =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                { state.QueryState with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                    Matcher =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                        match state.QueryState.Matcher with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                        | EQ -&amp;gt; LIKE&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                        | LIKE -&amp;gt; MATCH&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                        | MATCH -&amp;gt; EQ } }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            InternalState.QueryState.Matcher =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                match state.QueryState.Matcher with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                | EQ -&amp;gt; LIKE&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                | LIKE -&amp;gt; MATCH&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                | MATCH -&amp;gt; EQ }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;書き換えるときに良さは感じなかったけど、これ実際に書くときに良さを感じるはず。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;                         |&amp;gt; Seq.head&lt;br /&gt;                         |&amp;gt; PSObject.AsPSObject&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-                        |&amp;gt; (fun o -&amp;gt; o.Properties)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                        |&amp;gt; _.Properties&lt;/span&gt;&lt;br /&gt;                 | _ -&amp;gt; o.Properties)&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-            |&amp;gt; Seq.map (fun p -&amp;gt; p.Name)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            |&amp;gt; Seq.map _.Name&lt;/span&gt;&lt;br /&gt;             |&amp;gt; Seq.fold (fun acc n -&amp;gt; acc.Add n) properties
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;もうこれは書き換えるときでも読みやすくなったなって感じがするわな。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TailCall&lt;/code&gt; attribute に関しては、 module 直下の関数かメソッドしか使えないみたい。関数内の関数に付与した場合、それが末尾再帰になってなくても警告されない。
どっかで文書を見かけた気がするのだけど今探したら見つけられなかった。なんしか自分で動作確認をしてそうなってるというのは確認している。
だからこれを使うためだけに関数内の関数を外に出した。&lt;/p&gt;
&lt;p&gt;やっぱこういう検査機構は、ミスってないお墨付きがつくから気持ちが良い。
もちろん今回付与した部分も大丈夫だった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あとこの流れの中で PowerShell Gallery へ up してる配布物が pdb を含んだままになってると気づいたので、 DL サイズ下げたいしなくすことにした。&lt;/p&gt;
&lt;p&gt;以下の文書を参考に設定した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-properties?view=vs-2022&quot; title=&quot;Common MSBuild Project Properties - MSBuild | Microsoft Learn&quot;&gt;Common MSBuild Project Properties - MSBuild | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;PropertyGroup&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Condition&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;#x27;$(Configuration)&amp;#x27; == &amp;#x27;Release&amp;#x27; &amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;DebugType&lt;/span&gt;&amp;gt;&lt;/span&gt;none&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;DebugType&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;DebugSymbols&lt;/span&gt;&amp;gt;&lt;/span&gt;false&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;DebugSymbols&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;PropertyGroup&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これでちょっとだけ配信サイズが縮んだ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;もうそろそろ次のリリースをしていい加減 alpha 外したい気持ちがしてきた。
でもせめて Linux 用ビルドができからやりたいなーという気持ちもあり、年内どう最後を締めるか悩んでる。
目標届かなくても改善点は細々あるし、なんなら .NET Standard 2.0 まで下げたのもあるから、出していいと思うけどなー。気持ちの面が邪魔してくる。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 10 Dec 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-12-03-rebuild-blog-with-fable-pt20.html</guid><link>https://krymtkts.github.io/posts/2023-12-03-rebuild-blog-with-fable-pt20.html</link><title>Fable でブログを再構築する pt.20</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; で作った &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; の手直し。&lt;/p&gt;
&lt;p&gt;細かすぎる修正は置いといて主だったものだけ記す。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;もう 2 週前になるのだけど、 &lt;a href=&quot;https://github.com/highlightjs/highlight.js/blob/6317acd780bfe448f75393ea42d53c0149013274/src/styles/base16/solarized-dark.css&quot; title=&quot;highlight.js の Solarized dark の CSS&quot;&gt;highlight.js の Solarized dark の CSS&lt;/a&gt; を CDN から引っ張ってきてたけど、 blog-fable の生成物へ同梱するようにした。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/112&quot; title=&quot;#112&quot;&gt;#112&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;CDN に分かれてたら &lt;code&gt;package.json&lt;/code&gt; のバージョン更新に追随し忘れることもあるし、試した感じどうも GitHub Pages だとまとめて配信するほうが速いっぽいし。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;node_modules&lt;/code&gt; 配下の &lt;code&gt;highlight.js&lt;/code&gt; には minified な CSS が用意されてるのでそれをそのままコピった。
SCSS もあったので、試しに自前で &lt;code&gt;sass --style=compressed --no-source-map&lt;/code&gt; 指定してビルドしてみたけど、ビミョーにデカくなったのでやめた。
これは highlight.js をチラ見した感じ &lt;code&gt;sass&lt;/code&gt; は使ってないから。
スタイルを編集してること無いしそのまま利用で OK 。&lt;/p&gt;
&lt;p&gt;これで外部への依存がリンクくらいしかなくなったはず。随分とスッキリしたな。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと Markdown の脚注を有効にするの忘れてたので、 追加した。
過去の記事で数カ所脚注を使ってて、今後もたまに使うだろうしあった方がいいかなあと思ってのこと。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/markedjs/marked&quot; title=&quot;marked&quot;&gt;marked&lt;/a&gt; は Markdown の標準に脚注がないから対応してない。
&lt;a href=&quot;https://github.github.com/gfm/&quot; title=&quot;GitHub Flavored Markdown(gfm)&quot;&gt;GitHub Flavored Markdown(gfm)&lt;/a&gt; みたいに脚注をサポートしたいなら Extension を使うのが筋らしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/markedjs/marked/issues/714&quot; title=&quot;Is &amp;quot;footnote&amp;quot; supported in marked.js? · Issue #714 · markedjs/marked&quot;&gt;Is &amp;quot;footnote&amp;quot; supported in marked.js? · Issue #714 · markedjs/marked&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ちょうど最近 &lt;a href=&quot;https://github.com/bent10/marked-extensions/tree/b82985fc0c2c71287d69a9063464a740396ad5f3/packages/footnote&quot; title=&quot;&lt;code&gt;marked-footnote&lt;/code&gt;&quot;&gt;&lt;code&gt;marked-footnote&lt;/code&gt;&lt;/a&gt; といういいのを作った人がいて、それをそのまま採用させてもらった。
デフォだと脚注にでかいタイトルが付くのだけど、これは accessibility のためっぽい。でもあまりにもでかいし見出しは不要かなと思って水平ラインに置き換えた。スマン。&lt;/p&gt;
&lt;p&gt;あと脚注に Markdown の link 記法 &lt;code&gt;[nanigashi](https://example.com)&lt;/code&gt; を含むと正常に脚注を出力できないバグがあった。
対象の脚注が &lt;code&gt;[&lt;/code&gt; を含む場合に正規表現で捕まえたい対象を逃してしまうというやつなのだけど、長めのパターンを直して PR するの面倒かもなと思って Issue を送ってみた。 &lt;a href=&quot;https://github.com/bent10/marked-extensions/issues/23&quot; title=&quot;Issue #23 · bent10/marked-extensions&quot;&gt;Issue #23 · bent10/marked-extensions&lt;/a&gt;
そしたらすぐに対応してもらえて、とても助かった。&lt;/p&gt;
&lt;p&gt;使う node module はそんな感じで、次は Fable でどう使うかってところ。
これに関しては、 Marked Extension に限定する限りは fable binding 書くメリットあんまないと感じてて、 &lt;code&gt;obj&lt;/code&gt; をそのまま使った。&lt;/p&gt;
&lt;p&gt;一点 &lt;a href=&quot;https://github.com/markedjs/marked-highlight&quot; title=&quot;marked-highlight.js&quot;&gt;marked-highlight.js&lt;/a&gt; と違って extension を作成する関数が &lt;code&gt;export default&lt;/code&gt; になってた。
この場合は対応する &lt;code&gt;importDefault&lt;/code&gt; で取り込んであげないと対象が見つからない。
(この点 marked-highlight.js は大量に export されてるうちの 1 つだったから &lt;code&gt;importMember&lt;/code&gt;を使ってる)&lt;/p&gt;
&lt;p&gt;以下のように &lt;code&gt;obj&lt;/code&gt; をパラメータにして &lt;code&gt;MarkedExtension&lt;/code&gt; を返す定義する。
option の指定は型ありのときと変わらず匿名レコードで行って、&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; markedFootnote&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; Marked.MarkedExtension &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; importDefault &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;marked-footnote&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// 使うとき&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; footNote &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; markedFootnote &lt;span class=&quot;hljs-operator&quot;&gt;!!&lt;/span&gt;{&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; description &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;lt;hr /&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ただし間違ってても検査できないのが玉に瑕。でも局所的だしいちいち書くほどでもないかなと思って。その内気が変わるかもだけど&lt;/p&gt;
&lt;p&gt;だいぶ npm module を Fable で使うときの取り回しに慣れてきた気がする～嬉しい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 03 Dec 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-11-26-writing-cmdlet-in-fsharp-pt25.html</guid><link>https://krymtkts.github.io/posts/2023-11-26-writing-cmdlet-in-fsharp-pt25.html</link><title>F# でコマンドレットを書いてる pt.25</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;デバッグモードがほしいなと言っていたやつ &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/81&quot; title=&quot;#81&quot;&gt;#81&lt;/a&gt;&lt;/li&gt;&lt;li&gt;あと Linux で pocof を動作確認するための container image を作るやつ &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/84&quot; title=&quot;#84&quot;&gt;#84&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;デバッグモードに関しては、バグレポートをもらうときとかに &lt;code&gt;-Verbose&lt;/code&gt; スイッチみたいに有効化したいシーンが想定される(pocof の場合 console に情報を出力できないからログファイル出力)。
けど今のところ開発時に確認できる程度で良くて、 compiler directive で良さそうかなと思ってそうした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/compiler-directives&quot; title=&quot;Compiler Directives - F# | Microsoft Learn&quot;&gt;Compiler Directives - F# | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これでサクッとログのファイル出力がされるようにしたのだけど、ちょっと弊害もあった。
&lt;code&gt;dotnet test&lt;/code&gt; で実行されるテストってマルチプロセスかマルチスレッドで実行されるみたいで、単一のファイルへの書き込みだと &lt;code&gt;System.IO.Exception&lt;/code&gt; する。
回避のために、パフォ影響考えずにロックを掛けることで複数プロセスでの書き込みのエラーを発生しなくした。
MSBuild でプロセス数を絞れるみたいなので、それ使ったらいいのかも知れんけど。 &lt;a href=&quot;https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-command-line-reference?view=vs-2022#switches&quot; title=&quot;MSBuild Command-Line Reference - MSBuild | Microsoft Learn&quot;&gt;MSBuild Command-Line Reference - MSBuild | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;あくまで手軽にデバッグビルドで有効にするだけのログなのでこういう回避もアリかなと。&lt;/p&gt;
&lt;p&gt;あと &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/caller-information&quot; title=&quot;Caller information&quot;&gt;Caller information&lt;/a&gt; を使ってログを賑やかした。
初めて試したみたけど &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.defaultparametervalueattribute?view=net-7.0&quot; title=&quot;&lt;code&gt;DefaultParameterValue&lt;/code&gt;&quot;&gt;&lt;code&gt;DefaultParameterValue&lt;/code&gt;&lt;/a&gt; などは関数には使えなくてメソッドしかダメみたいね。 C# との相互運用が目的ならそらそうか。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/parameters-and-arguments#optional-parameters&quot; title=&quot;Parameters and Arguments - F#&quot;&gt;Parameters and Arguments - F#&lt;/a&gt; 見る限り関数のサンプルないしな。&lt;/p&gt;
&lt;p&gt;先述のドキュメントだけでわからない点は fslang-design を見るのが良さそう。
今のところ IL の話まで理解する必要はないかも知れんけど、期待されるパターンが書いてあり、理解が深まる。
&lt;a href=&quot;https://github.com/fsharp/fslang-design/blob/main/FSharp-4.1/FS-1027-complete-optional-defaultparametervalue.md&quot; title=&quot;fslang-design/FSharp-4.1/FS-1027-complete-optional-defaultparametervalue.md at main · fsharp/fslang-design&quot;&gt;fslang-design/FSharp-4.1/FS-1027-complete-optional-defaultparametervalue.md at main · fsharp/fslang-design&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Caller information 出してみた効果は使ってみて判断する。 ただ RFC3339 形式の日時出力も足したしそれだけは使えそう。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;次は Linux の container image を作るやつ。
初めは以下の MS 謹製 PowerShell image に dotnet 足したらいいかなと思ってたが、結構面倒だった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hub.docker.com/_/microsoft-powershell&quot; title=&quot;PowerShell by Microsoft | Docker Hub&quot;&gt;PowerShell by Microsoft | Docker Hub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;何が面倒って dotnet 7 の最新バージョン(7.0.404 とか)が distro の repository にあるとは限らないこと。
最新を使いたければ Microsoft の repository を引き込む必要がある。
試しに Alpine Linux, Ubuntu で見てみたけど 7.0.1xx なので pocof の &lt;code&gt;global.json&lt;/code&gt; の条件満たしてねえ。&lt;/p&gt;
&lt;p&gt;自力で追加するなら Linux でのインストール方法 (&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/install/linux-ubuntu#register-the-microsoft-package-repository&quot; title=&quot;.NET and Ubuntu overview - .NET | Microsoft Learn&quot;&gt;.NET and Ubuntu overview - .NET | Microsoft Learn&lt;/a&gt;)を Dockerfile に焼き直すだけ。
なのだけど、めんどしこんなん世界で誰かが既にやってるやろと思って container image を探した。&lt;/p&gt;
&lt;p&gt;結局 dotnet の Linux container image が dotnet 完備で PowerShell も新しくて楽なので採用した。これサイコー。
&lt;a href=&quot;https://hub.docker.com/_/microsoft-dotnet-sdk/&quot; title=&quot;.NET SDK by Microsoft | Docker Hub&quot;&gt;.NET SDK by Microsoft | Docker Hub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ただサイズがデカイ... 1.5GB もあった。&lt;/p&gt;
&lt;p&gt;ひとまず Linux の PowerShell 環境を手に入れたので、 pocof を対話モードで動かしてみたところ、以下のエラーを得た。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;PS /src&amp;gt; Get-ChildItem | Select-Pocof&lt;br /&gt;Select-Pocof: The method or operation is not implemented.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;前から unit test と &lt;a href=&quot;https://github.com/pester/Pester&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; による非対話モードのテストは Windows, Linux, Mac いずれも成功してる。
cross platform の対話モード依存のエラーってことかな。
対応できてないやろなと想像はしてたけど、やっぱ動いてなかったので Issue を作成。&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/85&quot; title=&quot;#85&quot;&gt;#85&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;エラーの詳細を見たら &lt;code&gt;Microsoft.PowerShell.ConsoleHostRawUserInterface.GetBufferContents&lt;/code&gt; がダメみたい。まじか。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;PS /src&amp;gt; $ErrorView = &amp;#x27;DetailedView&amp;#x27;&lt;br /&gt;PS /src&amp;gt; $Error&lt;br /&gt;&lt;br /&gt;Exception             :&lt;br /&gt;    Type       : System.NotImplementedException&lt;br /&gt;    TargetSite :&lt;br /&gt;        Name          : GetBufferContents&lt;br /&gt;        DeclaringType : Microsoft.PowerShell.ConsoleHostRawUserInterface, Microsoft.PowerShell.ConsoleHost, Version=7.3.10.500, Culture=neutral, PublicKeyToken=31bf3856ad364e35&lt;br /&gt;        MemberType    : Method&lt;br /&gt;        Module        : Microsoft.PowerShell.ConsoleHost.dll&lt;br /&gt;    Message    : The method or operation is not implemented.&lt;br /&gt;    Source     : Microsoft.PowerShell.ConsoleHost&lt;br /&gt;    HResult    : -2147467263&lt;br /&gt;    StackTrace :&lt;br /&gt;   at Microsoft.PowerShell.ConsoleHostRawUserInterface.GetBufferContents(Rectangle rectangle)&lt;br /&gt;   at System.Management.Automation.Internal.Host.InternalHostRawUserInterface.GetBufferContents(Rectangle r)&lt;br /&gt;   at pocof.PocofScreen.RawUI..ctor(PSHostRawUserInterface rui) in /src/src/pocof/UI.fs:line 55&lt;br /&gt;   at pocof.PocofScreen.init(PSHostRawUserInterface rui, String prompt, FSharpFunc`2 invoke) in /src/src/pocof/UI.fs:line 173&lt;br /&gt;   at pocof.SelectPocofCommand.interact(InternalConfig conf, InternalState state, Position pos, PSHostRawUserInterface rui, FSharpFunc`2 invoke) in /src/src/pocof/Library.fs:line 44&lt;br /&gt;   at pocof.SelectPocofCommand.EndProcessing() in /src/src/pocof/Library.fs:line 191&lt;br /&gt;CategoryInfo          : NotImplemented: (:) [Select-Pocof], NotImplementedException&lt;br /&gt;FullyQualifiedErrorId : NotImplementedException,pocof.SelectPocofCommand&lt;br /&gt;InvocationInfo        :&lt;br /&gt;    MyCommand        : Select-Pocof&lt;br /&gt;    ScriptLineNumber : 1&lt;br /&gt;    OffsetInLine     : 17&lt;br /&gt;    HistoryId        : 2&lt;br /&gt;    Line             : Get-ChildItem | pocof&lt;br /&gt;    PositionMessage  : At line:1 char:17&lt;br /&gt;                       + Get-ChildItem | pocof&lt;br /&gt;                       +                 ~~~~~&lt;br /&gt;    InvocationName   : pocof&lt;br /&gt;    CommandOrigin    : Internal&lt;br /&gt;ScriptStackTrace      : at &amp;lt;ScriptBlock&amp;gt;, &amp;lt;No file&amp;gt;: line 1&lt;br /&gt;PipelineIterationInfo :
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;似てそうな Issue みつけたけど transcript してないしな。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PowerShell/issues/1920&quot; title=&quot;Unix system executables terminate with error if transcription enabled · Issue #1920 · PowerShell/PowerShell&quot;&gt;Unix system executables terminate with error if transcription enabled · Issue #1920 · PowerShell/PowerShell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今ん所は &lt;code&gt;NotImplementedException&lt;/code&gt; を検知した場合の workaround として pocof 開く前のバッファの復元をしないようにして、最小限の Linux 対応とした。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/86&quot; title=&quot;#86&quot;&gt;#86&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Linux でもバッファの復元したいし、もうちょっと調査する。
&lt;a href=&quot;https://github.com/PowerShell/PowerShell/blob/811efa46df822bf7be6179b6219f9f9d160eb7d5/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs#L1560&quot; title=&quot;PowerShell/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs のこの箇所&quot;&gt;PowerShell/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs のこの箇所&lt;/a&gt;見るに単純に実装されてなかったりして...&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;この container iamge 試行錯誤の影響で、自機の 256 GB しかない記憶領域の残が 1 GB を切ってしまった。やば。
直ちに container image の掃除と VHD を圧縮することにした。
Windows 11 Home だと &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/hyper-v/optimize-vhd?view=windowsserver2022-ps&quot; title=&quot;&lt;code&gt;Optimize-VHD&lt;/code&gt;&quot;&gt;&lt;code&gt;Optimize-VHD&lt;/code&gt;&lt;/a&gt; が使えないので、以下のように &lt;code&gt;diskpart&lt;/code&gt; というコマンドを使うらしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/microsoft/WSL/issues/4699#issuecomment-627133168&quot; title=&quot;WSL 2 should automatically release disk space back to the host OS · Issue #4699 · microsoft/WSL&quot;&gt;WSL 2 should automatically release disk space back to the host OS · Issue #4699 · microsoft/WSL&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ここで &lt;code&gt;attach&lt;/code&gt;, &lt;code&gt;detach&lt;/code&gt; なくてもできるみたい。動的に拡張できる VHD なので readonly いらんのかな。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stephenreescarter.net/how-to-shrink-a-wsl2-virtual-disk/&quot; title=&quot;How to Shrink a WSL2 Virtual Disk – Stephen Rees-Carter&quot;&gt;How to Shrink a WSL2 Virtual Disk – Stephen Rees-Carter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/compact-vdisk&quot; title=&quot;compact vdisk | Microsoft Learn&quot;&gt;compact vdisk | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Remarks&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A dynamically expanding VHD must be selected for this operation to succeed. Use the select vdisk command to select a VHD and shift the focus to it.&lt;/li&gt;&lt;li&gt;You can only use compact dynamically expanding VHDs that are detached or attached as read-only.&lt;/li&gt;&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;単純な手順を示すとこんな感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;docker system prune &lt;span class=&quot;hljs-literal&quot;&gt;--all&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--force&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# 掃除しきる&lt;/span&gt;&lt;br /&gt;wsl &lt;span class=&quot;hljs-literal&quot;&gt;--shutdown&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Resolve-Path&lt;/span&gt;  ~\AppData\Local\Docker\wsl\data\ext4.vhdx | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Clipboard&lt;/span&gt;&lt;br /&gt;diskpart &lt;span class=&quot;hljs-comment&quot;&gt;# 以降 diskpart との対話&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# select vdisk file=&amp;quot;paste here&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# compact vdisk&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このように diskpart の窓の中でコマンド打たないといけないのは非常にだるい。ここは例に倣ってスクリプト化しておきたい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/diskpart-scripts-and-examples&quot; title=&quot;diskpart scripts and examples | Microsoft Learn&quot;&gt;diskpart scripts and examples | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;以下に試作した手順を記す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Docker Desktop も dockerd も立ち上がってない前提&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Start-Process&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;C:\Program Files\Docker\Docker\resources\dockerd.exe&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-WindowStyle&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Hidden&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# dockerd がいれば docker cli は動かせる&lt;/span&gt;&lt;br /&gt;docker system prune &lt;span class=&quot;hljs-literal&quot;&gt;--all&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--force&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Process&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;*dockerd*&amp;quot;&lt;/span&gt; | % {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Kill();&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.WaitForExit()&lt;br /&gt;}&lt;br /&gt;wsl &lt;span class=&quot;hljs-literal&quot;&gt;--shutdown&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$vdisk&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Resolve-Path&lt;/span&gt;  ~\AppData\Local\Docker\wsl\data\ext4.vhdx&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$tmp&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{env:Temp}/diskpart.txt&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-string&quot;&gt;@&amp;quot;&lt;br /&gt;select vdisk file=&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$vdisk&lt;/span&gt;&amp;quot;&lt;br /&gt;compact vdisk&lt;br /&gt;&amp;quot;@&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$tmp&lt;/span&gt;&lt;br /&gt;diskpart /s &lt;span class=&quot;hljs-variable&quot;&gt;$tmp&lt;/span&gt; &amp;gt; ./log.txt&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; ./log.txt | &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Remove-Item&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$tmp&lt;/span&gt;,./log.txt
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;少なくとも &lt;code&gt;docker ~&lt;/code&gt; ってコマンドを打つだけなら &lt;code&gt;dockerd.exe&lt;/code&gt; が立ち上がってさえいれば OK 。
なので VHD の圧縮だけならこんな感じでいけそうなのだけど、 Docker Desktop の起動・終了の制御だけ全くわからんくて調査中。
同時に Docker Desktop が立ち上がってるとどのみちこいつを graceful に殺さねば &lt;code&gt;wsl --shutdown&lt;/code&gt; で Docker Desktop がエラーダイアログ出してくる。
&lt;code&gt;com.docker.backend.exe&lt;/code&gt; が全てを司ってるのはわかったけど、こいつをどのように御せばいいのかわからん。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;次、積み残し Issue やりたいなと思いつつも、 .NET 8 来たし更新するのが先かな。
F# 8 に新しく来た &lt;code&gt;_.Property&lt;/code&gt; shorthand と nested record field copy and update は pocof でもすぐ取り入れたいしな。
&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/announcing-fsharp-8/&quot; title=&quot;Announcing F# 8 - .NET Blog&quot;&gt;Announcing F# 8 - .NET Blog&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 26 Nov 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-11-19-writing-cmdlet-in-fsharp-pt24.html</guid><link>https://krymtkts.github.io/posts/2023-11-19-writing-cmdlet-in-fsharp-pt24.html</link><title>F# でコマンドレットを書いてる pt.24</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;描画部分で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.host.pshostrawuserinterface?view=powershellsdk-7.3.0&quot; title=&quot;&lt;code&gt;PSHostRawUserInterface&lt;/code&gt;&quot;&gt;&lt;code&gt;PSHostRawUserInterface&lt;/code&gt;&lt;/a&gt; をそのまま取り回してたところに一層別の型を噛まして、ちょっとだけ unit test を書けるようにした。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/73&quot; title=&quot;#73&quot;&gt;#73&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PSHostRawUserInterface&lt;/code&gt; の mock をそのまま書こうものなら大量のメソッドを実装することになりそうだし、一層噛まして楽にできたと思う。
まだ触り程度の test しか書いてないけど、あるとないでは天地の差よ。&lt;/p&gt;
&lt;p&gt;この対応の中でおもしろかったのが、 platform 違いを体感できたこと。
キー入力周りの .NET の cross platform の挙動の違いだったりバグについては .NET ブログかなんかで見たことがあったのだけど、今回初めてほんまに違うんやなと実感した。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PSHostRawUserInterface&lt;/code&gt; を wrap した型の mock を unit test で書いたのだけど、そこでたまたま既存コードのコピペで &lt;code&gt;Console.TreatControlCAsInput&lt;/code&gt; を使ったところがあった。
これ、 Windows でのみアクセス時に &lt;code&gt;System.IO.IOException : The handle is invalid.&lt;/code&gt; が発生する。 Linux や Mac ではこの不正な handler は発生せずテストが成功していた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/actions/runs/6838909170&quot; title=&quot;Refactor PocofScreen. · krymtkts/pocof@3de1579&quot;&gt;Refactor PocofScreen. · krymtkts/pocof@3de1579&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;以下こけてた Windows のログを抜粋。 &lt;a href=&quot;https://github.com/krymtkts/pocof/actions/runs/6838909170/job/18596749738#step:5:66&quot; title=&quot;test (windows-latest) · krymtkts/pocof@3de1579&quot;&gt;test (windows-latest) · krymtkts/pocof@3de1579&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;[xUnit.net 00:00:01.01]     PocofUI+Buff writeScreen.should render top down. [FAIL]&lt;br /&gt;  Error Message:&lt;br /&gt;   System.IO.IOException : The handle is invalid.&lt;br /&gt;  Stack Trace:&lt;br /&gt;     at System.ConsolePal.get_TreatControlCAsInput()&lt;br /&gt;   at PocofUI.MockRawUI..ctor() in D:\a\pocof\pocof\src\pocof.Test\PocofUI.fs:line 19&lt;br /&gt;   at PocofUI.Buff writeScreen.should render bottom up.() in D:\a\pocof\pocof\src\pocof.Test\PocofUI.fs:line 70&lt;br /&gt;   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)&lt;br /&gt;   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;CLI のハンドラのなんかが起こってるのは間違いなそうやけど何も解決策分からず。 unit test なので実際に CLI の in/out を司る者がいないからこうなるんやろけど。
mock やし単に true が欲しかっただけの箇所なので、 &lt;code&gt;Console.TreatControlCAsInput&lt;/code&gt; を利用しないようにさえすれば起こらないのでそう直した。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと別件で、 .NET 8 がリリースされ PowerShell 7.4 が出たことで &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.PowerShell.SDK/7.4.0&quot; title=&quot;&lt;code&gt;Microsoft.PowerShell.SDK&lt;/code&gt; 7.4.0&quot;&gt;&lt;code&gt;Microsoft.PowerShell.SDK&lt;/code&gt; 7.4.0&lt;/a&gt; が来てた。
&lt;code&gt;dependabot.yml&lt;/code&gt; の設定がまずかったからその変更で PR を作られてしまった。
.NET 7 のままだからか &lt;code&gt;Microsoft.PowerShell.SDK&lt;/code&gt; を利用してる箇所のテストコードが null reference でクラッシュするという事態に。
&lt;a href=&quot;https://github.com/krymtkts/pocof/actions/runs/6896506479/job/18808902758&quot; title=&quot;Bump the test-lib group with 2 updates · krymtkts/pocof@acf0c31&quot;&gt;Bump the test-lib group with 2 updates · krymtkts/pocof@acf0c31&lt;/a&gt;
すまん dependabot-san 。&lt;/p&gt;
&lt;p&gt;こういうインパクトの大きい更新は自分でやるから、 &lt;code&gt;Microsoft.PowerShell.SDK&lt;/code&gt; と &lt;code&gt;PowerShellStandard.Library&lt;/code&gt; の patch version しか受けないよう変更した。
.NET と PowerShell のバージョンが相互に関係し合うのは知ってるけど、他に利用してる NuGet module がどう影響受けるか把握してないので、ちょくちょく着手していきたい。
ゆーても Chocolatey には 7.4 の更新きてるのを確認して自機の PowerShell 7.4 に上げたばっかりなので、ちょっと後で。&lt;/p&gt;
&lt;p&gt;(余談やけど &lt;a href=&quot;https://www.nuget.org/packages/PowerShellStandard.Library/7.0.0-preview.1&quot; title=&quot;&lt;code&gt;PowerShellStandard.Library&lt;/code&gt; 7.0.0-preview.1&quot;&gt;&lt;code&gt;PowerShellStandard.Library&lt;/code&gt; 7.0.0-preview.1&lt;/a&gt; が unlisted なの初めて知った。
&lt;a href=&quot;https://github.com/PowerShell/PowerShellStandard/blob/59998dced0948864a33fe6aed5f0a07bd12a91a6/src/dotnetTemplate/Microsoft.PowerShell.Standard.Module.Template/Microsoft.PowerShell.Standard.Module.Template/Microsoft.PowerShell.Standard.Module.Template.csproj#L9&quot; title=&quot;Microsoft.PowerShell.Standard.Module.Template&quot;&gt;Microsoft.PowerShell.Standard.Module.Template&lt;/a&gt; からは参照されたままなのだけど数年動き無いしどうなるんやろ。)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/blob/7dd35cdadeed14444fa85608eba256c6be24d82a/.github/dependabot.yml&quot; title=&quot;pocof/.github/dependabot.yml&quot;&gt;pocof/.github/dependabot.yml&lt;/a&gt; から NuGet module のところだけ抜粋。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;package-ecosystem:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;nuget&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;directory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;schedule:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;interval:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;weekly&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;day:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;friday&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;time:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;06:00&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;timezone:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Asia/Tokyo&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;groups:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;pwsh-std:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;patterns:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;PowerShellStandard.Library&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;update-types:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;patch&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;pwsh-sdk:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;patterns:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Microsoft.PowerShell.SDK&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;update-types:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;patch&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;test-lib:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;patterns:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;exclude-patterns:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;PowerShellStandard.Library&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Microsoft.PowerShell.SDK&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ignore:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;dependency-name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;PowerShellStandard.Library&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;update-types:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;version-update:semver-major&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;version-update:semver-minor&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;dependency-name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Microsoft.PowerShell.SDK&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;update-types:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;version-update:semver-major&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;version-update:semver-minor&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;assignees:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtkts&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;reviewers:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtkts&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このように特定のモジュールの major minor update を除外したいとなると、&lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups&quot; title=&quot;&lt;code&gt;groups&lt;/code&gt;&quot;&gt;&lt;code&gt;groups&lt;/code&gt;&lt;/a&gt; の指定だけではできない。
明示的に &lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#ignore&quot; title=&quot;&lt;code&gt;ignore&lt;/code&gt;&quot;&gt;&lt;code&gt;ignore&lt;/code&gt;&lt;/a&gt; に該当モジュールを入れないと個別に PR 送る対象になってしまうので、なんか煩雑な感じの記述になった。&lt;/p&gt;
&lt;p&gt;dependabot-san の設定変更できつかったのが、 main branch に &lt;code&gt;dependabot.yml&lt;/code&gt; が反映されないと内容の検査ができないところ。
まだ linter とかの検証方法無いよな？ そういう Issue も開いたままだし。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dependabot/dependabot-core/issues/4605&quot; title=&quot;Make it possible to validate Dependabot config before it lands on &lt;code&gt;main&lt;/code&gt; · Issue #4605 · dependabot/dependabot-core&quot;&gt;Make it possible to validate Dependabot config before it lands on &lt;code&gt;main&lt;/code&gt; · Issue #4605 · dependabot/dependabot-core&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;何度もやり直すのはまあ良しとしても、きついのは PR 作りまくったり Git の履歴が汚れるところ。
なんかいい方法ないんかいな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 19 Nov 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-11-12-writing-cmdlet-in-fsharp-pt23.html</guid><link>https://krymtkts.github.io/posts/2023-11-12-writing-cmdlet-in-fsharp-pt23.html</link><title>F# でコマンドレットを書いてる pt.23</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;p&gt;作り始めた頃からずっと放置してた bottom up のレイアウトに対応した。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/72&quot; title=&quot;#72&quot;&gt;#72&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;自分で Issue 作っといてなんやけど、当初よりコレある意味あんのかな？という感じがしてて、やり始めるまで気乗りしなかった。
しかしいざ手を動かしてみたら top down と部分的に違うだけでほぼ同じやし、長らく放置してた pocof の描画部分を思い出すのにもちょうどいいかもなと思えてきた。
久しぶりに pocof の開発する通過儀礼としてはいい感じだった。
あと逆さまに検索内容が表示されるのも案外面白かったので、あってもいいかなコレという気にはなれた。&lt;/p&gt;
&lt;p&gt;描画部分を久しぶりに触ったので &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.host.pshostrawuserinterface?view=powershellsdk-7.3.0&quot; title=&quot;&lt;code&gt;PSHostRawUserInterface&lt;/code&gt;&quot;&gt;&lt;code&gt;PSHostRawUserInterface&lt;/code&gt;&lt;/a&gt; をそのまま取り回してるから unit test 書けない(書きづらい)ねんよなというのも思い出した。
でも今になって見た感じだと、&lt;code&gt;PSHostRawUserInterface&lt;/code&gt; をくるんだ型を作っといて一層挟んであげればどうにかなるなと言う感触がする。&lt;/p&gt;
&lt;p&gt;検索で絞り込んだ内容をデバッグログに出力する機能も長らく作ってなくて、開発時にはてきとーに開発用のコードを挟んでたりしたので、そのへんも合わせてリファクタリングしたいなーという気持ちになってきた。&lt;/p&gt;
&lt;p&gt;今回 top down / bottom up に対応した描画ロジックは以下の通り。
&lt;a href=&quot;https://github.com/krymtkts/pocof/blob/d68a172ffb6ca94fc7751fca2fc624d1e9683c16/src/pocof/UI.fs#L64-L120&quot; title=&quot;pocof/src/pocof/UI.fs&quot;&gt;pocof/src/pocof/UI.fs&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; __.writeScreen&lt;br /&gt;            (layout&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PocofData.Layout)&lt;br /&gt;            (state&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PocofData.InternalState)&lt;br /&gt;            (x&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;)&lt;br /&gt;            (entries&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; PocofData.Entry &lt;span class=&quot;hljs-type&quot;&gt;list&lt;/span&gt;)&lt;br /&gt;            (props&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;list&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt;)&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; basePosition, firstLine, toHeight &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; 主にいじったのここ。 layout に応じて作られた let binding を使うように全体調整しただけ&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; layout &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; PocofData.TopDown &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, (&lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt;) &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; PocofData.BottomUp &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; basePosition &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; __.rui.WindowSize.Height &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; こういう PSHostRawUserInterface に直接アクセスする部分を取り除く&lt;/span&gt;&lt;br /&gt;                    basePosition, basePosition &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, (&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;) (basePosition &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;            __.writeScreenLine basePosition&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;|&lt;/span&gt; __.prompt &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; state.Query&lt;br /&gt;&lt;br /&gt;            __.writeRightInfo state entries.Length basePosition&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; これオプションでどうにかする&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// PocofDebug.logFile &amp;quot;./debug.log&amp;quot; [ List.length entries ]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            __.writeScreenLine firstLine&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; state.Notification &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;               &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                   &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; props &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                   &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Ok&lt;/span&gt; (p) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; (String.concat &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt; p).[&lt;span class=&quot;hljs-operator&quot;&gt;..&lt;/span&gt; __.rui.WindowSize.Width &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]&lt;br /&gt;                   &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Error&lt;/span&gt; (e) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;note&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; e&lt;br /&gt;               &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;note&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; state.Notification&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; h &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; __.rui.WindowSize.Height &lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; out &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; List.length entries &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt; h &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; entries&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; List.take h entries&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; PocofData.unwrap&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; __.invoke&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Seq.fold&lt;br /&gt;                    (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; acc s &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                        s.Split Environment.NewLine&lt;br /&gt;                        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.ofArray&lt;br /&gt;                        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;@&lt;/span&gt;) acc)&lt;br /&gt;                    []&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;seq&lt;/span&gt; { &lt;span class=&quot;hljs-number&quot;&gt;0.&lt;/span&gt;.h }&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Seq.iter (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; i &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                __.writeScreenLine&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;|&lt;/span&gt; toHeight i&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; List.tryItem i out &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                   &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt; s &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                       &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; これオプションでどうにかする&lt;/span&gt;&lt;br /&gt;                       &lt;span class=&quot;hljs-comment&quot;&gt;// logFile &amp;quot;./debug.log&amp;quot; [ s ]&lt;/span&gt;&lt;br /&gt;                       s&lt;br /&gt;                   &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; String.Empty)&lt;br /&gt;&lt;br /&gt;            __.setCursorPosition&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;|&lt;/span&gt; __.getCursorPositionX state.Query x&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;|&lt;/span&gt; basePosition
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;関数がでかいしゴチャついてる。デバッグログ出力がコメントアウトで残されており雑い。でも色々やれるイメージ湧いてきて、良い。ひとまず NOTE コメントのある箇所をどうにかしたい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;__.rui&lt;/code&gt; が &lt;code&gt;PSHostRawUserInterface&lt;/code&gt; なのだけど、こいつをまず引き剥がしたいところ。
その後デバッグモードの組み込みをしてデバッグログ出力を改善する。
page up / down のサポートをするときには、描画対象となるデータを取ってる &lt;code&gt;let out&lt;/code&gt; のところを表示中のページと描画域の行の数で調整して～とか。&lt;/p&gt;
&lt;p&gt;描画で &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.console.write?view=net-7.0&quot; title=&quot;Console.Write&quot;&gt;Console.Write&lt;/a&gt; を使って茶を濁してるところはもうちょっと先。コンソールバッファの操作に関してわからないことが多いから調べないといけない。クロスプラットフォーム見据えたら .NET だけでできる範囲限られてそうやし。 Windows 以外ではインタラクティブな操作をテストしてないのもあって。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;blog-fable&quot;&gt;blog-fable&lt;/a&gt; の方を積極的にいじる熱落ち着いてるので、これから当面イメージが湧く限り &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; に集中していけそう。いつまで続くか知らんけど。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 12 Nov 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-11-04-writing-cmdlet-in-fsharp-pt22.html</guid><link>https://krymtkts.github.io/posts/2023-11-04-writing-cmdlet-in-fsharp-pt22.html</link><title>F# でコマンドレットを書いてる pt.22</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; の開発をした。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; で素振りした &lt;a href=&quot;/posts/2023-10-29-rebuild-blog-with-fable-pt19.html&quot; title=&quot;dependabot&quot;&gt;dependabot&lt;/a&gt; の導入 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/62&quot; title=&quot;#62&quot;&gt;#62&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/63&quot; title=&quot;#63&quot;&gt;#63&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/64&quot; title=&quot;#64&quot;&gt;#64&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/69&quot; title=&quot;#69&quot;&gt;#69&lt;/a&gt;&lt;/li&gt;&lt;li&gt;キー入力に async expression を利用する &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/67&quot; title=&quot;#67&quot;&gt;#67&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;キー入力に async expression を利用する、がメイン。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; の開発で F# の async expression を触ったので、ちゃんと F# らしく pocof を改善してこうという気になった。&lt;/p&gt;
&lt;p&gt;元々はキー入力されるまで &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.console.keyavailable?view=net-7.0&quot; title=&quot;&lt;code&gt;Console.KeyAvailable&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.KeyAvailable&lt;/code&gt;&lt;/a&gt; でチェックして無限に再帰する形で実装してたのだけど、このコメントによれば、どうも継続を使ったら非同期にできるらしい。
&lt;a href=&quot;https://stackoverflow.com/questions/56398388/async-to-wait-for-a-key-in-f&quot; title=&quot;asynchronous - Async to wait for a key in F#? - Stack Overflow&quot;&gt;asynchronous - Async to wait for a key in F#? - Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;回答者が &lt;a href=&quot;https://github.com/nightroman/Invoke-Build&quot; title=&quot;Invoke-Build の nightroman サン&quot;&gt;Invoke-Build の nightroman サン&lt;/a&gt;というのも渋い。ぜひ使いたい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-control-fsharpasync.html#FromContinuations&quot; title=&quot;&lt;code&gt;Async.FromContinuations&lt;/code&gt;&quot;&gt;&lt;code&gt;Async.FromContinuations&lt;/code&gt;&lt;/a&gt; でキー入力待ちを非同期にして &lt;a href=&quot;https://fsharp.github.io/fsharp-core-docs/reference/fsharp-control-fsharpasync.html#RunSynchronously&quot; title=&quot;&lt;code&gt;Async.RunSynchronously&lt;/code&gt;&quot;&gt;&lt;code&gt;Async.RunSynchronously&lt;/code&gt;&lt;/a&gt; で結果を待ち受ける。
これによって無限ループで無駄に CPU 回していたやつが回避される、と。
ひとまずこうした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; getKey () &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                Async.FromContinuations(&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; (cont, _, _) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; Console.ReadKey &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; cont)&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Async.RunSynchronously
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これでキー入力してないときの CPU 使用率はかなり改善された。&lt;/p&gt;
&lt;p&gt;元々コピペした文字列を &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.console.readkey?view=net-7.0&quot; title=&quot;&lt;code&gt;Console.ReadKey&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.ReadKey&lt;/code&gt;&lt;/a&gt; で 1 文字ずつ読み取って表示の処理まで回してるからパフォ良くない課題がある。
今回の非同期化で幾分シンプルになったし、 &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.console.keyavailable?view=net-7.0&quot; title=&quot;&lt;code&gt;Console.KeyAvailable&lt;/code&gt;&quot;&gt;&lt;code&gt;Console.KeyAvailable&lt;/code&gt;&lt;/a&gt; と再帰を組み合わせて文字列丸ごと読み取ることで改善できそうな雰囲気も感じてきた。&lt;/p&gt;
&lt;p&gt;因みに &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/async-expressions&quot; title=&quot;Async expressions - F# | Microsoft Learn&quot;&gt;Async expressions - F# | Microsoft Learn&lt;/a&gt; にはこういう定石パターンみたいなの載ってなかったので、今回のように実例から学ぶのがいいのかな。&lt;/p&gt;
&lt;p&gt;今回のキー入力を非同期にしたやつは、先にググったらそのまま良さそうな snippet が見つかったから GitHub Copilot には相談しなかった。
でも次は聞いてみたらなんか良いコード出してもらえるかもな。&lt;/p&gt;
&lt;p&gt;他に &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/lazy-expressions&quot; title=&quot;Lazy Expressions - F# | Microsoft Learn&quot;&gt;Lazy Expressions - F# | Microsoft Learn&lt;/a&gt; なんかも試したいけど pocof に活用できることないかもな...という直感。まずコードを漁って実例から学ぶとしよう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 04 Nov 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-10-29-rebuild-blog-with-fable-pt19.html</guid><link>https://krymtkts.github.io/posts/2023-10-29-rebuild-blog-with-fable-pt19.html</link><title>Fable でブログを再構築する pt.19</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; で作った &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; にブログ乗り換えたけど、まだ気になるとこをいじったりしている。&lt;/p&gt;
&lt;p&gt;依存関係のメンテを楽にするため、 Dependabot version updates を使ってみることにした。以下を参考にして &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; で &lt;code&gt;dependabot.yml&lt;/code&gt; を作成した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates&quot; title=&quot;About Dependabot version updates - GitHub Docs&quot;&gt;About Dependabot version updates - GitHub Docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#rebase-strategy&quot; title=&quot;Configuration options for the dependabot.yml file - GitHub Docs&quot;&gt;Configuration options for the dependabot.yml file - GitHub Docs&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;使い始めて 1 週間くらいの利用期間を経て色々見えてきた感じ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;使ってみて早々、コレ結構設定(&lt;code&gt;dependabot.yml&lt;/code&gt;)で調整してても Fable の project とは相性悪いなーと思った。
Fable の依存関係って .NET(NuGet) と npm 、 2 つの package system にまたがってるものがある。
krymtkts/blog-fable における具体例だと &lt;a href=&quot;https://github.com/Zaid-Ajaj/Feliz&quot; title=&quot;&lt;code&gt;Feliz&lt;/code&gt;&quot;&gt;&lt;code&gt;Feliz&lt;/code&gt;&lt;/a&gt; から &lt;code&gt;react&lt;/code&gt;,&lt;code&gt;react-dom&lt;/code&gt; に依存してるけど、これを &lt;code&gt;dependabot.yml&lt;/code&gt; では複数 &lt;code&gt;package-ecosystem&lt;/code&gt; をまとめた &lt;code&gt;groups&lt;/code&gt; を書けないみたい。 JSON Schema の &lt;code&gt;package-ecosystem&lt;/code&gt; が &lt;code&gt;string&lt;/code&gt; やし。
つまり dependabot サンが .NET で &lt;code&gt;Feliz&lt;/code&gt; か npm で &lt;code&gt;react*&lt;/code&gt; の PR を作ってきたら、自分で femto で更新して～みたいな流れを踏む必要がある。&lt;/p&gt;
&lt;p&gt;結果的に npm 側の &lt;code&gt;react*&lt;/code&gt; を 検知しないようにして &lt;code&gt;Fable.*&lt;/code&gt;,&lt;code&gt;Feliz&lt;/code&gt; だけ dependabot サンに PR 作ってもらい、自分で femto で更新するように、今はしている。
なんか、特定の依存関係の PR を dependabot サンが作ったのを引き金にして workflow で femto install して commit 的自動化ができたらカッコよさそう。
でも実現可能性についてはまだ調べておらず、さっぱりわからん。&lt;/p&gt;
&lt;p&gt;現状このような形での設定となった。
JST 金曜にチェックするのはだいたい週末に趣味プロするから。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;updates:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# Maintain dependencies for GitHub Actions&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;package-ecosystem:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;github-actions&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;directory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;schedule:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;interval:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;weekly&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;day:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;friday&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;time:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;09:00&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;timezone:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Asia/Tokyo&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;groups:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;workflow:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;patterns:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;assignees:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtkts&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;reviewers:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtkts&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# Maintain dependencies for NuGet&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;package-ecosystem:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;nuget&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;directory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;schedule:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;interval:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;weekly&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;day:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;friday&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;time:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;09:00&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;timezone:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Asia/Tokyo&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;groups:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;dotnet-tools:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;patterns:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;fable&amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;femto&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;fable:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;patterns:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Fable.*&amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Feliz&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;assignees:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtkts&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;reviewers:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtkts&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# Maintain dependencies for npm&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;package-ecosystem:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;npm&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;directory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;schedule:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;interval:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;weekly&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;day:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;friday&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;time:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;09:00&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;timezone:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Asia/Tokyo&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;groups:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;dependencies:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;dependency-type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;production&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;exclude-patterns:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;react*&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; react should be updated with Fable.&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;dev-dependencies:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;dependency-type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;development&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;assignees:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtkts&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;reviewers:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtkts&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あと NuGet の lock file を使ってる場合とも相性が悪いぽくて、 dependabot サンは &lt;code&gt;*.fsproj&lt;/code&gt; のバージョンは上げてくれるけどそこから lock file の作り直しはしてくれないみたい。
npm の &lt;code&gt;package.lock.json&lt;/code&gt; はやってくれるのになんでだよと思ったが、やっぱ Issue 立ってるみたい ↓。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dependabot/dependabot-core/issues/1303&quot; title=&quot;Support for NuGet package lock files · Issue #1303 · dependabot/dependabot-core&quot;&gt;Support for NuGet package lock files · Issue #1303 · dependabot/dependabot-core&lt;/a&gt; コレみたい。間違ってたらスマン。&lt;/p&gt;
&lt;p&gt;結局この場合も手でメンテしてやる必要があって、いまんところ以下が最も引っかかることなく作業できるかなって思ってる。ここまで来たら dependabot サンが対応するまでは bump 用に task runner 作っておいた方が良いよな...&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; .\src\packages.lock.json&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# この辺を一掃しておかないとエラーになる&lt;/span&gt;&lt;br /&gt;fable clean&lt;br /&gt;femto install Fable.Core ./sr&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 動作確認ができて lock file が再生成される&lt;/span&gt;&lt;br /&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;更に、 dependabot サンから PR を受け付けたら、端的にいうと動作確認が必要になる。
お試し運用期間は動作確認スタイルで良いかなと始めてみたけど、依存関係の更新頻度 1 週間でも結構きついなという量だったので、テストの自動化は必須。
でも krymtkts/blog-fable にはテスト無いから、単純に fable によるビルドと Markdown からの SSG がコケないのだけはチェックできたら良いかなと。&lt;/p&gt;
&lt;p&gt;なので Pull request 受け付けたときにはビルドだけして、 main branch への merge 後に GitHub Pages へ deploy って形になる。
そしたら追加した PR 用と元々ある deploy 用でビルド箇所の YAML は丸かぶりするわけ。コレもめんどい。&lt;/p&gt;
&lt;p&gt;結局 composite action を作って使い回すのが良さそうだった。
&lt;a href=&quot;https://docs.github.com/en/actions/creating-actions/creating-a-composite-action&quot; title=&quot;Creating a composite action - GitHub Docs&quot;&gt;Creating a composite action - GitHub Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;試してみたら、 composite action で出力されたファイルはうまく後続の step でも使えた。
こういう composite action を用意した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Build pages Action&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Setup .NET and Node.js, install dependencies and build pages.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;runs:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;using:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;composite&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;steps:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Setup&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;.NET&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/setup-dotnet@v3&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;with:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;global-json-file:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./global.json&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;cache:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;cache-dependency-path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;src/packages.lock.json&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Setup&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Node.js&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/setup-node@v4&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;with:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;node-version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Install&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dependencies&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;bash&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;install&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Build&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pages&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;bash&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使う方はこう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deploy&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;GitHub&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Pages&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;on:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;push:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;branches:&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;main&amp;quot;&lt;/span&gt;]&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;workflow_dispatch:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;permissions:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;contents:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;read&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;pages:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;write&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;id-token:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;write&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;concurrency:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;group:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;pages&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;cancel-in-progress:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;jobs:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;build:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;runs-on:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;steps:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Checkout&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/checkout@v4&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Build&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pages&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./.github/actions/build&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# ここが composite action で楽になっている&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Setup&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Pages&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/configure-pages@v3&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Upload&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;artifact&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/upload-pages-artifact@v2&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;with:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;docs/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;deploy:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;github-pages&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;url:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${{&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;steps.deployment.outputs.page_url&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;}}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;runs-on:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;needs:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;build&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;steps:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deploy&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;GitHub&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Pages&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;id:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;deployment&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/deploy-pages@v2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;他にワークフローの再利用を使う手もあったけど、今回のケースでは &lt;code&gt;docs/&lt;/code&gt; に出力したファイル群を使いまわせるか不明だったので確認がとれてた composite action でやった。 &lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/reusing-workflows&quot; title=&quot;Reusing workflows - GitHub Docs&quot;&gt;Reusing workflows - GitHub Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;いずれもドキュメントにはそういう記述なかった気がするけど案外いけるのかな。今度試してみたい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Dependabot version updates を試してみたことで必要性に駆られて composite action にも手を出した。
脇道それた感あるが、結果的に &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; にも適用できるものを得られたのでヨシ！😹&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 29 Oct 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-10-22-rebuild-blog-with-fable-pt18.html</guid><link>https://krymtkts.github.io/posts/2023-10-22-rebuild-blog-with-fable-pt18.html</link><title>Fable でブログを再構築する pt.18</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; で作ったブログに乗り換えたけど、まだ気になるとこをいじったりしている。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;まず画像の Lazy loading をつけてみた。画像貼ることあんまりないけど。何ができるかなーと MDN を調べてみてすぐできそうだったので。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading#images_and_iframes&quot; title=&quot;Lazy loading - Web performance | MDN&quot;&gt;Lazy loading - Web performance | MDN&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;要は &lt;code&gt;![...](...)&lt;/code&gt; こういう画像リンクの場合に以下のように &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; をつけるだけ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;...&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;alt&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;...&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;loading&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;lazy&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Marked の Renderer にオプションを渡して &lt;code&gt;img&lt;/code&gt; タグ出力を担う &lt;code&gt;image&lt;/code&gt; 関数を上書きしたら良いだけ。&lt;a href=&quot;https://marked.js.org/using_pro#renderer&quot; title=&quot;Using Pro - Marked Documentation&quot;&gt;Using Pro - Marked Documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;コード長いので該当のオプションの箇所だけを転記する。
コレで可視範囲外の画像が遅延読み込みされるようになるらしい。実に単純な変更だ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; image (href&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) (title&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) (text&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; add lazy loading attribute.&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;&amp;quot;&amp;quot;&amp;lt;img src=&amp;quot;%s&lt;span class=&quot;hljs-subst&quot;&gt;{href}&lt;/span&gt;&amp;quot; title=&amp;quot;%s&lt;span class=&quot;hljs-subst&quot;&gt;{title}&lt;/span&gt;&amp;quot; alt=&amp;quot;%s&lt;span class=&quot;hljs-subst&quot;&gt;{text}&lt;/span&gt;&amp;quot; loading=&amp;quot;lazy&amp;quot; /&amp;gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; mops &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;!!&lt;/span&gt;{&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; heading &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; heading&lt;br /&gt;                     link &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; link&lt;br /&gt;                     listitem &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; listitem&lt;br /&gt;                     checkbox &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; checkbox&lt;br /&gt;                     image &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; image &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;試しにいっぱい画像があるページの &lt;a href=&quot;/posts/2019-01-14-ortho-linear-keyboard-planck.html&quot; title=&quot;昔 Planck を組み立てた記事&quot;&gt;昔 Planck を組み立てた記事&lt;/a&gt; なんかを開いてみたら、意外と画像読み込まれてて実際にコレで効果あんのか？という感じがした。
でもスクロールダウンしていくと、確かに 1 枚だけ遅延読み込みされてきた。すご。
1 枚かーという気もしなくはないけど、いつか異常に大量の画像を貼る機会があったら効果を実感するだろう。機会なさそうやけど。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;他に、 GitHub Pages へ deploy する workflow で NuGet package のキャッシュを試してみた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/actions/setup-dotnet/blob/2216f56ae1eec353f06abd464e2ec435fa5f5d43/README.md#caching-nuget-packages&quot; title=&quot;Caching NuGet Packages | actions/setup-dotnet&quot;&gt;Caching NuGet Packages | actions/setup-dotnet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;初回は単にフラグオンでいけるかなと思ってやったが NuGet package の lock file を作ってなくて失敗した。
これ当然の話しでドキュメントにも lock file 無いとエラーするって書いてた。けど読まずに体当たりしたため。&lt;/p&gt;
&lt;p&gt;そも NuGet package の lock file のことあんまりわかってなかったので、ひとまず fsproj に出力するための設定をしてみたり。以下で勉強した限りオプション入れるだけっぽい。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#locking-dependencies&quot; title=&quot;NuGet PackageReference in project files | Microsoft Learn&quot;&gt;NuGet PackageReference in project files | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/&quot; title=&quot;Enable repeatable package restores using a lock file - The NuGet Blog&quot;&gt;Enable repeatable package restores using a lock file - The NuGet Blog&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;lock file さえあればちゃんとエラーすることなく正常終了した。
初回でキャッシュが無いから、ログにもそう出てた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/actions/runs/6595551745/job/17920660575#step:4:11&quot; title=&quot;#72&quot;&gt;#72&lt;/a&gt; のログを転記。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Run actions/setup-dotnet@v3&lt;br /&gt;  with:&lt;br /&gt;    global-json-file: ./global.json&lt;br /&gt;    cache: true&lt;br /&gt;    cache-dependency-path: src/packages.lock.json&lt;br /&gt;  env:&lt;br /&gt;    GITHUB_PAGES: true&lt;br /&gt;/home/runner/work/_actions/actions/setup-dotnet/v3/externals/install-dotnet.sh --channel 7.0&lt;br /&gt;dotnet-install: .NET Core SDK with version &amp;#x27;7.0.402&amp;#x27; is already installed.&lt;br /&gt;Dotnet cache is not found
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/actions/caches&quot; title=&quot;Actions タブの Caches&quot;&gt;Actions タブの Caches&lt;/a&gt; を見たらキャシュが作成されてたので、キャッシュがなくなる前に次の workflow 実行したらキャッシュ有り版のログになるかな。&lt;/p&gt;
&lt;p&gt;ちょうど bug があったので直したやつ &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/73&quot; title=&quot;#73&quot;&gt;#73&lt;/a&gt; を merge したところ、キャッシュ使われてた。
ただ workflow 全体を見て速くなった感じはなさそう。 Fable だからなのか。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/actions/runs/6601005193/job/17931606545#step:4:15&quot; title=&quot;#73&quot;&gt;#73&lt;/a&gt; からログを転記。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Run actions/setup-dotnet@v3&lt;br /&gt;  with:&lt;br /&gt;    global-json-file: ./global.json&lt;br /&gt;    cache: true&lt;br /&gt;    cache-dependency-path: src/packages.lock.json&lt;br /&gt;  env:&lt;br /&gt;    GITHUB_PAGES: true&lt;br /&gt;/home/runner/work/_actions/actions/setup-dotnet/v3/externals/install-dotnet.sh --channel 7.0&lt;br /&gt;dotnet-install: .NET Core SDK with version &amp;#x27;7.0.402&amp;#x27; is already installed.&lt;br /&gt;Received 131171387 of 131171387 (100.0%), 161.8 MBs/sec&lt;br /&gt;Cache Size: ~125 MB (131171387 B)&lt;br /&gt;/usr/bin/tar -xf /home/runner/work/_temp/bf7a4381-abc4-4d1d-90af-6c72251bb2dd/cache.tzst -P -C /home/runner/work/blog-fable/blog-fable --use-compress-program unzstd&lt;br /&gt;Cache restored successfully&lt;br /&gt;Cache restored from key: dotnet-cache-Linux-73204c40d9255ea97458df81ea64893c7b0c7130549819b8ae0fb308360b2d25
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この方法で NuGet package のキャッシュできそうなので、同じ方法を &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; にもやってみたのだけど、そっちはまだ模索中。
platform が違うと生成される contentHash も違うらしく NU1403 というエラーで頓挫している。&lt;/p&gt;
&lt;p&gt;NU1403 と cross-platform 周りで調べた内容。 NU1403 が出たら &lt;code&gt;DisableImplicitNuGetFallbackFolder&lt;/code&gt; で大体解消するってのが定石らしいけど、 cross-platform なので話は別ぽい。調べたが理解が浅くてわからん。
cross-platform な lock file を置いても &lt;a href=&quot;https://github.com/nektos/act&quot; title=&quot;nektos/act&quot;&gt;nektos/act&lt;/a&gt; でテストすると hash が合わないエラー NU1403 が解消できない。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu1403&quot; title=&quot;NuGet Error NU1403 | Microsoft Learn&quot;&gt;NuGet Error NU1403 | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/57161512/nuget-lock-file-fails-to-restore-with-locked-mode&quot; title=&quot;.net - NuGet lock file fails to restore with --locked-mode - Stack Overflow&quot;&gt;.net - NuGet lock file fails to restore with --locked-mode - Stack Overflow&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/58612554/can-dotnet-test-specify-a-runtime-identifier&quot; title=&quot;c# - Can dotnet-test specify a runtime-identifier? - Stack Overflow&quot;&gt;c# - Can dotnet-test specify a runtime-identifier? - Stack Overflow&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;なんで Fable の方は Windows で生成した lock file が ubuntu の runner でうまくいったんだろうか。 NuGet Package への理解が浅い。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あとやりたいこととしては、以前から気になってる Bulma の css 軽量化。&lt;/p&gt;
&lt;p&gt;ただ&lt;a href=&quot;/posts/2023-09-24-rebuild-blog-with-fable-pt14.html&quot; title=&quot;前に書いた&quot;&gt;前に書いた&lt;/a&gt;ように Bulma がちゃんと SCSS 対応されてないことで &lt;code&gt;@use&lt;/code&gt; を使った場合にスタイルを部分的にするとビルドエラーするから、それをなんとか解消できないと先がない。
妥協案としては &lt;code&gt;@use&lt;/code&gt; を諦めて &lt;code&gt;@import&lt;/code&gt; にしたら良いのだろうけど、 SCSS で非推奨やからなあ...悩ましい。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 22 Oct 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-10-15-rebuild-blog-with-fable-pt17.html</guid><link>https://krymtkts.github.io/posts/2023-10-15-rebuild-blog-with-fable-pt17.html</link><title>Fable でブログを再構築する pt.17</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; で作ったブログに乗り換えた。
このブログは既に Powered by &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; だ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2023-10-08-rebuild-blog-with-fable-pt16.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;検証したときの手順ベースでうまくできた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# krymtkts/krymtkts.github.io の root directory にて&lt;/span&gt;&lt;br /&gt;git &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--create&lt;/span&gt; feature/blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 現行ブログのリソースを削除する&lt;/span&gt;&lt;br /&gt;ll &lt;span class=&quot;hljs-literal&quot;&gt;-Exclude&lt;/span&gt; content,contents | &lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;git add &lt;span class=&quot;hljs-literal&quot;&gt;-u&lt;/span&gt;&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Remove old resources.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# blog-fable repo を merge する&lt;/span&gt;&lt;br /&gt;git remote add blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt; ssh://git@github.com/krymtkts/blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt;.git&lt;br /&gt;git fetch blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt;&lt;br /&gt;git merge &lt;span class=&quot;hljs-literal&quot;&gt;--allow-unrelated-histories&lt;/span&gt; blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt;/main&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Sample を消す&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; contents/* &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt;&lt;br /&gt;git add &lt;span class=&quot;hljs-literal&quot;&gt;-u&lt;/span&gt;&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Remove sample posts and pages.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;posts&amp;#x27;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;pages&amp;#x27;&lt;/span&gt; | %{&lt;span class=&quot;hljs-built_in&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;./content/md/&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;./contents/&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&amp;quot;&lt;/span&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;img&amp;#x27;&lt;/span&gt; | %{&lt;span class=&quot;hljs-built_in&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;./content/&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;./contents/&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&amp;quot;&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 旧コンテンツを消す&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; content &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Move contents.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# エラーしないように Markdown を書き換える&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 自動でできる分&lt;/span&gt;&lt;br /&gt;. .\scripts\&lt;span class=&quot;hljs-built_in&quot;&gt;convert-contents&lt;/span&gt;.ps1&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# あと少しの手動書き換え&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# App.fs の設定を書き換える&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 実行して動作確認する&lt;/span&gt;&lt;br /&gt;npm ci&lt;br /&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;自動で書き換え可能と判断した以下は PowerShell でスクリプト化(&lt;code&gt;scripts\convert-contents.ps1&lt;/code&gt;)した。
今思えば F# スクリプトで書いても良かったなという感じもするけど。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;posts の front matter を edn から YAML に変換&lt;/li&gt;&lt;li&gt;内部リンクに &lt;code&gt;.html&lt;/code&gt; を付与&lt;/li&gt;&lt;li&gt;コードブロックの言語 typo とか非対応言語の置換&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;少し手で書き換えたのは以下。対処法ないものやめんどいもので止む無く。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;言語なしのコードブロック(&lt;code&gt;```&lt;/code&gt;)&lt;ul&gt;
&lt;li&gt;閉じる方特別つかず、手動で &lt;code&gt;```plaintext&lt;/code&gt; に変更した&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;edn で書かれた front matter の tags リストにカンマがないやつ&lt;ul&gt;
&lt;li&gt;スクリプトでできる気がしたが数少なかったので&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;pages の書き換え&lt;ul&gt;
&lt;li&gt;1 ページしかなかったので&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;相対リンクで書かれてたかしょ&lt;ul&gt;
&lt;li&gt;1 箇所しかなかったので...&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;因みにこの手順だけでは終われなくて、 GitHub の repository の設定をイジる必要があった。
具体的には、 branch から deploy される設定を GitHub Actions で deploy するように変更した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Settings -&amp;gt; Pages -&amp;gt; Build and deployment の Source を GitHub Actions に変える&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;これを既存の Deploy from a branch から変えるのは公開中ページに影響ないか度胸がいったが、サクッと変えてもサイトが非公開化されたりしなかったので、安心してよい。&lt;/p&gt;
&lt;p&gt;ちゃんと準備してきたこともあってすんなり終わった。&lt;/p&gt;
&lt;p&gt;Markdown parser だったり highlighter は自分で書いてないけど、結構な部分自分で作った感じするので、愛着が湧いて良い。
けっこう速くできてるけど、まだ高速化できる箇所もあったりなんかメンテの楽しみが増えて良いな。
期間にして半年くらいの週末と休日の数時間を使って作ってきて、時間かかり過ぎな気もするが現時点で満足の行くものになった気がする。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 15 Oct 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-10-08-rebuild-blog-with-fable-pt16.html</guid><link>https://krymtkts.github.io/posts/2023-10-08-rebuild-blog-with-fable-pt16.html</link><title>Fable でブログを再構築する pt.16</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築している。&lt;/p&gt;
&lt;p&gt;こまい修正をして、その後現ブログの Markdown を元にどれくらいのパフォを望めるのか試してみた。&lt;/p&gt;
&lt;p&gt;パフォ比較時点での記事数は今書いているこの記事を含めて、 posts が 151 pages が 1 画像が 25 。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# krymtkts/krymtkts.github.io の root directory にて&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;md/posts&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;md/pages&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;img&amp;#x27;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; ./content/&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Measure-Object&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; Count }&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;151&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;25&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この状態で &lt;code&gt;lein run&lt;/code&gt; だと 3 度試行して概ね 26.174 , 27.144, 28.722 。 26~28 くらいか。&lt;/p&gt;
&lt;p&gt;次に krymtkts/blog-fable の歴史を krymtkts/krymtkts.github.io に統合して測定する。
統合する手法は前に &lt;a href=&quot;/posts/2022-03-26-merge-blog-repo.html&quot; title=&quot;Blog 用 Git repositories のマージ&quot;&gt;Blog 用 Git repositories のマージ&lt;/a&gt; でやったのと同じで慣れたもの。
生成元の Markdown 配置だけ構造変わってるのでそこの置き換えだけは必要な感じだが、今回は検証なので symbolic link でやる。
Markdown と画像以外は全部消す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# krymtkts/krymtkts.github.io の root directory にて&lt;/span&gt;&lt;br /&gt;git &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--create&lt;/span&gt; feature/blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;mkdir contents&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 現行ブログのリソースを削除する&lt;/span&gt;&lt;br /&gt;ll &lt;span class=&quot;hljs-literal&quot;&gt;-Exclude&lt;/span&gt; content,contents | &lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;git add &lt;span class=&quot;hljs-literal&quot;&gt;-u&lt;/span&gt;&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Remove old resources.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# blog-fable repo を merge する&lt;/span&gt;&lt;br /&gt;git remote add blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt; ssh://git@github.com/krymtkts/blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt;.git&lt;br /&gt;git fetch blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt;&lt;br /&gt;git merge &lt;span class=&quot;hljs-literal&quot;&gt;--allow-unrelated-histories&lt;/span&gt; blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt;/main&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Administrator access で検証のための symbolic link を作成する&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; contents/* &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;posts&amp;#x27;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;pages&amp;#x27;&lt;/span&gt; | %{&lt;span class=&quot;hljs-built_in&quot;&gt;New-Item&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ItemType&lt;/span&gt; SymbolicLink &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; contents &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Value&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(pwd)/content/md/&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&amp;quot;&lt;/span&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;img&amp;#x27;&lt;/span&gt; | %{&lt;span class=&quot;hljs-built_in&quot;&gt;New-Item&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ItemType&lt;/span&gt; SymbolicLink &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; contents &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Value&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(pwd)/content/&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&amp;quot;&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# エラーしないように Markdown を書き換える ← 後述&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# App.fs の設定を変える&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;npm install&lt;br /&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで初回はビルドが発生するので 21.479 、若干速くなるけどキャッシュなしならあんま変わらんなという印象は否めない感じ。
以降はキャッシュがあったら 6.424 , 7.597 という感じだった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2023-10-01-rebuild-blog-with-fable-pt15.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;このように記した。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;あと気になるのはパフォ面。
Fable のビルドは遅いけどそれ以外は結構速いから期待できんじゃないかな。
Cryogen での SSG は記事が多いともっさりしてて 151 記事で &lt;code&gt;lein run&lt;/code&gt; の終了まで 25 秒くらかかる。
8 記事しかない状態で 4 秒未満のとこしか見てないから、 Cryogen と同じ記事数でどうなるか...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;少なくともローカルで Markdown を書いて開発サーバで確認する分には速くなりそう。
GitHub Actions のワークフローで動かす分にはあんまり変わらないか。
何なら npm と dotnet 両方の依存関係があるし遅くなったりして。&lt;/p&gt;
&lt;p&gt;GitHub Actions でキャッシュするようにしたら良さそうか。
でも GitHub Actions のキャッシュて 7 日間経過したら消えるらしいので、自分の使い方だと大体週一やからキャッシュの恩恵にあずかれなさげかな。
ひとまずやるだけやろう。&lt;/p&gt;
&lt;p&gt;あと一部先述しているように本格的な移行を進めるにあたり、以下の最低限対応が必要。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;highlight.js 未対応言語の書き換え&lt;ul&gt;
&lt;li&gt;わかりやすいように新ブログでは謎言語をエラーで許容しなくしたので、言語の識別子の typo や 空, &lt;code&gt;textile&lt;/code&gt; &lt;code&gt;log&lt;/code&gt; みたいな対応してないやつがエラーするようになった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;front matter を &lt;a href=&quot;https://github.com/edn-format/edn&quot; title=&quot;edn&quot;&gt;edn&lt;/a&gt; から YAML 形式に書き換え&lt;/li&gt;&lt;li&gt;(念のため) サイト内 link に &lt;code&gt;.html&lt;/code&gt; を足すようにする&lt;ul&gt;
&lt;li&gt;GitHub Pages だといい感じに処理してくれるが、新ブログで生成する &lt;code&gt;*.html&lt;/code&gt; に合わせる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;他に見落としあるかも？という気はせんでもないが、最低限これだけ処置すればいつでも現ブログを移行できるようになるはず。&lt;/p&gt;
&lt;p&gt;front matter の書き換えだけちょっとめんどくさいな...というやる気ゼロモードだが、あえて edn を維持する必要がなくやらざるを得ない。
量的に(150 あり)手作業はありえないので PowerShell でいい塩梅に処理できないか検討する。&lt;/p&gt;
&lt;p&gt;ここまでくればあとは実施するのみだが、コレやってしまうと Feedly で見る限り少なくとも世界に 1 人は購読してくれている人がいるので、その人に影響あろうからちょっと気になるところではある。仕方ない点ではあるか。&lt;/p&gt;
&lt;p&gt;あとアレな、 Fable と共に過ごすということは Node.js のエコシステムの上で生活するので、依存関係の更新が今後ずっとつきまとう。
メンテの省力化のために dependabot 導入とか考えても良さそう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 08 Oct 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-10-01-rebuild-blog-with-fable-pt15.html</guid><link>https://krymtkts.github.io/posts/2023-10-01-rebuild-blog-with-fable-pt15.html</link><title>Fable でブログを再構築する pt.15</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築している。&lt;/p&gt;
&lt;p&gt;TODO の回収と細々とした使い勝手の改善など
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/61&quot; title=&quot;#61&quot;&gt;#61&lt;/a&gt;
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/62&quot; title=&quot;#62&quot;&gt;#62&lt;/a&gt;
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/64&quot; title=&quot;#64&quot;&gt;#64&lt;/a&gt;
をした。
内部のリファクタリングなり実装忘れの機能追加をしてきて、かなり移行への気持ちも高まってきた(毎回言ってる)。&lt;/p&gt;
&lt;p&gt;その中でも自分でいい感じにできたんじゃないかなという所は、 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/63&quot; title=&quot;#63&quot;&gt;#63&lt;/a&gt;
で &lt;code&gt;Intl.DateTimeFormat&lt;/code&gt; のごく小さな binding を書いてみたところ。&lt;/p&gt;
&lt;p&gt;調べた感じ、昔の Fable.Import.Browser にはあったけど、分割されたあとなくなってるぽい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fable-compiler/Fable/issues/1925&quot; title=&quot;Import of &amp;#39;intl&amp;#39; package fails in production mode · Issue #1925 · fable-compiler/Fable&quot;&gt;Import of &amp;#39;intl&amp;#39; package fails in production mode · Issue #1925 · fable-compiler/Fable&lt;/a&gt;
&lt;a href=&quot;https://github.com/fable-compiler/fable-import/blob/a24f2c51bcfc79737427613e5c4aa5e99e114d40/Browser/Fable.Import.Browser.fs#L12129-L12241&quot; title=&quot;fable-import/Browser/Fable.Import.Browser.fs at a24f2c51bcfc79737427613e5c4aa5e99e114d40 · fable-compiler/fable-import&quot;&gt;fable-import/Browser/Fable.Import.Browser.fs at a24f2c51bcfc79737427613e5c4aa5e99e114d40 · fable-compiler/fable-import&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;分割先のモジュールを調べるにはこの Issue を見る → &lt;a href=&quot;https://github.com/fable-compiler/fable-import/issues/80&quot; title=&quot;Track repo splits · Issue #80 · fable-compiler/fable-import&quot;&gt;Track repo splits · Issue #80 · fable-compiler/fable-import&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;これを参考に足りない部分を補う形で以下のように記述した。
自分が使いたい &lt;code&gt;formatToParts&lt;/code&gt; &lt;code&gt;DataTimeFormatPart&lt;/code&gt; はなかったから自前で書いて、 &lt;code&gt;DateTimeFormatOptions&lt;/code&gt; は違いなし。この &lt;code&gt;Create&lt;/code&gt; の書き方は学びになった。
MDN を参考にしたら簡単だったのでふつーにいけた。 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/formatToParts&quot; title=&quot;Intl.DateTimeFormat.prototype.formatToParts() - JavaScript | MDN&quot;&gt;Intl.DateTimeFormat.prototype.formatToParts() - JavaScript | MDN&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; minimum implementation for Intl.DateTimeFormat.formatToParts.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;RequireQualifiedAccess&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Intl &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Global&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; DateTimeFormat&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; DateTimeFormat &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; jsNative&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;AllowNullLiteral&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;DateTimeFormatOptions&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; weekday&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; year&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; month&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; day&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; hour&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; minute&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; second&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; hourCycle&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; timeZone&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; timeZoneName&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;AllowNullLiteral&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;DateTimeFormatPart&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``type``&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; value&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;AllowNullLiteral&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;DateTimeFormat&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Emit &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;new Intl.$0($1, $2)&amp;quot;&lt;/span&gt;&amp;gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; Create&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; lang&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; options&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; DateTimeFormatOptions &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; DateTimeFormat&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;abstract&lt;/span&gt; formatToParts&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; date&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; System.DateTime &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; DateTimeFormatPart &lt;span class=&quot;hljs-type&quot;&gt;array&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コレを書いたことでちょっとは安心感持って使えるかな？という感じやが、
そもそも書き直すことあんまなさそうなのと結局戻り値はサイズ固定配列なので、そこまだなんとかしたい感じ。&lt;/p&gt;
&lt;p&gt;ただ小さい binding でも書いてみることで Fable binding への理解度上がった感ある。&lt;/p&gt;
&lt;p&gt;あと完全に忘れてたのが、画像ファイルがあった場合に出力先へコピる機能。
初めは、 favicon とか画像類はスクリプトを手でいじって好きにやる想定にしてたけど途中で変えたから、まるっと忘れてた。
機能的にはそんなもんちゃうかな？結構機能は削りまくってるのでなんか忘れてそうではあるが。&lt;/p&gt;
&lt;p&gt;あと気になるのはパフォ面。
Fable のビルドは遅いけどそれ以外は結構速いから期待できんじゃないかな。
Cryogen での SSG は記事が多いともっさりしてて 151 記事で &lt;code&gt;lein run&lt;/code&gt; の終了まで 25 秒くらかかる。
8 記事しかない状態で 4 秒未満のとこしか見てないから、 Cryogen と同じ記事数でどうなるか...&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 01 Oct 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-09-24-rebuild-blog-with-fable-pt14.html</guid><link>https://krymtkts.github.io/posts/2023-09-24-rebuild-blog-with-fable-pt14.html</link><title>Fable でブログを再構築する pt.14</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築している。
もういい加減ブログ移行作業着手したいけど、ちまちま直してたら修正スべき箇所見つかってきてちまちまちした更新を続けている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2023-09-17-rebuild-blog-with-fable-pt13.html&quot; title=&quot;前のやつ&quot;&gt;前のやつ&lt;/a&gt; ↓。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;何が駄目かって、 &lt;code&gt;Async.AwaitEvent&lt;/code&gt; するところで非同期ブロックが入るのだけど、その後クライアントから切断を受信して &lt;code&gt;loop&lt;/code&gt; 変数の値を変更・ループ ② を止めても、ループ ① は非同期ブロックされてて次の変更イベント発火まで生き続けるのよね。
なので画面遷移やリロードのたびに変更イベントの待ちが溜まっていって、変更イベントで一気にドバっと流れるというのになってる。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;どう解決するかわかりまして、 &lt;code&gt;CancellationToken&lt;/code&gt; でもって破棄してやれば良いとのことだったのでそうした。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/54&quot; title=&quot;#54&quot;&gt;#54&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/tutorials/async#asyncstart&quot; title=&quot;Async and Task Programming - F# | Microsoft Learn&quot;&gt;Async and Task Programming - F# | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ようやっと F# で非同期計算する入り口に立った気。&lt;/p&gt;
&lt;p&gt;他に細々した更新やバグ修正してたのだけど、手間がかかったのだと依存関係の更新をしてた。
特に Marked と Highlight.js の更新はちょっと気が重かった。
ずっと古い ver に依存しておったことで型定義は &lt;code&gt;@types/highlightjs&lt;/code&gt; &lt;code&gt;@types/marked&lt;/code&gt; に依存してたのだけど、それを取り除いて純正の型を使う切り替えが必要だった。 Marked も Highlight.js もえらい前から型提供してたみたい。
コピペ元が古いから自分での確認を怠っており全く気づかなかったか。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/markedjs/marked/releases/tag/v6.0.0&quot; title=&quot;Release v6.0.0 · markedjs/marked&quot;&gt;Release v6.0.0 · markedjs/marked&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/highlightjs/highlight.js/commit/c836e3aae667ce8c8f7b28534a25d280587f7d3f&quot; title=&quot;(parser/docs) Add jsdoc annotations and TypeScript type file (#2517) · highlightjs/highlight.js@c836e3a&quot;&gt;(parser/docs) Add jsdoc annotations and TypeScript type file (#2517) · highlightjs/highlight.js@c836e3a&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;個別の型定義を取り除いたあとは &lt;a href=&quot;https://github.com/fable-compiler/ts2fable&quot; title=&quot;ts2fable&quot;&gt;ts2fable&lt;/a&gt; で Fable binding を生成する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;npx ts2fable node_modules\highlight.js\types\index.d.ts src/bindings/HighlightJs.fs&lt;br /&gt;npx ts2fable node_modules\marked\lib\marked.d.ts src/bindings/Marked.fs
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ぐいっと一気に引き上げたので極力型を fable binding を再生成したかったが、結構負担大きかった。
結局生成した binding を手で補正する必要があった。&lt;/p&gt;
&lt;p&gt;Highlight.js に関しては再生成した型定義をエラーが出ない範囲で削った。自分が使う極小範囲に留めた binding を作ったわけだ。&lt;/p&gt;
&lt;p&gt;Marked はちょっとそう簡単にはいかなかった。びっくりするくらい上手くいかない。
ts2fable って &lt;code&gt;Omit&lt;/code&gt; とか型の交差を理解しなくて、そのまま F# のコードに出力される。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fable-compiler/ts2fable/issues/474&quot; title=&quot;Combined and Omit&amp;lt;&amp;gt; types · Issue #474 · fable-compiler/ts2fable&quot;&gt;Combined and Omit&amp;lt;&amp;gt; types · Issue #474 · fable-compiler/ts2fable&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;あとは &lt;code&gt;Record&lt;/code&gt; とかも理解しない。これらに対する対処を手でやりつつ、非公開な型を削るのしんどかった。
ので、 Marked は元々使ってた &lt;code&gt;@types/marked&lt;/code&gt; で生成した型から、不要な部分や削除された部分を最小限で削ったものにした。
恐らく利用してない範囲に非互換な型定義があるんじゃないかと思うが、利用範囲だけは手直しして使えるようにした感じ。&lt;/p&gt;
&lt;p&gt;Fable の binding を用意する方法、結局 ts2fable を使うよりも自分で更地から書いた方がいいのでは...という気配薄っすら感じる。
が、まったく ts2fable 開発されてないわけじゃないし今のところコミュニティの方向はどこに向いてんだろ。
追々調べておく必要がありそう。そうそう binding て書く機会もないしな。
とはいえよ、 module で API には快適変更があるときに binding 再生成だけで住むのが理想よな。ちょっと遠そう。&lt;/p&gt;
&lt;p&gt;他、 Marked で使ってた &lt;code&gt;headerIds&lt;/code&gt; という Extension が v8.0.0 からなくなってた。 &lt;a href=&quot;https://marked.js.org/using_advanced&quot; title=&quot;Using Advanced - Marked Documentation&quot;&gt;Using Advanced - Marked Documentation&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Removed in v8.0.0 use marked-gfm-heading-id to add a string to prefix the id attribute when emitting headings (h1, h2, h3, etc).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;けどこれは &lt;code&gt;h*&lt;/code&gt; 要素に anchor をつけるように作ってたから元々いらなくて、なくてもいけたのでコレを機に消した。
&lt;a href=&quot;https://marked.js.org/using_advanced&quot; title=&quot;Using Advanced - Marked Documentation&quot;&gt;Using Advanced - Marked Documentation&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あとこれは現在進行系で解決できてない困ってること。
Bulma が document で書かれてるような部分的な利用ができなくなってるってのがわかった。
非推奨となった &lt;code&gt;@import&lt;/code&gt; を使ってたら起こらないけど &lt;code&gt;@use&lt;/code&gt; だと起こる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bulma.io/documentation/customize/with-node-sass/&quot; title=&quot;With node-sass | Bulma: Free, open source, and modern CSS framework based on Flexbox&quot;&gt;With node-sass | Bulma: Free, open source, and modern CSS framework based on Flexbox&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;SCSS ビルド時にこういうエラーが出る。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Error: The target selector was not found.&lt;br /&gt;Use &amp;quot;@extend %overlay !optional&amp;quot; to avoid this error.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/jgthms/bulma/issues/3391&quot; title=&quot;Webpack @extend !optional error · Issue #3391 · jgthms/bulma&quot;&gt;Webpack @extend !optional error · Issue #3391 · jgthms/bulma&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;同じようなことに困ってる人いる。
単純に Bulma 側が SCSS 対応がちゃんとできてないってことなんやろな。 &lt;code&gt;@import&lt;/code&gt; ならいけるからな。&lt;/p&gt;
&lt;p&gt;Dart 製の &lt;code&gt;sass&lt;/code&gt; モジュールを使ってるせいか未だ調べてないけど、解決する予定もなさそうなので一旦全部入りでやり過ごす。
できれば利用してるスタイルだけにとどめて高速・軽量化したいのやけどなー。
Bulma 自体今年はメンテ止まってるし、最悪自分でなんとかする感じかな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 24 Sep 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-09-17-rebuild-blog-with-fable-pt13.html</guid><link>https://krymtkts.github.io/posts/2023-09-17-rebuild-blog-with-fable-pt13.html</link><title>Fable でブログを再構築する pt.13</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築している。&lt;/p&gt;
&lt;p&gt;開発サーバが重いので、諸々調整をしている。&lt;/p&gt;
&lt;p&gt;既に対応済みのものとしては、ビルドの軽量化。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/52&quot; title=&quot;#52&quot;&gt;#52&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/53&quot; title=&quot;#53&quot;&gt;#53&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;毎回全部ビルドし直す必要はないので、 &lt;code&gt;*.fs&lt;/code&gt;, &lt;code&gt;*.md&lt;/code&gt; と &lt;code&gt;*.scss&lt;/code&gt; どれが変更されたかを判別して、実行するビルドタスクを切り替えるような実装にした。&lt;/p&gt;
&lt;p&gt;特に今後ブログのコードをいじることはあまりないだろうから、 Markdown を変更したときのビルド待ちは極力抑えたかった。
その場合 &lt;code&gt;dotnet fable&lt;/code&gt; でビルド済みの JavaScript があるからそれを実行する形を採用した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fake.build/index.html&quot; title=&quot;FAKE&quot;&gt;FAKE&lt;/a&gt; には npm コマンドを実行するモジュールがある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fake.build/reference/fake-javascript-npm.html&quot; title=&quot;Npm (Fake)&quot;&gt;Npm (Fake)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これを利用して直接 &lt;code&gt;node&lt;/code&gt; を呼び出すことはできないが、 &lt;code&gt;package.json&lt;/code&gt; に書いておいて &lt;code&gt;npm run&lt;/code&gt; すれば FAKE から呼び出せる。
こんな感じ ↓ で &lt;code&gt;build-md&lt;/code&gt; と &lt;code&gt;build-css&lt;/code&gt; を用意して FAKE から呼び出すだけ。 (ちょっとタスク名は整理した方がいいか)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;scripts&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;postinstall&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet tool restore&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;build-css&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;sass --style=compressed --no-source-map ./sass/style.scss ./docs/blog-fable/css/style.css&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;serve&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet fsi ./dev-server.fsx&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;build-fable&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet fable src --runScript&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;build&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;npm run build-css &amp;amp;&amp;amp; npm run build-fable&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;dev&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;npm run build dev &amp;amp;&amp;amp; npm run serve&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;build-md&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;node ./src/App.fs.js&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// 実行は非常に簡素なインタフェース&lt;/span&gt;&lt;br /&gt;Npm.run &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;build-md&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Npm(FAKE) があれば、 &lt;code&gt;dotnet fable&lt;/code&gt; に関しても &lt;code&gt;npm run&lt;/code&gt; 経由で呼べばよいのだけど、 1 つ難点がありそのまま DotNet モジュールを利用している。
それは実行結果を得られないところだ。
コマンドの成否を以て何かしている訳では無いが、わざわざ情報を劣化させる理由もないのでそのままステイだ。&lt;/p&gt;
&lt;p&gt;毎回 &lt;code&gt;dotnet fable&lt;/code&gt; することがなくなったから、 Markdown の編集だけならかなり快適になったはず。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;次に、適切に処理していなかった WebSocket 接続の手当をしている話。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/53&quot; title=&quot;#53&quot;&gt;#53&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これちょっと難しくて、 WebSocket が難しいのでなくて Suave でクライアントからメッセージを受けつつサーバ起点で何かするのが厄介で、手こずってる。&lt;/p&gt;
&lt;p&gt;ひとまずやりたかった「Suave でクライアントからメッセージを受けつつサーバ起点で何かする」に関しては 2 つのループで実現できるのがわかったのでそれを使った。
これを参照した。 → &lt;a href=&quot;https://github.com/SuaveIO/suave/issues/307&quot; title=&quot;How to implement server-push over websocket in suave? · Issue #307 · SuaveIO/suave&quot;&gt;How to implement server-push over websocket in suave? · Issue #307 · SuaveIO/suave&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2 つのループを設けることで、クライアントが切断したときにサーバ側の WebSocket ハンドラを終了するのと、サーバ側の変更イベントでクライアントにプッシュする、が同時に実現できる。
ただまだ駄目なところがあって完成ではない。現時点の Suave の WebSocket のハンドラは以下の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; socketHandler (ws&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; WebSocket) _ &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;mutable&lt;/span&gt; loop &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        Async.Start(&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;async&lt;/span&gt; {&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; loop &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// ループ①&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;do!&lt;/span&gt; refreshEvent.Publish &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Async.AwaitEvent&lt;br /&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;fire event.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; seg &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ASCII.bytes &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;refreshed&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; ByteSegment&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;do!&lt;/span&gt; ws.send Text seg &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Async.Ignore&lt;br /&gt;            }&lt;br /&gt;        )&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;socket&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; loop &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// ループ②&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let!&lt;/span&gt; msg &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ws.read ()&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; msg &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; (Close, _, _) &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; emptyResponse &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;hljs-operator&quot;&gt;||&lt;/span&gt;] &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; ByteSegment&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;do!&lt;/span&gt; ws.send Close emptyResponse &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-built_in&quot;&gt;printfn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;WebSocket connection closed gracefully.&amp;quot;&lt;/span&gt;&lt;br /&gt;                    loop &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; ()&lt;br /&gt;        }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;何が駄目かって、 &lt;code&gt;Async.AwaitEvent&lt;/code&gt; するところで非同期ブロックが入るのだけど、その後クライアントから切断を受信して &lt;code&gt;loop&lt;/code&gt; 変数の値を変更・ループ ② を止めても、ループ ① は非同期ブロックされてて次の変更イベント発火まで生き続けるのよね。
なので画面遷移やリロードのたびに変更イベントの待ちが溜まっていって、変更イベントで一気にドバっと流れるというのになってる。&lt;/p&gt;
&lt;p&gt;因みに &lt;code&gt;Async.AwaitEvent&lt;/code&gt; のあとで &lt;code&gt;if&lt;/code&gt; なり仕込んで抜けられるかなと試したけど、同じ周回だと &lt;code&gt;loop&lt;/code&gt; 変数への変更が伝播してなくて止まらなかった。 &lt;code&gt;ref&lt;/code&gt; をあえて使ったらまた違うのかな。&lt;/p&gt;
&lt;p&gt;F# の async/await ちゃんと触ってないから手こずってるけど、これ上手く手なづけたら &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; へも良い影響出せそうなので、これを気にちゃんとやってこう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 17 Sep 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-09-10-rebuild-blog-with-fable-pt12.html</guid><link>https://krymtkts.github.io/posts/2023-09-10-rebuild-blog-with-fable-pt12.html</link><title>Fable でブログを再構築する pt.12</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築している。&lt;/p&gt;
&lt;p&gt;色調整して Accessibility 上げたかったけど Solarized Dark を使おうとしたらどうにもならんので諦めた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dequeuniversity.com/rules/axe/4.7/color-contrast&quot; title=&quot;Elements must meet minimum color contrast ratio thresholds | Axe Rules | Deque University | Deque Systems&quot;&gt;Elements must meet minimum color contrast ratio thresholds | Axe Rules | Deque University | Deque Systems&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ここで Foreground と Background を色比較してコントラスト比を見ることができる。
AAA に合格する比率まで色を明るくしたらもう印象が違い過ぎるから、やめた。&lt;/p&gt;
&lt;p&gt;コードブロックやリンクがあると、それだけで Accessibility のスコアが下がるのでどうにもならん。&lt;/p&gt;
&lt;p&gt;あと以下にも抵触してるみたい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dequeuniversity.com/rules/axe/4.7/link-in-text-block&quot; title=&quot;Links must be distinguishable without relying on color | Axe Rules | Deque University | Deque Systems&quot;&gt;Links must be distinguishable without relying on color | Axe Rules | Deque University | Deque Systems&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今はリンクと本文の違いが色しかないから、これに下線を足したりすればましになる気配はある。&lt;/p&gt;
&lt;p&gt;Accessibility て難しいなーと改めて思う。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;他には、本格的な乗り換えに備えて以下を行った。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;公開日や更新日の表示忘れ対応とドキュメント更新 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/48&quot; title=&quot;#48&quot;&gt;#48&lt;/a&gt;&lt;/li&gt;&lt;li&gt;サンプルの更新 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/49&quot; title=&quot;49&quot;&gt;49&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;初めから乗り換えを目的にやってるけど、いざ手をつける段階になったらこれまた色々気になってくるので、なるべく処理してからやろうとしてる。
やれ dev server が反応しなくなる時があるとか、 TODO は乗り換えまでに解消しておきたいなとか。&lt;/p&gt;
&lt;p&gt;乗り換え時には &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; と &lt;a href=&quot;https://github.com/krymtkts/krymtkts.github.io&quot; title=&quot;krymtkts/krymtkts.github.io&quot;&gt;krymtkts/krymtkts.github.io&lt;/a&gt; の歴史を合流するつもりやから、先にできるだけ課題を潰しておきたいというのがある。
頻繁に両方メンテとかはやりたくなくて、なんか改善や変えたいことがあったら &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; の方で試してからブログの方に投入するみたいなフローでやりたい。&lt;/p&gt;
&lt;p&gt;歴史を合流する方法以外にコードを統合するマトモな術は、 Fable Module とか dotnet のテンプレ化あたり。
けどその辺に手を出すと注力するところが主目的から外れるので、やらないつもり。&lt;/p&gt;
&lt;p&gt;npm package を含んだ Fable Module の作成は色々気を使うことがあり、ここに力割くのもどうかなって。
&lt;a href=&quot;https://fable.io/docs/your-fable-project/author-a-fable-library.html&quot; title=&quot;Fable · Author a Fable library&quot;&gt;Fable · Author a Fable library&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;dotnet のテンプレ化に関しても、仮に誰か奇特な人が Fable でブログを作りたくて repo に辿り着いたとき便利だなとかその程度かな？
template repository になってても同じ感じか。&lt;/p&gt;
&lt;p&gt;私的ブログの新しいコードを書いてるだけなので、機能を公開することに重きを置かず、一番楽にコードを統合できる歴史を合流する術で進めるという感じ。&lt;/p&gt;
&lt;p&gt;まだやっときたいこと諸々あれど、ひとまず &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; を作り始めた当初の目標である年内乗り換えは現実味を帯びてきた気がする。
2023-10 末で期間としては半年になるから、その辺から年末の間でいい感じに移行したいなー。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 10 Sep 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-09-03-rebuild-blog-with-fable-pt11.html</guid><link>https://krymtkts.github.io/posts/2023-09-03-rebuild-blog-with-fable-pt11.html</link><title>Fable でブログを再構築する pt.11</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築している。&lt;/p&gt;
&lt;p&gt;ここ 1 ヶ月ほどでやりたかったことを 3 つ進められた。エライ(低ハードル)。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ややこしくなってた入出力パスの構築 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/38&quot; title=&quot;#38&quot;&gt;#38&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/39&quot; title=&quot;#39&quot;&gt;#39&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://pagespeed.web.dev/analysis/https-krymtkts-github-io-blog-fable/vfo1picz8u?form_factor=mobile&quot; title=&quot;PageSpeed Insights&quot;&gt;PageSpeed Insights&lt;/a&gt; のスコア改善 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/42&quot; title=&quot;#42&quot;&gt;#42&lt;/a&gt;&lt;/li&gt;&lt;li&gt;カラースキームの導入 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/43&quot; title=&quot;#43&quot;&gt;#43&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;以下のとおり結果的に結構良いスコア叩き出すようになった。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;platform&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Performance&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Accessibility&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Best Practices&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;SEO&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Mobile&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;99&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;93&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Desktop&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;93&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;100&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;a href=&quot;https://ethanschoonover.com/solarized/&quot; title=&quot;Solarized&quot;&gt;Solarized&lt;/a&gt; が好きなのだけど今回は Dark にしてみた。エディタやターミナルなんでも Solarized Dark にして 10 年近いのでついにブログも Dark に。
まだいい感じに色調整できてないから Accessibility をちょい下げてしまってるが、後ほど調整する。&lt;/p&gt;
&lt;p&gt;今回やった中には、初体験でちょっと調べる必要があるものもあった。
これらはメモがてら以下に記しておく。全然 F# ネタではないけど。&lt;/p&gt;
&lt;p&gt;いずれも上手く拡張できる様になっており楽だった。感心するわ。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 &gt;&lt;a name=&quot;Marked-Renderer-&quot; href=&quot;#Marked-Renderer-&quot;&gt;Marked の Renderer を拡張する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://marked.js.org/using_pro#renderer&quot; title=&quot;The Renderer - Marked Documentation&quot;&gt;The Renderer - Marked Documentation&lt;/a&gt; に示されるように &lt;code&gt;Renderer&lt;/code&gt; オブジェクトにわたすオプションで拡張できる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;listitem(string text, boolean task, boolean checked)&lt;/code&gt; と &lt;code&gt;checkbox(boolean checked)&lt;/code&gt; の組み合わせにちょっと癖があった。
どっちも定義しているとどっちも呼ばれてチェックボックスが 2 個になってしまう。
&lt;code&gt;checkbox(boolean checked)&lt;/code&gt; 側を無効化するような書き方をして &lt;code&gt;checkbox&lt;/code&gt; 要素を &lt;code&gt;label&lt;/code&gt; 要素で包み込んだ。
シグネチャが &lt;code&gt;checkbox(boolean checked)&lt;/code&gt; なもんで、こっち側は &lt;code&gt;label&lt;/code&gt; 要素書こうにもテキスト不明でできないねんよな。
ブログの場合 &lt;code&gt;checkbox&lt;/code&gt; 要素が単独で使用されることまずないからこうしたけど、なんかもっと良い方法がないのかは気になるところ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; listitem &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; text task check &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; checkState &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; check &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;checked&amp;quot;&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; input を label で包んで関連を持たせる&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; task &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;&amp;quot;&amp;quot;&amp;lt;li&amp;gt;&amp;lt;label class=&amp;quot;checkbox&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;checkbox&amp;quot; class=&amp;quot;checkbox&amp;quot; disabled &lt;span class=&quot;hljs-subst&quot;&gt;{checkState}&lt;/span&gt; /&amp;gt;&lt;span class=&quot;hljs-subst&quot;&gt;{text}&lt;/span&gt;&amp;lt;/label&amp;gt;&amp;lt;/li&amp;gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;&amp;quot;&amp;quot;&amp;lt;li&amp;gt;&lt;span class=&quot;hljs-subst&quot;&gt;{text}&lt;/span&gt;&amp;lt;/li&amp;gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; checkbox &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; checkbox は list と一緒に使われる前提と考えて何も返さない&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; mops &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;!!&lt;/span&gt;{&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; heading &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; heading&lt;br /&gt;                     link &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; link&lt;br /&gt;                     listitem &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; listitem&lt;br /&gt;                     checkbox &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; checkbox &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            jsOptions&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;Marked.MarkedExtension&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; o &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                o.renderer &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;|&lt;/span&gt; U2.Case2 mops&lt;br /&gt;                o.gfm &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;                o.headerIds &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;Bulma-style-&quot; href=&quot;#Bulma-style-&quot;&gt;Bulma の自前 style をビルドする&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://bulma.io/documentation/customize/with-node-sass/&quot; title=&quot;With node-sass | Bulma: Free, open source, and modern CSS framework based on Flexbox&quot;&gt;With node-sass | Bulma: Free, open source, and modern CSS framework based on Flexbox&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;概ねこの手順の通りにやればいい。&lt;/p&gt;
&lt;p&gt;ただし以下の非推奨があって、それらは自前で最新のものに置き換える必要があった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/node-sass&quot; title=&quot;&lt;code&gt;node-sass&lt;/code&gt;&quot;&gt;&lt;code&gt;node-sass&lt;/code&gt;&lt;/a&gt; は非推奨、 Dart 製の &lt;a href=&quot;https://www.npmjs.com/package/sass&quot; title=&quot;&lt;code&gt;sass&lt;/code&gt;&quot;&gt;&lt;code&gt;sass&lt;/code&gt;&lt;/a&gt; に変える&lt;/li&gt;&lt;li&gt;Sass では &lt;code&gt;@import&lt;/code&gt; は非推奨、 &lt;code&gt;@use&lt;/code&gt; に書き換える&lt;ul&gt;
&lt;li&gt;余談だが commit message には backquote で囲わずにこれらのキーワードを書いてたら GitHub 上でホバーしたときにその ID の方々がポップアップされて笑ってしまった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;これらは Sass の最新仕様に追随するよう自前でこしらえた。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-code-node-sass-code-code-sass-code-&quot; href=&quot;#-code-node-sass-code-code-sass-code-&quot;&gt;&lt;code&gt;node-sass&lt;/code&gt; を &lt;code&gt;sass&lt;/code&gt; に&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;変えるのは大したことないけど、 cli インタフェースのオプションも変わってるので、そこはケアする必要がある。
ついでに出力される CSS を圧縮するオプション &lt;code&gt;--style=compressed&lt;/code&gt; もつける。今回のケースでは空白が消えたことで 3KB くらい節約できた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-patch&quot;&gt;   &amp;quot;scripts&amp;quot;: {&lt;br /&gt;     &amp;quot;postinstall&amp;quot;: &amp;quot;dotnet tool restore&amp;quot;,&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    &amp;quot;css-build&amp;quot;: &amp;quot;node-sass --omit-source-map-url ./sass/style.scss ./docs/blog-fable/css/style.css&amp;quot;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    &amp;quot;css-build&amp;quot;: &amp;quot;sass --style=compressed --no-source-map ./sass/style.scss ./docs/blog-fable/css/style.css&amp;quot;,&lt;/span&gt;&lt;br /&gt;     &amp;quot;serve&amp;quot;: &amp;quot;dotnet fsi ./dev-server.fsx&amp;quot;,&lt;br /&gt;     &amp;quot;build&amp;quot;: &amp;quot;dotnet fable src --runScript&amp;quot;,&lt;br /&gt;     &amp;quot;dev&amp;quot;: &amp;quot;npm run build dev &amp;amp;&amp;amp; npm run serve&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-code-import-code-code-use-code-&quot; href=&quot;#-code-import-code-code-use-code-&quot;&gt;&lt;code&gt;@import&lt;/code&gt; を &lt;code&gt;@use&lt;/code&gt; に&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;@use&lt;/code&gt; を使う場合は、変数のデフォルト値を書き換えるには先述の手順のとおりにはできない。
&lt;a href=&quot;https://sass-lang.com/documentation/variables/#default-values&quot; title=&quot;Default Values | Sass: Variables&quot;&gt;Default Values | Sass: Variables&lt;/a&gt; の示す通り &lt;code&gt;@use &amp;lt;url&amp;gt; with (&amp;lt;variable&amp;gt;: &amp;lt;value&amp;gt;, &amp;lt;variable&amp;gt;: &amp;lt;value&amp;gt;)&lt;/code&gt; を使う。以下書き換えイメージ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-patch&quot;&gt; @charset &amp;quot;utf-8&amp;quot;;&lt;br /&gt;&lt;br /&gt; // NOTE: based on https://ethanschoonover.com/solarized/&lt;br /&gt; $base03 :#002b36;&lt;br /&gt; $base02 :#073642;&lt;br /&gt; $base01 :#586e75;&lt;br /&gt; $base00 :#657b83;&lt;br /&gt; $base0 :#839496;&lt;br /&gt; $base1 :#93a1a1;&lt;br /&gt; $base2 :#eee8d5;&lt;br /&gt; $base3 :#fdf6e3;&lt;br /&gt; $yellow :#b58900;&lt;br /&gt; $orange :#cb4b16;&lt;br /&gt; $red :#dc322f;&lt;br /&gt; $magenta :#d33682;&lt;br /&gt; $violet :#6c71c4;&lt;br /&gt; $blue :#268bd2;&lt;br /&gt; $cyan :#2aa198;&lt;br /&gt; $green :#859900;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-@import &amp;quot;../node_modules/bulma/bulma.sass&amp;quot;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-// NOTE: Solarized Dark.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$black: $base3;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$black-bis: $base2;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$black-ter: $base2;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$grey-darker: $base1;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$grey-dark: $base1;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$grey: $base0;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$grey-light: $base00;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$grey-lighter: $base01;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$grey-lightest: $base01;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$white-ter: $base02;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$white-bis: $base02;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$white: $base03;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-// NOTE: set alternative colors.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$turquoise: $cyan;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-$purple: $violet;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+@use &amp;quot;../node_modules/bulma/bulma.sass&amp;quot; with (&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    // NOTE: Solarized Dark.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $black: $base3,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $black-bis: $base2,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $black-ter: $base2,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $grey-darker: $base1,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $grey-dark: $base1,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $grey: $base0,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $grey-light: $base00,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $grey-lighter: $base01,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $grey-lightest: $base01,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $white-ter: $base02,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $white-bis: $base02,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $white: $base03,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    // NOTE: set alternative colors.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $turquoise: $cyan,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $purple: $violet,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;p&gt;もうちょっと PageSpeed Insights のスコア上げられる雰囲気はあるので、そこだけ粘ってみる。
結構 Fable 製ブログも出来上がってきたし、いよいよ自ブログ移行に向けた試行をはじめられそう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 03 Sep 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-08-27-github-streak-a-year.html</guid><link>https://krymtkts.github.io/posts/2023-08-27-github-streak-a-year.html</link><title>GitHub streak a year</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2023-05-14-rebuild-blog-with-fable-pt3.html&quot; title=&quot;5 月の日記で触れた&quot;&gt;5 月の日記で触れた&lt;/a&gt; GitHub Streak が 2023-08-21 ようやく 365 日に到達した。やったね。
次は 730 日を目指すのだけど、マイルストンとしてまずキリよい 400 を置き、次に 500, 600 と目指していく。&lt;/p&gt;
&lt;p&gt;Streak にこだわりだしたのは、生涯プログラマであろうとしたらやっぱり日々の鍛錬というか毎日コード書いて感覚を保ちたいよな、というのが根底にある。&lt;/p&gt;
&lt;p&gt;とはいえコードを書いてない日、例えばにこの日記のような文章を書くだけのコミットもあるし、 GitHub Streak って Issue や review でも数えられるので厳密ではないのだけど。
でもそのくらいの緩さじゃないと初めから続けられなかっただろうし、ちょうど良い落とし所であろう。&lt;/p&gt;
&lt;p&gt;Streak が途絶えたとて何ら困ることないのだけど、途絶えると取り戻すのに同等の時間がかかるものは、続ける方向に適度にプレッシャーが発生して良い。
特にゲーマー脳を少なからず持っていれば、トロコン感覚を持って臨める。
積み重ねてきたものって割と簡単にやめる事ができるので、このような強制力を持って習慣を維持するのは良い案だと感じている。&lt;/p&gt;
&lt;p&gt;しかしながら Streak を始めてから今に至るまで、仕事や私生活において日々の生活リズムが狂うようなインパクトの大きい出来事が一度も起こってない。
つまるところそういったインパクトがあったときにも続けられるというサンプルが無いわけだから、もしものときに上手く続けられるかは定かではない。
今の自分ならそういう状況でも淡々とこなせそうな気配は薄っすら感じるが、これも Streak を続けてきたことで得た感触だろう。ゆーても油断は禁物やけど。&lt;/p&gt;
&lt;p&gt;次の目標 400 はもうすぐなので、堅実に次につなげていこう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 27 Aug 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-08-20-writing-cmdlet-in-fsharp-pt21.html</guid><link>https://krymtkts.github.io/posts/2023-08-20-writing-cmdlet-in-fsharp-pt21.html</link><title>F# でコマンドレットを書いてる pt.21</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; の開発をした。
&lt;a href=&quot;/posts/2023-07-16-writing-cmdlet-in-fsharp-pt20.html&quot; title=&quot;pocof のコンパイルを .NET 7 にした&quot;&gt;pocof のコンパイルを .NET 7 にした&lt;/a&gt; こともあってなんかテンション的に触りやすくなった(逆に Fable でブログ書き直す方を放置)。
&lt;a href=&quot;/posts/2023-08-13-test-publish-psresource.html&quot; title=&quot;PSResourceGet への乗り換え&quot;&gt;PSResourceGet への乗り換え&lt;/a&gt; もできたのだけど、その時気になることがあった。&lt;/p&gt;
&lt;p&gt;いつかはやらないといけないと考えていたが、配布 DLL が多すぎる。
&lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.5.0-alpha&quot; title=&quot;PowerShell Gallery | pocof 0.5.0-alpha&quot;&gt;PowerShell Gallery | pocof 0.5.0-alpha&lt;/a&gt; の FileList 見たらわかるけどめちゃくちゃ DLL がある。
pocof で使ってない DLL もいっぱい含まれている。&lt;/p&gt;
&lt;p&gt;これは...解決したい。&lt;/p&gt;
&lt;p&gt;.NET では実行可能ファイルであれば自己完結型と言われる単一バイナリの生成ができるのだけど、 DLL ではそういうのはない様子。
PowerShell モジュールの場合どういう手段が取れるのかちゃんと理解してなかったが、こういうこと ↓ で大量の DLL 全部ぶちまけられてた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nuget.org/packages/Microsoft.PowerShell.SDK/#versions-body-tab&quot; title=&quot;Microsoft.PowerShell.SDK&quot;&gt;Microsoft.PowerShell.SDK&lt;/a&gt; を参照してる&lt;/li&gt;&lt;li&gt;F# の各言語に localize されたリソースの DLL が出力される&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;これらに対処してバンドルに含まれる DLL を減らしてみた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/57&quot; title=&quot;#57&quot;&gt;#57&lt;/a&gt;&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;Microsoft-PowerShell-SDK&quot; href=&quot;#Microsoft-PowerShell-SDK&quot;&gt;Microsoft.PowerShell.SDK&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;pocof のような PowerShell モジュールは PowerShell のランタイム内で動く。
また pocof では PowerShell の機能をモリモリ使って出力結果を生成するようなことがない。
このようなケースでは、 &lt;a href=&quot;https://github.com/PowerShell/PowerShellStandard&quot; title=&quot;PowerShell/PowerShellStandard&quot;&gt;PowerShell/PowerShellStandard&lt;/a&gt; のリファレンスライブラリだけでいいみたい。&lt;/p&gt;
&lt;p&gt;pocof で &lt;code&gt;Microsoft.PowerShell.SDK&lt;/code&gt; を &lt;code&gt;PowerShellStandard.Library&lt;/code&gt; に入れ替えて全テスト実行してみた。
テストデータ作成のために &lt;code&gt;PSObject&lt;/code&gt; を作成しているところだけ影響があった。
つまり pocof 本体に影響はないので、テストプロジェクトで &lt;code&gt;Microsoft.PowerShell.SDK&lt;/code&gt; を参照してれば OK ということ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2022-05-07-start-to-write-cmdlet-by-fsharp.html&quot; title=&quot;一番初めに pocof を書き始めた&quot;&gt;一番初めに pocof を書き始めた&lt;/a&gt;ころの記事では &lt;code&gt;PowerShellStandard.Library&lt;/code&gt; を参照してたのだけどなんか途中で変えてみたい。
初回リリースでは既に &lt;code&gt;Microsoft.PowerShell.SDK&lt;/code&gt; に変わってたのだけど、この頃は &lt;a href=&quot;https://fsprojects.github.io/FsUnit/&quot; title=&quot;FsUnit&quot;&gt;FsUnit&lt;/a&gt; 使ったテストなかった気がするし、違う理由かなんか分からず変えてそう。コミットログ追えばわかるかな。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;F-localize-DLLs&quot; href=&quot;#F-localize-DLLs&quot;&gt;F# の localize されたリソースの DLLs&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;pocof では localize されたリソースの DLL 要らない。なんか F# のリソースが使われるとしても英語でいいし。
これらの各言語リソースの DLL を取り除くには &lt;code&gt;SatelliteResourceLanguages&lt;/code&gt; という MSBuild プロパティを指定すれば良いようだ。言語を指定せずに空(&lt;code&gt;null&lt;/code&gt;)だと全言語対象のママになるので、英語を指定しないといけない。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://forums.fsharp.org/t/what-is-the-purpose-of-the-fsharp-core-resource-dll-files/1402&quot; title=&quot;What is the purpose of the FSharp.Core.resource.dll files? - General - F# Software Foundation Community Forums&quot;&gt;What is the purpose of the FSharp.Core.resource.dll files? - General - F# Software Foundation Community Forums&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/core/project-sdk/msbuild-props#satelliteresourcelanguages&quot; title=&quot;SatelliteResourceLanguages | Microsoft.NET.Sdk の MSBuild プロパティ - .NET | Microsoft Learn&quot;&gt;SatelliteResourceLanguages | Microsoft.NET.Sdk の MSBuild プロパティ - .NET | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;終わり&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;MUSBuild の世界は難しいなー。でもこれでかなり DDL が減った。
ただ最後に &lt;code&gt;System.Management.Automation.dll&lt;/code&gt; が残ってる。&lt;/p&gt;
&lt;p&gt;これって PowerShell 環境ならかならずあるのでは...という気がするのだけど。
open してる名前空間の関係で消えないのかな？もうちょい検証してみないとわからん。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 20 Aug 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-08-13-test-publish-psresource.html</guid><link>https://krymtkts.github.io/posts/2023-08-13-test-publish-psresource.html</link><title>Publish-PSResource を試す</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2023-07-23-psresourceget.html&quot; title=&quot;以前から気になってた&quot;&gt;以前から気になってた&lt;/a&gt; PSResourceGet の &lt;code&gt;Publish-PSResource&lt;/code&gt; を試す機会があったので試した。
試したと書いてるけど、自分の利用ケースで問題なく使えるか見ただけ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSJobCanAttendance/&quot; title=&quot;krymtkts/PSJobCanAttendance&quot;&gt;krymtkts/PSJobCanAttendance&lt;/a&gt; を修正する機会があったので、ついでに &lt;code&gt;Publish-PSResource&lt;/code&gt; へ切り替えた。上手くいってた。
&lt;a href=&quot;https://github.com/krymtkts/PSJobCanAttendance/pull/9&quot; title=&quot;#9&quot;&gt;#9&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(追記 2023-08-15)
試したバージョンは以下の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Module&lt;/span&gt; *PSResourceGet; &lt;span class=&quot;hljs-variable&quot;&gt;$PSVersionTable&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Format-Table&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ModuleType Version    PreRelease Name                                ExportedCommands&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;    &lt;span class=&quot;hljs-literal&quot;&gt;----------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                                &lt;span class=&quot;hljs-literal&quot;&gt;----------------&lt;/span&gt;&lt;br /&gt;Binary     &lt;span class=&quot;hljs-number&quot;&gt;0.5&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;23&lt;/span&gt;     beta23     Microsoft.PowerShell.PSResourceGet  {&lt;span class=&quot;hljs-built_in&quot;&gt;Find-PSResource&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;Get-InstalledPSResource&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;Get-PS&lt;/span&gt;…&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Name                           Value&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                           &lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;&lt;br /&gt;PSVersion                      &lt;span class=&quot;hljs-number&quot;&gt;7.3&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;&lt;br /&gt;PSEdition                      Core&lt;br /&gt;GitCommitId                    &lt;span class=&quot;hljs-number&quot;&gt;7.3&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;&lt;br /&gt;OS                             Microsoft Windows &lt;span class=&quot;hljs-number&quot;&gt;10.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;22621&lt;/span&gt;&lt;br /&gt;Platform                       Win32NT&lt;br /&gt;PSCompatibleVersions           {&lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;4.0&lt;/span&gt;…}&lt;br /&gt;PSRemotingProtocolVersion      &lt;span class=&quot;hljs-number&quot;&gt;2.3&lt;/span&gt;&lt;br /&gt;SerializationVersion           &lt;span class=&quot;hljs-number&quot;&gt;1.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0.1&lt;/span&gt;&lt;br /&gt;WSManStackVersion              &lt;span class=&quot;hljs-number&quot;&gt;3.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/publish-psresource?view=powershellget-3.x&quot; title=&quot;Publish-PSResource (Microsoft.PowerShell.PSResourceGet) - PowerShell | Microsoft Learn&quot;&gt;Publish-PSResource (Microsoft.PowerShell.PSResourceGet) - PowerShell | Microsoft Learn&lt;/a&gt; を参照して、
&lt;code&gt;Path&lt;/code&gt;, &lt;code&gt;ApiKey&lt;/code&gt;, &lt;code&gt;Verbose&lt;/code&gt;, &lt;code&gt;WhatIf&lt;/code&gt; を使った。
&lt;code&gt;Verbose&lt;/code&gt;, &lt;code&gt;WhatIf&lt;/code&gt; は確認用なのでなくても良い。
&lt;code&gt;Repository&lt;/code&gt; も省略できて、省略した場合は優先度が高い repository に公開される。自分の場合は PowerShell Gallery 。&lt;/p&gt;
&lt;p&gt;PSJobCanAttendance の場合は公開するファイルが少ないからか、実行したら一瞬で公開された。 PSResourceGet になったら公開まで高速化されるんや。&lt;/p&gt;
&lt;p&gt;これでいけそうな感触を得たので、 pocof でも試す。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/54&quot; title=&quot;krymtkts/pocof#54&quot;&gt;krymtkts/pocof#54&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AllowPrerelease&lt;/code&gt; とか &lt;code&gt;RequiredVersion&lt;/code&gt; とかのオプションで指定していたところがなくなって、 &lt;code&gt;*.psd1&lt;/code&gt; から読み取るように変わってるぽい。
ただ &lt;code&gt;ModuleName&lt;/code&gt; とかの指定どうなるんやと思ったけど、ディレクトリ名ぽいな。&lt;/p&gt;
&lt;p&gt;ということなので、従来の pocof の公開方法である &lt;code&gt;(Get-Module).Path&lt;/code&gt; を渡す方法は無理だってこと。これだと ddl のパスが得られるのだけどこれは弾かれたし、 &lt;code&gt;*.psd1&lt;/code&gt; のパスを渡す方法だと親ディレクトリがバージョン番号になってモジュール名にならない。 API Key にモジュール名の制限をかけてたから権限で弾かれて変な数字の名前をしたモジュールの公開を免れた。
そこんところを公開用のディレクトリにモジュール類をコピーして、その中の &lt;code&gt;pocof.psd1&lt;/code&gt; を &lt;code&gt;Publish-PSResource&lt;/code&gt; するようにしてみた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;+---.github&lt;br /&gt;+---coverage&lt;br /&gt;+---docs&lt;br /&gt;+---publish&lt;br /&gt;|   \---pocof &amp;lt;- ここへこぴる&lt;br /&gt;|       \---pocof.psd1&lt;br /&gt;+---src&lt;br /&gt;|   \---pocof&lt;br /&gt;        \---bin&lt;br /&gt;            \---Release&lt;br /&gt;                \---*&lt;br /&gt;                    \---pocof.psd1 &amp;lt;- コピー元&lt;br /&gt;\---tests
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;が、以下のようなエラーでまだ上手くいってない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Error: 2023-08-13 18:59:25:&lt;br /&gt;At C:\Users\takatoshi\dev\github.com\krymtkts\pocof\psakefile.ps1:108 char:5 +     Publish-PSResource @Params +     ~~~~~~~~~~~~~~~~~~~~~~~~~~ [&amp;lt;&amp;lt;==&amp;gt;&amp;gt;] Exception: Repository &amp;#x27;PSGallery&amp;#x27;: Response status code does not indicate success: 403 (The specified API key is invalid, has expired, or does not have permission to access the specified package.).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;公開対象のディレクトリ名がモジュール名になるって判断が間違ってるのか...いけそうな感触を持ったけどあかんのかな、挑戦は続く。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-2023-08-14&quot; href=&quot;#-2023-08-14&quot;&gt;追記 2023-08-14&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;その後、 PowerShell Gallery の API Key を作り直したり、 pocof のみ更新可能に絞っていた package を &lt;code&gt;*&lt;/code&gt; にして全権与えてみたりしたがダメだった。
DDL の Module に対応してないような旨はどこにもなかった気がするけど。&lt;/p&gt;
&lt;p&gt;Issue で気になるものとしては、 prerelease の依存関係を持つケースに対応してないというのがある。
&lt;a href=&quot;https://github.com/PowerShell/PSResourceGet/issues/1251&quot; title=&quot;PSResourceGet module prerelease version scheme issues · Issue #1251 · PowerShell/PSResourceGet&quot;&gt;PSResourceGet module prerelease version scheme issues · Issue #1251 · PowerShell/PSResourceGet&lt;/a&gt;
けど pocof 自身はそういう依存関係を持ってないので該当しないはず。
&lt;del&gt;他の可能性があるとしたら、 prerelease のみのバージョン履歴を持つ場合に未知のバグがあるとかかな。&lt;/del&gt;
普通に自家製バグ、見当外れ。&lt;/p&gt;
&lt;p&gt;いかんせん条件が定かでないので、一通り他の PSResourceGet の Cmdlet も試してみるとかが妥当だろうけど、めんどくせえええ...
&lt;del&gt;でも解決しないと pocof のプルリク永久に生き続けるし、事象を調べるか誰かが解決するのを待つか、面倒な選択しかない。&lt;/del&gt;
自家製バグが原因なので時間かけてでも調査して当たり前。&lt;/p&gt;
&lt;p&gt;&lt;del&gt;なんかいい感じにサクッとできるつもりだったがそうならなかったのは、我ながら「持ってる」な。しらんけど。&lt;/del&gt;
単に休みボケのケアレスミス発動しただけ。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-2023-08-16&quot; href=&quot;#-2023-08-16&quot;&gt;追記 2023-08-16&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;昨日この件を調べるためのテストモジュールを書いた。
F# で空のモジュールをサクッと書いて PSResourceGet と PowerShellGet の両方で公開できるようなのを。
でも PowerShellGet でも同じような権限のエラーになった。&lt;/p&gt;
&lt;p&gt;それもそのはず普通に自分が書いた psake タスクのバグだったわ...恥ずかし。
API Key を &lt;code&gt;string&lt;/code&gt; で取り出さなあかんとこ &lt;code&gt;PSCredential&lt;/code&gt; がそのまま渡ってた...(&lt;code&gt;SecureString&lt;/code&gt; じゃないんやというのは置いといて)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof/blob/83e3bf2691a8485a6b2595934845204d21b885a2/psakefile.ps1#L101-L108&quot; title=&quot;pocof/psakefile.ps1 at 83e3bf2691a8485a6b2595934845204d21b885a2 · krymtkts/pocof&quot;&gt;pocof/psakefile.ps1 at 83e3bf2691a8485a6b2595934845204d21b885a2 · krymtkts/pocof&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;間違いそのママの差分はこんな感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;     $Params = @{&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        Name = $ModuleName&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        NugetAPIKey = (Get-Credential API-key -Message &amp;#x27;Enter your API key as the password&amp;#x27;).GetNetworkCredential().Password&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        Path = $p.FullName&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        Repository = &amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        ApiKey = (Get-Credential API-key -Message &amp;#x27;Enter your API key as the password&amp;#x27;) # ここが終わってる&lt;/span&gt;&lt;br /&gt;         WhatIf = $DryRun&lt;br /&gt;         Verbose = $true&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        AllowPrerelease = $true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        RequiredVersion = $RequiredVersion&lt;/span&gt;&lt;br /&gt;     }&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    Publish-Module @Params&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    Publish-PSResource @Params&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;正しいのはこう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        ApiKey = (Get-Credential API-key -Message &amp;#x27;Enter your API key as the password&amp;#x27;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        ApiKey = (Get-Credential API-key -Message &amp;#x27;Enter your API key as the password&amp;#x27;).GetNetworkCredential().Password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;2 日浪費したけど解決してよかったわ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 13 Aug 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-08-06-disassemble-and-clean-keyswitches.html</guid><link>https://krymtkts.github.io/posts/2023-08-06-disassemble-and-clean-keyswitches.html</link><title>キースイッチを分解して掃除する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;ビルドログを書いた記憶ないけど、今は &lt;a href=&quot;https://keeb.io/collections/iris-split-ergonomic-keyboard&quot; title=&quot;Keebio の Iris&quot;&gt;Keebio の Iris&lt;/a&gt; Rev. 3 を 3 年くらい使ってる。&lt;/p&gt;
&lt;p&gt;キースイッチは &lt;a href=&quot;https://zealpc.net/products/zilent?variant=5894832357414&quot; title=&quot;Zealios Zilent 78g&quot;&gt;Zealios Zilent 78g&lt;/a&gt;。買った当時はそこそこ高級品の部類に入ってた記憶で、そのスムースさとタクタイル感の強いタッチがとても気に入っている。&lt;/p&gt;
&lt;p&gt;だけど 3 年もすると結構チャタリングを起こすようになってきてる。
どうも利用環境のホコリがスイッチに混入してるのと、 Zilent のキースイッチ内で削りカスみたいなのが発生するぽくて、そいつが接点周りで悪さしてることに拠るみたい。&lt;/p&gt;
&lt;p&gt;ホコリというのは一般的な毛ぼこりで、これが打鍵のときに軸の隙間から入り込んだり、 LED 用に開いている穴から侵入してるみたい。キースイッチを分解するとスプリングにホコリが付着していることがママある。&lt;/p&gt;
&lt;p&gt;Zilent は軸の側面にスムースさと静音を目的としたシリコン的な緩衝材が埋め込まれてるのだけど、こいつがよく使うキーだとはみ出した部分が徐々に擦れて削りカスになる。
あとこれは Zilent 以外でも起こると思うけど、打鍵が垂直でないことでボトムハウジングと軸が擦れることでプラスチックの粉？が発生する。
こういった削りカスが接点の隙間に挟まって感度が悪くなってる様子。&lt;/p&gt;
&lt;p&gt;これらはいずれも実際に自機を分解して目視確認したものだけど、現象が自分の利用環境によるのか一般的なものかはわからない。&lt;/p&gt;
&lt;p&gt;こういう具合でなのでよくチャタリングしたキーを自分流で分解して掃除しているのだけど、なんか日記にでも残そうかなと思った次第だ。&lt;/p&gt;
&lt;p&gt;分解掃除の道具は以下の通り。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Filco のキープラー&lt;ul&gt;
&lt;li&gt;キーキャップを取るのに使う&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;ダブルクリップの針金部分で自作したキースイッチオープナー&lt;ul&gt;
&lt;li&gt;ダブルクリップの針金部分を適度に曲げると MX Compatible キースイッチに適したオープナーができる。結構使いにくい&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;尼で買った先端の精度が甘い精密ピンセット&lt;ul&gt;
&lt;li&gt;分解時の部品取扱とか、接点の掃除に使う&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;SuperMax っていうインド製の両刃カミソリの替刃についてた謎の樹脂製ヒゲブラシ&lt;ul&gt;
&lt;li&gt;これで顔を洗う気に離れなかったが、キーボードのような細かい隙間があるものの簡単な掃除に便利&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;自作キーオープナーは何処かで誰かのアイデアを見かけて試したら上手くいったので長らく使っている。
キーキャップを外し、キースイッチのツメの部分の穴に合わせて左右にキーオープナーを差し込み、適度につまんで適度にひねりを入れるとトップハウジングがパカっと外せる。
今日日みんなキースイッチは hot swappable だろうからこんな苦しんでキースイッチを分解掃除することないんじゃなかろうか。
このように結構面倒なので、最適なキーオープナーあれば買いたい気持ち。&lt;/p&gt;
&lt;p&gt;また、わたしは RSA プロファイルのキーキャップを好んで使っているので、キーオープナーでトップハウジングを外そうとしたら左右のキーキャップが干渉する。なので分解するキースイッチの左右のキーキャップも外しておく必要がある。&lt;/p&gt;
&lt;p&gt;なんとかしてキースイッチを分解したら、ピンセットでトップハウジング、軸、スプリングを取り出して、先述のヒゲブラシでボトム含めささっと掃除する。スプリングやボトムのホコリはこれでほぼ取れる。&lt;/p&gt;
&lt;p&gt;軸が擦れてできるホコリはピンセットで丁寧に取り除くのが良い(めんどい)。特に毛羽立って取れかかってるシリコン的緩衝材などはブラシで取れない。
また接点部分も同様でにピンセットで丁寧に取り除く。取り除くと言ってもピンセットの先端で何回か接点部分を擦ってやる感じ。&lt;/p&gt;
&lt;p&gt;この作業をスイッチの数だけ繰り返す。気が狂いそう。
しかしこれで大体のスイッチは元通りの挙動に直せる。時が経てばまた再発するけど。&lt;/p&gt;
&lt;p&gt;注意点すべきは、接点部分の掃除とトップをはめ込む際。あまり無理にピンセットでガシガシやると板バネ部分が曲がって死ぬ。
特にトップをはめ込む向きを間違うと板バネが大変なことになる。わたしの 1 キーはそれでほぼ死んでる。キーマップ的に 1 の代替キーがあってそっちをメインで使ってるからそれほど困らないけど、普通は壊さない方がいい。
板バネが死んだキーははんだを外してキースイッチ自体取り替えるしかない。&lt;/p&gt;
&lt;p&gt;この様な作業には集中力を要するし、キースイッチ 1 つ調整するのに数分かかる。
ド近眼の不惑ともなると老眼で細かいものも見にくいので、多少チャタっても打鍵角度や押し込む量を調整してなるべく作業しなくていいように誤魔化してしまうのが現状。&lt;/p&gt;
&lt;p&gt;ぐだぐだ文句を書き連ねたけど、調整後のスイッチは概ね素晴らしいタイピング体験を提供してくれるから満足。単にだるくて何度もやりたくないのだ。
つい先日左手側を 7 キーほど掃除した(最高)けど、右手側もまたやらないといけなくてほんとだるい。&lt;/p&gt;
&lt;p&gt;もっと簡単にキースイッチのメンテナンスをできるようにキーボード自体や整備環境をアップグレードする方がいいかもと感じる。
けど、次のキーボード何がいいかな～という最大の選択をクリアできないからなんとも進まない。
やるならワイヤレスにしたいとか、 Iris よりキー少なくていいなとか、 lube したらホコリカバーできたりするかな？とか。
そういった試行錯誤を色々考えるだけでも時間かかってるからいつかは着手するやろうけど。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 06 Aug 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-07-30-rebuild-blog-with-fable-pt10.html</guid><link>https://krymtkts.github.io/posts/2023-07-30-rebuild-blog-with-fable-pt10.html</link><title>Fable でブログを再構築する pt.10</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築している。&lt;/p&gt;
&lt;p&gt;最近日記には書いてなかったが諸々の Issue を解決してた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/24&quot; title=&quot;#24&quot;&gt;#24&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/27&quot; title=&quot;#27&quot;&gt;#27&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/32&quot; title=&quot;#32&quot;&gt;#32&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/34&quot; title=&quot;#34&quot;&gt;#34&lt;/a&gt; RSS の実装。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/31&quot; title=&quot;#31&quot;&gt;#31&lt;/a&gt; 出力パス構築を整理するために、手始めとしてエントリポイントの設定を整理。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/37&quot; title=&quot;#37&quot;&gt;#37&lt;/a&gt; 生 JS の排除。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/25&quot; title=&quot;#25&quot;&gt;#25&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/28&quot; title=&quot;#28&quot;&gt;#28&lt;/a&gt; あと雑多な更新。&lt;/li&gt;&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;RSS はやっぱわたしがほぼ素人だったのもあってわからないことが多かった。
はじめは普段遣いしている &lt;a href=&quot;https://feedly.com/&quot; title=&quot;feedly&quot;&gt;feedly&lt;/a&gt; で購読してみて目視で変なところを直した。
最終的には &lt;a href=&quot;https://validator.w3.org/feed/check.cgi?url=https%3A%2F%2Fkrymtkts.github.io%2Fblog-fable%2Ffeed.xml&quot; title=&quot;Feed Validator Results: https://krymtkts.github.io/blog-fable/feed.xml&quot;&gt;Feed Validator Results: https://krymtkts.github.io/blog-fable/feed.xml&lt;/a&gt; でエラーを解消する形にした。こんな便利なものがあるとは。とても役に立った。&lt;/p&gt;
&lt;p&gt;RSS 周りの実装で改めて Fable が割る言い訳じゃないけど Fable のツラみを感じた。それは JavaScript の API がモロに出てくるところだ。
今回は feed の &lt;code&gt;pubDate&lt;/code&gt; の表記を RFC 822 date format にする必要があって、 &lt;code&gt;Intl.DateTimeFormat&lt;/code&gt; を使った。
こういうとき素直に .NET が使えるととても楽やのに...と思わざるを得ない。&lt;/p&gt;
&lt;p&gt;いったんこういう ↓ 激薄 binding を書いて、 &lt;code&gt;obj&lt;/code&gt; を引き回すことで無理くり使っている。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Intl &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Emit &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;new Intl.DateTimeFormat([$0], $1)&amp;quot;&lt;/span&gt;&amp;gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; DateTimeFormat lang options &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; jsNative
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; DateTime &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; options&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;!!&lt;/span&gt;{&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; weekday &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;short&amp;quot;&lt;/span&gt;&lt;br /&gt;             year &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;numeric&amp;quot;&lt;/span&gt;&lt;br /&gt;             month &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;short&amp;quot;&lt;/span&gt;&lt;br /&gt;             day &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;2-digit&amp;quot;&lt;/span&gt;&lt;br /&gt;             hour &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;numeric&amp;quot;&lt;/span&gt;&lt;br /&gt;             minute &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;numeric&amp;quot;&lt;/span&gt;&lt;br /&gt;             second &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;numeric&amp;quot;&lt;/span&gt;&lt;br /&gt;             hourCycle &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;h23&amp;quot;&lt;/span&gt;&lt;br /&gt;             timeZone &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Asia/Tokyo&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;TODO:&lt;/span&gt; parametarize it.&lt;/span&gt;&lt;br /&gt;             timeZoneName &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;short&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;TODO:&lt;/span&gt; write binding.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; formatter&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Intl.DateTimeFormat &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;en-US&amp;quot;&lt;/span&gt; options&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; zonePattern &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Regex(&lt;span class=&quot;hljs-string&quot;&gt;@&amp;quot;GMT([+-])(\d+)&amp;quot;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; toRFC822DateTime (d&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; DateTime) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; parts&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;obj&lt;/span&gt; [] &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; formatter&lt;span class=&quot;hljs-operator&quot;&gt;?&lt;/span&gt;formatToParts (d)&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; p&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; [] &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; parts &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Array.map (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; x&lt;span class=&quot;hljs-operator&quot;&gt;?&lt;/span&gt;value)&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; d &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;&lt;span class=&quot;hljs-subst&quot;&gt;{p.[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]}&lt;/span&gt;&lt;span class=&quot;hljs-subst&quot;&gt;{p.[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]}&lt;/span&gt;&lt;span class=&quot;hljs-subst&quot;&gt;{p.[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;]}&lt;/span&gt; &lt;span class=&quot;hljs-subst&quot;&gt;{p.[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]}&lt;/span&gt; &lt;span class=&quot;hljs-subst&quot;&gt;{p.[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;]}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; t &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; (p.[&lt;span class=&quot;hljs-number&quot;&gt;8.&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.12&lt;/span&gt;] &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; String.concat &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; z &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; p.[&lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;] &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;UTC&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;+0000&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; z &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; item &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; zonePattern.Matches(z)&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; group &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; item.Item &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; op &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; (group.Groups.Item &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;).Value&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; offset &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; int (group.Groups.Item &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;).Value&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;&lt;span class=&quot;hljs-subst&quot;&gt;{op}&lt;/span&gt;%02d&lt;span class=&quot;hljs-subst&quot;&gt;{offset}&lt;/span&gt;00&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;&lt;span class=&quot;hljs-subst&quot;&gt;{d}&lt;/span&gt; &lt;span class=&quot;hljs-subst&quot;&gt;{t}&lt;/span&gt; &lt;span class=&quot;hljs-subst&quot;&gt;{z}&lt;/span&gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;日付操作のための module 入れればいいってだけでもあるけど、このためだけに module いれるのもなあ...となるべく自力で解決する方向。&lt;/p&gt;
&lt;p&gt;ただ TODO 残してるのもあるけど、それより Dynamic typing で危なっかしいしちゃんと binding を書きたいところ。
あと添字でアクセスしまくるしか方法思いつかんかったけどもっとマシなのないのかな...&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/37&quot; title=&quot;#37&quot;&gt;#37&lt;/a&gt; で開発モードでの live reloading するために使ってた生 JavaScript を Fable が出力したやつを使うように変えた。&lt;/p&gt;
&lt;p&gt;普通であれば webpack とかで bundling するんやろけど、開発モード以外で JavaScript を使う予定がないので、出力された js ファイルを出力先ディレクトリにコピることで実現している。
他に方法あるかわからん。
ただブラウザでもそのまま使える js ファイルを出力する豆知識は得られた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Browser.Dom&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Browser.WebSocket&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; init _ &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; ws &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; WebSocket.Create &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;ws://&lt;span class=&quot;hljs-subst&quot;&gt;{window.location.host}&lt;/span&gt;/websocket&amp;quot;&lt;/span&gt;&lt;br /&gt;    ws.onmessage &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; window.location.reload ()&lt;br /&gt;&lt;br /&gt;window.addEventListener (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;load&amp;quot;&lt;/span&gt;, init)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これ ↑ がこう ↓ なる。 &lt;code&gt;private&lt;/code&gt; をつけておいたら &lt;code&gt;export&lt;/code&gt; されない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;init&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;_arg&lt;/span&gt;) {&lt;br /&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; ws = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;WebSocket&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;`ws://&lt;span class=&quot;hljs-subst&quot;&gt;${&lt;span class=&quot;hljs-variable language_&quot;&gt;window&lt;/span&gt;.location.host}&lt;/span&gt;/websocket`&lt;/span&gt;);&lt;br /&gt;  ws.&lt;span class=&quot;hljs-property&quot;&gt;onmessage&lt;/span&gt; = &lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;_arg_1&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable language_&quot;&gt;window&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;location&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;reload&lt;/span&gt;();&lt;br /&gt;  };&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable language_&quot;&gt;window&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;addEventListener&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;load&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;arg00$0040&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-title function_&quot;&gt;init&lt;/span&gt;(arg00$0040);&lt;br /&gt;});
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/31&quot; title=&quot;#31&quot;&gt;#31&lt;/a&gt; でエントリポイントの render 関数で諸々の設定をするように変えた。
元々好きに関数を組み合わせて出力を作れたらいいかなと思ってたけど、それぞれの関数で整合性を取らないといけない点があってめんどい、というのが設定を導入した理由。&lt;/p&gt;
&lt;p&gt;ひとまずこれで外向きのインタフェースは固定して、あとは内側の重複したパス構築部分をまとめていけたら、楽に整合性取れるんじゃないかな。&lt;/p&gt;
&lt;p&gt;8 月くらいにできるかなーって思ってたけど、使わない CSS を読んでるやつとかも使ってるやつだけビルドして出せるようにしたいとか、諸々考え出すと実際のところ無理かな。
気長にいこ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 30 Jul 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-07-23-psresourceget.html</guid><link>https://krymtkts.github.io/posts/2023-07-23-psresourceget.html</link><title>PSResourceGet メモ</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PSResourceGet&quot; title=&quot;PSResourceGet&quot;&gt;PSResourceGet&lt;/a&gt; を使い始めてまだちょっとだが、明らかに変わったことがある。
これ PowerShellGet v2 より圧倒的に速いな。
PowerShellGet v3 時代からインストールするようにはしてたけど日々使ってなかったから気づいてなかった。&lt;/p&gt;
&lt;p&gt;ただ &lt;a href=&quot;/posts/2023-07-09-migrate-dev-environment#PSResourceGet.html&quot; title=&quot;開発環境をプチ移行する&quot;&gt;開発環境をプチ移行する&lt;/a&gt; にも追記したように、 v3 には &lt;code&gt;Get-PSResource&lt;/code&gt; みたいなややこしい Cmdlet もいる。
PSResourceGet を入れてるなら v3 の方は消しとくのが無難。&lt;/p&gt;
&lt;p&gt;なのでこの度普段定期的にしかやってなかった古いモジュールの整理をした。既に誰でもやってそうだが習慣的に行えるよう関数にした。
なおこの関数、モジュール依存関係を壊すようなのがあればエラーになるだろう。
それを回避したければ &lt;code&gt;-SkipDependencyCheck&lt;/code&gt; 足してもいいかもだが、とりあえず壊れたときめんどいのでやめた(壊れたモジュール使うまで気づけなさそう)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Uninstall-OutdatedModules&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;SupportsShouldProcess&lt;/span&gt;)]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;()&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Get-InstalledPSResource&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; AllUsers | &lt;span class=&quot;hljs-built_in&quot;&gt;Group-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Count &lt;span class=&quot;hljs-operator&quot;&gt;-GT&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Group | &lt;span class=&quot;hljs-built_in&quot;&gt;Sort-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Version &lt;span class=&quot;hljs-literal&quot;&gt;-Descending&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Skip&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;    } | &lt;span class=&quot;hljs-built_in&quot;&gt;Uninstall-PSResource&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; AllUsers&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上記の関数の通り、 &lt;code&gt;Get-InstalledPSResource&lt;/code&gt; は複数 ver 入ってるとそのままあるだけ返してくれる。
v2 時代は &lt;code&gt;Get-Module&lt;/code&gt; しないとダメだったのは &lt;a href=&quot;/posts/2022-11-12-clean-up-pwsh-modules.html&quot; title=&quot;以前書いた PowerShell モジュールの大掃除日記&quot;&gt;以前書いた PowerShell モジュールの大掃除日記&lt;/a&gt; でのこと。時代は変わったな。&lt;/p&gt;
&lt;p&gt;また、こういう処理も v2 であれば &lt;code&gt;Get-InstalledModule&lt;/code&gt; は結構遅かったのが、 PSResourceGet になってとても速くなった。&lt;/p&gt;
&lt;p&gt;AllUsers の scope に 30 位のモジュールがある。
実行するのは自環境、 Razer Blade Stealth 13 Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz 2.00 GHz, Windows 11 22H2, PowerShell 7.3.6 にて。
初回の実行で v2 だと 1 秒くらい、 PSResourceGet だと 50ms 未満。
ショボマシンでこの差は結構でかいな。何らかのローカルなデータストアにキャッシュでもしてんのかな PSResourceGet は。&lt;/p&gt;
&lt;p&gt;MS の PowerShell Team の blog 読んだらここに書いたようなこと書いてたかもだが、改めて自分で試してみて新しいツールの利用が身体化されてる感じはするな。&lt;/p&gt;
&lt;p&gt;あと &lt;a href=&quot;https://github.com/krymtkts/pocof/&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; で気になってる &lt;code&gt;Publish-PSResource&lt;/code&gt; のテストモジュール使った動作確認は未だやってない(めんどくて)。
のでそろそろ手を付けないといけないけど、 web のどっかで情報出てきたらうれしいのだけど。&lt;/p&gt;
&lt;p&gt;そういや勤怠スクリプト類などの他の PowerShell モジュールのこと忘れてた。今年の秋には PSResourceGet 対応しとかないとあかんか。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 23 Jul 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-07-16-writing-cmdlet-in-fsharp-pt20.html</guid><link>https://krymtkts.github.io/posts/2023-07-16-writing-cmdlet-in-fsharp-pt20.html</link><title>F# でコマンドレットを書いてる pt.20</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;久しぶりに &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; の開発をした。
ゆーても .NET 6 → .NET 7 と、 PowerShellGet → PSResourceGet だけ。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-NET-6-NET-7-a-href-https-github-com-krymtkts-pocof-pull-53-title-53-53-a-&quot; href=&quot;#-NET-6-NET-7-a-href-https-github-com-krymtkts-pocof-pull-53-title-53-53-a-&quot;&gt;.NET 6 → .NET 7 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/53&quot; title=&quot;#53&quot;&gt;#53&lt;/a&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ASP.NET じゃないけどこれがやることわかりやすくまとまってたので参考にした。
&lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/migration/60-70?view=aspnetcore-7.0&amp;tabs=visual-studio-code&quot; title=&quot;Migrate from ASP.NET Core 6.0 to 7.0 | Microsoft Learn&quot;&gt;Migrate from ASP.NET Core 6.0 to 7.0 | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;SDK を &lt;code&gt;global.json&lt;/code&gt; で固定するようにした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet new globaljson &lt;span class=&quot;hljs-literal&quot;&gt;--sdk-version&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;7.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;306&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--roll-forward&lt;/span&gt; latestFeature
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;その後 &lt;code&gt;*.fsproj&lt;/code&gt; の &lt;code&gt;TargetFramework&lt;/code&gt; を net6.0 → net7.0 にする。
&lt;code&gt;global.json&lt;/code&gt; の作成に先んじて &lt;code&gt;TargetFramework&lt;/code&gt; を変更してビルドするとうまくいかなかったが、変えるとすんなりいった。キャッシュの影響？&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/Microsoft.PowerShell.SDK/7.3.6&quot; title=&quot;NuGet Gallery | Microsoft.PowerShell.SDK 7.3.6&quot;&gt;NuGet Gallery | Microsoft.PowerShell.SDK 7.3.6&lt;/a&gt;
を見て .NET 7 と互換性がある Microsoft.PowerShell.SDK に変える。
&lt;code&gt;7.2.4&lt;/code&gt; → &lt;code&gt;7.3.6&lt;/code&gt; にした。&lt;/p&gt;
&lt;p&gt;これでビルドが通るようになる。&lt;/p&gt;
&lt;p&gt;ビルド後に &lt;code&gt;Regex&lt;/code&gt; 周りでエラーが出るようになった。
&lt;code&gt;Regex.IsMatch&lt;/code&gt;メソッドで型推論できなくなった箇所があったので、型注釈して通るようにする。
&lt;code&gt;IsMatch(ReadOnlySpan&amp;lt;Char&amp;gt;)&lt;/code&gt; が .NET 7 から増えたっぽいのでこの影響かなあ。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.ismatch?view=net-7.0#system-text-regularexpressions-regex-ismatch(system-readonlyspan((system-char)))&quot; title=&quot;Regex.IsMatch Method (System.Text.RegularExpressions) | Microsoft Learn&quot;&gt;Regex.IsMatch Method (System.Text.RegularExpressions) | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;また例外の文面も変わったらしくて、 1 つのテストケースで期待値を新しいものに合わせた。&lt;/p&gt;
&lt;p&gt;GitHub Actions の job で &lt;code&gt;actions/setup-dotnet@v3&lt;/code&gt; に指定してるバージョンも &lt;code&gt;6.0.x&lt;/code&gt; → &lt;code&gt;7.0.x&lt;/code&gt; に変える。&lt;/p&gt;
&lt;p&gt;この際 act 使った GitHub Actions の workflow テスト中に Docker が死んでしまった。
最近 disk 容量少なくなってて、 Docker image が pull されたタイミングで枯渇したの原因(一時的に残 100KB くらいになってた。やば)。&lt;/p&gt;
&lt;p&gt;解消するために以下を参考にしたが、 dockerd の再起動だけでは解決しなかった。
&lt;a href=&quot;https://stackoverflow.com/questions/68218291/docker-error-with-read-only-file-system-unknown/70071216#70071216&quot; title=&quot;dockerfile - Docker error with read-only file system unknown - Stack Overflow&quot;&gt;dockerfile - Docker error with read-only file system unknown - Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;結果的に空き容量確保後に PC 再起動したら直った。&lt;/p&gt;
&lt;p&gt;これにて .NET 7 化は完了。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;PowerShellGet-PSResourceGet-a-href-https-github-com-krymtkts-pocof-pull-54-title-54-54-a-&quot; href=&quot;#PowerShellGet-PSResourceGet-a-href-https-github-com-krymtkts-pocof-pull-54-title-54-54-a-&quot;&gt;PowerShellGet → PSResourceGet &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/54&quot; title=&quot;#54&quot;&gt;#54&lt;/a&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;変えたのは &lt;code&gt;Publish-Module&lt;/code&gt; → &lt;code&gt;Publish-PSResource&lt;/code&gt; だけ。
&lt;a href=&quot;/posts/2023-07-09-migrate-dev-environment.html&quot; title=&quot;前回の日記&quot;&gt;前回の日記&lt;/a&gt; にも追記したが、 &lt;code&gt;Get-Module&lt;/code&gt; は &lt;code&gt;Microsoft.PowerShell.Core&lt;/code&gt; の持ち物だったので変える必要なかった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WhatIf&lt;/code&gt; までの確認に留めている。
というのも、結構パラメータが変わっておりホンマにうまく動くんかこれ...というのがあるため。
&lt;a href=&quot;https://github.com/PowerShell/PSResourceGet/issues?q=is%3Aissue+is%3Aopen+Publish-PSResource&quot; title=&quot;PSResourceGet の Issues&quot;&gt;PSResourceGet の Issues&lt;/a&gt; 見て &lt;code&gt;Publish-PSResource&lt;/code&gt; の状況をつかもうとしてるがまだまだあんまわからない。
それに &lt;code&gt;Publish-PSResource&lt;/code&gt; の前例を検索してもほぼない。&lt;/p&gt;
&lt;p&gt;既存モジュールでいきなりやるのはちょい不安。やるならまずテスト用の module 作ってそれで試すが吉とみた。
が、作るのめんどくせええええ、というのは否めない。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;おわり&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;/posts/2022-11-27-writing-cmdlet-in-fsharp-pt8.html&quot; title=&quot;昔の日記&quot;&gt;昔の日記&lt;/a&gt; で書いてた platyPS の prerelease 使うとエラーになる件忘れていてまた引っかかったが、久しぶりの pocof 開発なんとかできてよかった。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 16 Jul 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-07-09-migrate-dev-environment.html</guid><link>https://krymtkts.github.io/posts/2023-07-09-migrate-dev-environment.html</link><title>開発環境をプチ移行する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;旧聞だが、 PowerShellGet が PSResourceGet に改名した。
2023 秋の PowerShell 7.4 リリース前には GA するらしいのでそれに移行することとした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devblogs.microsoft.com/powershell/psresourceget-preview-is-now-available/&quot; title=&quot;PSResourceGet Preview is Now Available - PowerShell Team&quot;&gt;PSResourceGet Preview is Now Available - PowerShell Team&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ついでに VS Code から VS Code Insiders にも移行したのでメモがてら残す。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;VS-Code-Insiders&quot; href=&quot;#VS-Code-Insiders&quot;&gt;VS Code Insiders&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;VS Code Insiders にする理由はまだ順番待ちの GitHub Copilot Chat が落ちてきたら即使えるようにするためだ。
もうかなり待っていても来ないが、最新の VS Code じゃないと動かないとかなんとか。&lt;/p&gt;
&lt;p&gt;わたしは chocolatey で入れる。これも以下のコマンドを打つだけだ。
&lt;a href=&quot;https://community.chocolatey.org/packages/vscode-insiders&quot; title=&quot;Chocolatey Software | Visual Studio Code Insiders 1.80.0.20230704&quot;&gt;Chocolatey Software | Visual Studio Code Insiders 1.80.0.20230704&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bat&quot;&gt;choco install vscode-insiders -y
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;VS Code とは別に VS Code Insiders がインストールされる。&lt;/p&gt;
&lt;p&gt;ここで &lt;code&gt;code-insiders .&lt;/code&gt; を実行して VS Code Insiders を開くとまっさらになっている。はじめは Setting Sync が有効でないためだ。
最も簡単に VS Code から VS Code Insiders へ設定を移行する方法は、一時的に VS Code Insiders で Stable の Setting Sync に繋ぐ方法だろう。
わたしの場合は非公開になってしまった拡張機能以外はこれで問題なく移行できた。
移行後は Setting Sync を off にして Stable から離脱、再度 Setting Sync を on にして Insiders へ接続するようにすれば良い。
たまに Stable と Insiders で非互換があるらしいし、自身の利用端末全てで VS Code Insiders に移行するまではリスクがあると見て分けておくのが無難やろな。
例外的に、認証情報の類は &lt;code&gt;setting.json&lt;/code&gt; に token を書くような野蛮なもの以外すべてポチポチ再認証が必要だが、それでも随分楽なもんやな。&lt;/p&gt;
&lt;p&gt;VS Code Insiders ではコマンドも &lt;code&gt;code&lt;/code&gt; から &lt;code&gt;code-insiders&lt;/code&gt; に変わるので、これまた PowerShell の profile で該当の箇所を変えてやる必要がある。
普段から &lt;code&gt;code&lt;/code&gt; を使う場面は &lt;a href=&quot;https://github.com/x-motemen/ghq&quot; title=&quot;ghq&quot;&gt;ghq&lt;/a&gt; で一覧から選択した repo を開くときだけだ。
面倒なので今回 current directory を開く関数を profile に新設した。さすがに &lt;code&gt;code-insiders&lt;/code&gt; って長すぎるので許容できない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# もとからあるやつ&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Set-SelectedRepository&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    ghq list | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Pocof&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-First&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Location&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(ghq root)/&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&amp;quot;&lt;/span&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set-Alias&lt;/span&gt; gcd &lt;span class=&quot;hljs-built_in&quot;&gt;Set-SelectedRepository&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Option&lt;/span&gt; AllScope&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 新設&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Open-SelectedRepository&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;(&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;ValidateSet&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Stable&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Insider&amp;#x27;&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Channel&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Insider&amp;#x27;&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$code&lt;/span&gt; = &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$Channel&lt;/span&gt;) {&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Stable&amp;#x27;&lt;/span&gt; { &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;code&amp;#x27;&lt;/span&gt; }&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Insider&amp;#x27;&lt;/span&gt; { &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;code-insiders&amp;#x27;&lt;/span&gt; }&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Set-SelectedRepository&lt;/span&gt; &amp;amp;&amp;amp; &amp;amp; &lt;span class=&quot;hljs-variable&quot;&gt;$code&lt;/span&gt; .&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set-Alias&lt;/span&gt; gcode &lt;span class=&quot;hljs-built_in&quot;&gt;Open-SelectedRepository&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Option&lt;/span&gt; AllScope
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これ &lt;code&gt;gcd&lt;/code&gt; で選択肢がなかった場合の &lt;code&gt;code-insiders&lt;/code&gt; が current directory になるのでなんか改善したほうが良いけど、いったんこれで。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;PSResourceGet&quot; href=&quot;#PSResourceGet&quot;&gt;PSResourceGet&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;PSResourceGet のインストールも大したことない。ブログに示されるコマンドでインストールすれば良い。
わたしの場合は管理者権限で全ユーザ対象にインストールしてるので、追加でそのオプションだけつける。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Install-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; Microsoft.PowerShell.PSResourceGet &lt;span class=&quot;hljs-literal&quot;&gt;-AllowPrerelease&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; AllUsers
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;インストールしたら PowerShell の profile で書いてる PowerShellGet のコマンドを PSResourceGet のものに置き換える。
今回対象になったのは以下だ。基本 &lt;code&gt;Module&lt;/code&gt; だった部分が &lt;code&gt;PSResource&lt;/code&gt; になるだけだが、オプションも微妙に変わっているところもある。
profile で使ってるコマンドは以下の感じに置き換わる。意外に多かった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Get-InstalledModule&lt;/code&gt; -&amp;gt; &lt;code&gt;Get-InstalledPSResource&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-Scope&lt;/code&gt; の指定がいる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;Install-Module&lt;/code&gt; -&amp;gt; &lt;code&gt;Install-PSResource&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-AllowPrerelease&lt;/code&gt; -&amp;gt; &lt;code&gt;-Prerelease&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;-AllowClobber&lt;/code&gt; -&amp;gt; default 挙動に。 従来の挙動は &lt;code&gt;-NoClobber&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;Set-PSRepository&lt;/code&gt; -&amp;gt; &lt;code&gt;Set-PSResourceRepository&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;追記: こいつもあったわ &lt;code&gt;-InstallationPolicy Trusted&lt;/code&gt; -&amp;gt; &lt;code&gt;-Trusted&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;Get-Module&lt;/code&gt; -&amp;gt; &lt;del&gt;&lt;code&gt;Get-PSResource&lt;/code&gt;&lt;/del&gt;&lt;ul&gt;
&lt;li&gt;追記:&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Get-PSResource&lt;/code&gt; は PowerShellGet v3 にはあったけど PSResourceGet にはない。つまり何に変わったんだこれ？&lt;/li&gt;&lt;li&gt;&lt;code&gt;Get-Module&lt;/code&gt; は &lt;code&gt;Microsoft.PowerShell.Core&lt;/code&gt; が Source なのでそのまま使えば良いのか&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;Find-Module&lt;/code&gt; -&amp;gt; &lt;code&gt;Find-PSResource&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;Update-Module&lt;/code&gt; -&amp;gt; &lt;code&gt;Update-PSResource&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;これらの破壊的変更、どうも repo の CHANGELOG にまとまってないぽくて、すべてを一箇所で見つけることはできなかった。
&lt;a href=&quot;https://devblogs.microsoft.com/powershell/psresourceget-preview-is-now-available/&quot; title=&quot;PowerShell Team のブログ&quot;&gt;PowerShell Team のブログ&lt;/a&gt; とか追っていったら全貌わかるかもだが、面倒だ。
&lt;code&gt;NoClobber&lt;/code&gt; の挙動とかは以下を参考にした。信頼の Ironman 。
&lt;a href=&quot;https://blog.ironmansoftware.com/powershellget-v3/&quot; title=&quot;What&amp;#39;s new in PowerShellGet v3?&quot;&gt;What&amp;#39;s new in PowerShellGet v3?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これらの変更を profile に施したあとうまく動いてるのが確認できたら仕事機にも反映する。&lt;/p&gt;
&lt;p&gt;個人的にちょっとめんどいのが &lt;a href=&quot;https://github.com/aws/aws-tools-for-powershell&quot; title=&quot;AWS Tools for PowerShell&quot;&gt;AWS Tools for PowerShell&lt;/a&gt; との今後の付き合い。
AWS Tools for PowerShell が PSResourceGet に移行するまで、当面は v2 v3 並行稼働という感じになるのだろうか。うまくいくのだろうか。
互換モジュールが提供されてるから、そっちを使うのが良さげ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/CompatPowerShellGet&quot; title=&quot;PowerShell/CompatPowerShellGet: This module provide functions used with PowerShellGet v3 to provide compatibility with scripts expecting PowerShellGet v2&quot;&gt;PowerShell/CompatPowerShellGet: This module provide functions used with PowerShellGet v3 to provide compatibility with scripts expecting PowerShellGet v2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;あと開発環境とは別に &lt;a href=&quot;https://github.com/krymtkts/pocof/&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; の方でも PSResourceGet への移行を反映したい。
具体的にはコマンドの名前が変わったこの辺。これらは Issue にしてればいいかな。未だ .NET 7 にも移行してないから、そういうのもやっていき。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Get-Module&lt;/code&gt; -&amp;gt; &lt;del&gt;&lt;code&gt;Get-PSResource&lt;/code&gt;&lt;/del&gt;&lt;ul&gt;
&lt;li&gt;追記: 先述の通り&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;Publish-Module&lt;/code&gt; -&amp;gt; &lt;code&gt;Publish-PSResource&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;-1&quot; href=&quot;#-1&quot;&gt;追記 1&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;Find-AWSToolsModule&lt;/code&gt; が &lt;code&gt;Find-Module&lt;/code&gt; に依存してて、事前にダミーの &lt;code&gt;Find-Module&lt;/code&gt; してないとエラーになるやつ未だ直ってないようだ。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Find-AWSToolsModule: The term &amp;#39;PowerShellGet\Find-Module&amp;#39; is not recognized as a name of a cmdlet, function, script file, or executable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;自分用にはこれを回避するために関数を書いてたが、CompatPowerShellGet を使うとこの依存関係が永久に解決できないみたい。
module 違うからなあ...やはり v2 v3 の並行稼働しかなさそう...だいじょぶかな。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Get-PSResource&lt;/code&gt; も戻り値の property に変化があって、対処が必要だった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Path&lt;/code&gt; -&amp;gt; &lt;code&gt;InstalledLocation&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;-2&quot; href=&quot;#-2&quot;&gt;追記 2&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;PowerShellGet に &lt;code&gt;-AllowPrerelease&lt;/code&gt; つけて v3 をインストールしてたがややこしい。
PSResourceGet にない Cmdlet もあったりして危ない。おまえのことやぞ &lt;code&gt;Get-PSResource&lt;/code&gt; 。
PowerShellGet は prerelease 版を入れないようにするのが無難。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 09 Jul 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-07-02-rebuild-blog-with-fable-pt9.html</guid><link>https://krymtkts.github.io/posts/2023-07-02-rebuild-blog-with-fable-pt9.html</link><title>Fable でブログを再構築する pt.9</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築している。&lt;/p&gt;
&lt;p&gt;細々とした修正だけやった。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/23&quot; title=&quot;#23&quot;&gt;#23&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;O&amp;#39;reilly の F# 本で勉強してたからか最近まで &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/interpolated-strings&quot; title=&quot;Interpolated strings - F# | Microsoft Learn&quot;&gt;Interpolated strings - F# | Microsoft Learn&lt;/a&gt; わかってなかったのでそれに書き換えたり。あと &lt;a href=&quot;https://github.com/fable-compiler/fable-node&quot; title=&quot;Fable.Node&quot;&gt;Fable.Node&lt;/a&gt; の process 予約語で警告が出るやつも自前でかいた binding を使うことで解消した。
利用する範囲そんなに多くなければ最小の範囲に絞り込んで Node.js の binding を書き Fable.Node 排除するのもよいが、なんとなく先延ばしにした。&lt;/p&gt;
&lt;p&gt;RSS Feed に取り組み始めた。
まずは RSS feed の構造を知らんかったので、自ブログの出力した &lt;a href=&quot;https://krymtkts.github.io/feed.xml&quot; title=&quot;feed.xml&quot;&gt;feed.xml&lt;/a&gt; と &lt;a href=&quot;https://validator.w3.org/feed/docs/rss2.html&quot; title=&quot;RSS 2.0 specification&quot;&gt;RSS 2.0 specification&lt;/a&gt; &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc4287&quot; title=&quot;RFC 4287 - The Atom Syndication Format&quot;&gt;RFC 4287 - The Atom Syndication Format&lt;/a&gt; を学んでる。
自ブログは RSS 2.0 で書かれていて &lt;code&gt;atom:link&lt;/code&gt; セクションを使うことで追加の機能を入れてるらしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rssboard.org/rss-validator/&quot; title=&quot;RSS Validator&quot;&gt;RSS Validator&lt;/a&gt; なんてのも初めて知ったわ。試しに feed.xml を読ませてみたところ valid な RSS Feed と判定されてるが推奨事項がチラホラあった。
Fable でやるにあたってこういうのも丁寧に対応できると良いな。&lt;/p&gt;
&lt;p&gt;feed.xml を作るにあたって sitemap.xml を書いたのと同じく自前で &lt;a href=&quot;https://github.com/Zaid-Ajaj/Fable.SimpleXml&quot; title=&quot;Fable.SimpleXml&quot;&gt;Fable.SimpleXml&lt;/a&gt; を使って書くのか、楽に Node.js のモジュールを使うのかがちょっと悩ましいところ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jpmonette/feed&quot; title=&quot;jpmonette/feed: A RSS, Atom and JSON Feed generator for Node.js, making content syndication simple and intuitive! 🚀&quot;&gt;jpmonette/feed: A RSS, Atom and JSON Feed generator for Node.js, making content syndication simple and intuitive! 🚀&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/dylang/node-rss&quot; title=&quot;dylang/node-rss: RSS feed generator for Node.&quot;&gt;dylang/node-rss: RSS feed generator for Node.&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;この辺りが有名なモジュールのようだけど最後のコミットがちょっと古い。
&lt;a href=&quot;https://github.com/jpmonette/feed&quot; title=&quot;feed&quot;&gt;feed&lt;/a&gt; の場合以下みたいにオブジェクトをもりもり書いていくだけっぽくて、 Fable.SimpleXml 使って自分で構築するのと変わらんのでは...
という懸念があり、なんか自分でやったほうが良さそうに思っている。 RSS/Atom の知識乏しいけど、既存の焼き直しであればまあできるやろ的な。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// 以下はあくまでサンプルだがこれは書いてて楽しくなさそうな気配&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// feed&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; feed = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Feed&lt;/span&gt;({&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtkts&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;description&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtktss blog&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http://krymtkts.github.io/&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;link&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http://krymtkts.github.io/&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;image&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http://krymtkts.github.io/image.png&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;favicon&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http://krymtkts.github.io/favicon.ico&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;copyright&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Copyright © 2019-2023 krymtkts&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;updated&lt;/span&gt;: &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Date&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;),&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;feedLinks&lt;/span&gt;: {&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;json&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://krymtkts.github.io/json&amp;quot;&lt;/span&gt;,&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;atom&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://krymtkts.github.io/atom&amp;quot;&lt;/span&gt;,&lt;br /&gt;  },&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// node-rss&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; feed = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;RSS&lt;/span&gt;({&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtkts&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;description&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;krymtktss blog&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;site_url&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http://krymtkts.github.io&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;image_url&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http://krymtkts.github.io/icon.png&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;copyright&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Copyright © 2019-2023 krymtkts&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;pubDate&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;May 20, 2012 04:00:00 GMT&amp;quot;&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;feed_url&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http://krymtkts.github.io/rss.xml&amp;quot;&lt;/span&gt;,&lt;br /&gt;});
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; generateRssFeed (conf&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; RssFeed) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; items &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; rss &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;            title &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; conf.title&lt;br /&gt;            description &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; conf.description&lt;br /&gt;            link &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; conf.link&lt;br /&gt;            lastBuildDate &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; now.ToString(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;yyyy-MM-dd&amp;quot;&lt;/span&gt;)&lt;br /&gt;            generator &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;blog-fable&amp;quot;&lt;/span&gt;&lt;br /&gt;            items &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; items&lt;br /&gt;        } &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; convertToSimpleXml&lt;br /&gt;&lt;br /&gt;    rss&lt;br /&gt;    &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; serializeXml&lt;br /&gt;    &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt;) &lt;span class=&quot;hljs-string&quot;&gt;@&amp;quot;&amp;lt;?xml version=&amp;quot;&amp;quot;1.0&amp;quot;&amp;quot; encoding=&amp;quot;&amp;quot;UTF-8&amp;quot;&amp;quot;?&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;イメージ雑いけどこんな感じにならんかな？
自前でやることによって進捗が鈍化しそうやけど、しゃーないかという感じ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 02 Jul 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-06-25-rebuild-blog-with-fable-pt8.html</guid><link>https://krymtkts.github.io/posts/2023-06-25-rebuild-blog-with-fable-pt8.html</link><title>Fable でブログを再構築する pt.8</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築している。&lt;/p&gt;
&lt;p&gt;先日の開発サーバ作成、 404 に生成済み HTML 表示するのもわかったので完了した。&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/20&quot; title=&quot;#20&quot;&gt;#20&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;再ビルドのパフォ改善は、今やらないと言うかできないと判断した。
指定のファイル一覧だけを対象に HTML や関連する XML を再生成するって感じの機構を取り入れる必要があって、根本的に変えないとどうにもならんので、一通り必要と考える機能が揃ってから着手したい。&lt;/p&gt;
&lt;p&gt;次に XML の類に取り掛かった。まずはデータ量少ない sitemap.xml のほう。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/22&quot; title=&quot;#22&quot;&gt;#22&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;sitemap.xml に関しては何の XML か知らなかったが検索エンジンのクローラにより正確な情報を与えるためのデータらしいのは理解した。
今の Cryogen で生成されてる sitemap.xml がめちゃくちゃテキトーに作られてるのも含め。
こちらを参考に知識を補った。
&lt;a href=&quot;https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap&quot; title=&quot;Build and Submit a Sitemap | Google Search Central  |  Documentation  |  Google for Developers&quot;&gt;Build and Submit a Sitemap | Google Search Central  |  Documentation  |  Google for Developers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我がブログの運用に限れば、計測タグも設置してないし何 1 つ SEO 効果を期待してないけど、 wev.dev の PageSpeed Insights とかで良いスコアは出したい。
ハイスコア狙いのゲーム感覚なのだ。
だからこそいま全部同じ &lt;code&gt;loc&lt;/code&gt; の全部同じ &lt;code&gt;lastmod&lt;/code&gt; が出てるので、 &lt;code&gt;loc&lt;/code&gt; を URL 毎にするとか &lt;code&gt;lastmod&lt;/code&gt; に最終更新日を反映させるとかちょっとはマシにしたい。&lt;/p&gt;
&lt;p&gt;折角なので &lt;code&gt;priority&lt;/code&gt; も定めてみる。とりま index は &lt;code&gt;1.0&lt;/code&gt; として Archives, Tags はカテゴリ系なので生成の度更新するし &lt;code&gt;0.9&lt;/code&gt; としてみた。
新しめのページは高い方が良いんか？
結局全てが生成ファイルなので単純に post は投稿日付降順くらいしかできなそうやけど、ちょっとめんどいなあと思ったので今は控えて全部同じ &lt;code&gt;0.8&lt;/code&gt; とした。
代わりに投稿日付とは別に front matter に日付を持たせて、更新日付ぽい扱いができるよう悪あがきだけしておいた。&lt;/p&gt;
&lt;p&gt;Fable で XML を操作するのには &lt;a href=&quot;https://github.com/Zaid-Ajaj/Fable.SimpleXml&quot; title=&quot;Zaid-Ajaj/Fable.SimpleXml&quot;&gt;Zaid-Ajaj/Fable.SimpleXml&lt;/a&gt; を使う。 &lt;a href=&quot;https://github.com/Zaid-Ajaj/Feliz&quot; title=&quot;Feliz&quot;&gt;Feliz&lt;/a&gt; 作者の作品。
使いたい機能は大体誰かが用意してくれていてありがたい限りである。&lt;/p&gt;
&lt;p&gt;femto で足したらエラーになった。でも &lt;code&gt;fsproj&lt;/code&gt; はちゃんと変更されてたから大丈夫ぽい。 npm モジュールが無いからエラーになる。
README には &lt;code&gt;paket&lt;/code&gt; 使って足せと書いてあった(先に読め)。うちは使ってないから単純に &lt;code&gt;dotnet add&lt;/code&gt; で足す。これでも十分シンプルに使えるし。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet add .\src\App.fsproj package Fable.SimpleXml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Fable.SimpleXml は XML 宣言の読み込みは対応してるけど出力は対応してないみたいなので、手書き文字列を添えて出力してやる必要があった。
それ以外に関しては Feliz で HTML を書くのと同じ感覚で書ける。
参考として、以下に Fable.SimpleXml を使って sitemap.xml の文字列を作成する箇所を抜粋する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; generateSitemap root locs &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; urls &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            locs&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; Seq.map (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; loc &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                node&lt;br /&gt;                    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;br /&gt;                    []&lt;br /&gt;                    [ node &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;loc&amp;quot;&lt;/span&gt; [] [ text &lt;span class=&quot;hljs-string&quot;&gt;$&amp;quot;&lt;span class=&quot;hljs-subst&quot;&gt;{root}&lt;/span&gt;&lt;span class=&quot;hljs-subst&quot;&gt;{loc.loc}&lt;/span&gt;&amp;quot;&lt;/span&gt; ]&lt;br /&gt;                      node &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;lastmod&amp;quot;&lt;/span&gt; [] [ text loc.lastmod ]&lt;br /&gt;                      &lt;span class=&quot;hljs-comment&quot;&gt;//   node &amp;quot;changefreq&amp;quot; [] [ text &amp;quot;monthly&amp;quot; ]&lt;/span&gt;&lt;br /&gt;                      node &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;priority&amp;quot;&lt;/span&gt; [] [ text loc.priority ] ])&lt;br /&gt;            &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; List.ofSeq&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; urlSet &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            node&lt;br /&gt;                &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;urlset&amp;quot;&lt;/span&gt;&lt;br /&gt;                [ attr.value (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;xmlns&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http://www.sitemaps.org/schemas/sitemap/0.9&amp;quot;&lt;/span&gt;)&lt;br /&gt;                  attr.value (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;xmlns:xsi&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;) ]&lt;br /&gt;                urls&lt;br /&gt;&lt;br /&gt;        urlSet&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; serializeXml&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt;) &lt;span class=&quot;hljs-string&quot;&gt;@&amp;quot;&amp;lt;?xml version=&amp;quot;&amp;quot;1.0&amp;quot;&amp;quot; encoding=&amp;quot;&amp;quot;UTF-8&amp;quot;&amp;quot;?&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;XML 宣言も文字列なんぞ使わずにサクッと書けるとカッコよいのだけど。&lt;/p&gt;
&lt;p&gt;あとコメントアウトがあってダサいが、これは &lt;code&gt;changefreq&lt;/code&gt; も足したいなーと思ってやらなかった残穢だ。
Index, Archives, Tags は post の投稿間隔から自動算出できるが、いま面倒でやらなかったので戒めとして残している。&lt;/p&gt;
&lt;p&gt;これで次は RSS Feed の XML を作ったら最低限必要なものは揃う。スタイルや前後の post へのリンクみたいな細かな調整は必要だろうけど。
RSS Feed の仕組み、例えば既存の投稿に変更がある場合にどうなんの？とかもあんま知らんので、これを機に知識を補いたい。
結構 post 周りのコード手を入れないと Markdown から抽出・生成したタイトル・公開日・ HTML 後続処理に回せんな...
というのがあるので結構ダルそうではあるが、いい感じの手間がかかる点は最後に越える山としてふさわしい(と自分に言い聞かせる)。&lt;/p&gt;
&lt;p&gt;場当たり的なコードも積もってきたし、細々とした気になってる点を補正する等も着手していこう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 25 Jun 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-06-18-rebuild-blog-with-fable-pt7.html</guid><link>https://krymtkts.github.io/posts/2023-06-18-rebuild-blog-with-fable-pt7.html</link><title>Fable でブログを再構築する pt.7</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築している。&lt;/p&gt;
&lt;p&gt;当初開発サーバに使ってた &lt;a href=&quot;https://github.com/tapio/live-server&quot; title=&quot;tapio/live-server&quot;&gt;tapio/live-server&lt;/a&gt; は npm の vulnerability 報告がずっと出てた。
開発用なので構わないといえばそうだがやっぱいい気分ではないので、自力で開発サーバを立てるように変えていく(現在作業中)。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/20&quot; title=&quot;#20&quot;&gt;#20&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;F# Weekly の Sergey Tihon 氏がちょうどよい F# script を書いてるのを見つけたので、それをベースにする。
Web サーバに F# 製の &lt;a href=&quot;https://github.com/SuaveIO/suave&quot; title=&quot;SuaveIO/suave&quot;&gt;SuaveIO/suave&lt;/a&gt; を使うようになる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/34603913/suave-in-watch-mode-during-development&quot; title=&quot;f# - Suave in watch mode (during development) - Stack Overflow&quot;&gt;f# - Suave in watch mode (during development) - Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これに従うと、変更イベントで WebSocket のメッセージをページに送って、ページはメッセージを受け取ったらリロードする、という流れで live reload をすることになる。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ファイルの変更検知して変更イベントを発火する&lt;/li&gt;&lt;li&gt;変更イベントで WebSocket のメッセージ送信する&lt;/li&gt;&lt;li&gt;ページに差し込んだ JavaScript で WebSocket のメッセージを受け取ったら reload する&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;この開発サーバ用 F# スクリプトを開発するにあたり、
F# Interactive 特有の挙動とかあまりわかってなかったので、以下を参照に勉強した。
&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/tools/fsharp-interactive/&quot; title=&quot;F# Interactive (dotnet) Reference | Microsoft Learn&quot;&gt;F# Interactive (dotnet) Reference | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今回ファイルの変更を監視するのと、 &lt;code&gt;dotnet&lt;/code&gt; コマンド実行するのに &lt;a href=&quot;https://fake.build/index.html&quot; title=&quot;FAKE&quot;&gt;FAKE&lt;/a&gt; のモジュールがいくつか必要だったので NuGet から取得する形にした。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nuget.org/packages/Fake.Core.Trace&quot; title=&quot;NuGet Gallery | Fake.Core.Trace 6.0.0&quot;&gt;NuGet Gallery | Fake.Core.Trace 6.0.0&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.nuget.org/packages/Fake.DotNet.Cli&quot; title=&quot;NuGet Gallery | Fake.DotNet.Cli 6.0.0&quot;&gt;NuGet Gallery | Fake.DotNet.Cli 6.0.0&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.nuget.org/packages/Fake.IO.FileSystem&quot; title=&quot;NuGet Gallery | Fake.IO.FileSystem 6.0.0&quot;&gt;NuGet Gallery | Fake.IO.FileSystem 6.0.0&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;FAKE はいつか勉強せなあかんなと思っていたが、タイミング良く使う機会が来た。その良さもなんとなく感じており、なんでも F# で書きたくなる気持ちがわかってくる。&lt;/p&gt;
&lt;p&gt;先述の WebSocket でやり取りする JavaScript は、デプロイするブツには不要だ。
なので今回開発モードをこしらえて、その場合のみ WebSocket 用の JavaScript をロードする &lt;code&gt;script&lt;/code&gt; タグを差し込むようにした。
開発モード自体は SSG 実行時のオプションで渡す形にしている。設定ファイルなしでスクリプトだけで完結する世界観にしたいので。&lt;/p&gt;
&lt;p&gt;この開発用 JavaScript も、そのうち &lt;a href=&quot;https://github.com/fable-compiler/fable-browser/tree/master/src/WebSocket&quot; title=&quot;Fable.Browser.WebSocket&quot;&gt;Fable.Browser.WebSocket&lt;/a&gt; で書いてトランスパイルしたものを使うようにしたい。&lt;/p&gt;
&lt;p&gt;一通り作ってみて、いい感じに動いてるっぽい。
ただし強烈に遅いのと、 Suave で 404 ページを表示する方法がわからないので、今後の課題かな。差分ビルドとかできるとかっこよい。&lt;/p&gt;
&lt;p&gt;以下に今回のハマりどころを記載しておく。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;ハマりどころ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Suave 、 Fable 共にそうだけどドキュメントに書いてないことがチラホラあるので、分からなくてコード読む必要があった。備忘のためいくつかメモを記録しておく。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;Suave&quot; href=&quot;#Suave&quot;&gt;Suave&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;Suave で以下のエラーが出たときは、権限じゃなくてサーバの 設定が足りない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;System.UnauthorizedAccessException: Access to the path &amp;#x27;C:\Program Files\dotnet\sdk\7.0.302\FSharp\_temporary_compressed_files&amp;#x27; is denied.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これを解消するには権限を与えるのではなく、 Sauve がデフォルトで使ってる圧縮ファイルのパスを config に指定しないといけない(デフォでなんかやってくれよめんどくせえ)。
&lt;a href=&quot;https://github.com/SuaveIO/suave/blob/8efe4b32ea0dc52f36c10c8d8fec8191c6ae901c/src/Suave/Web.fs#L42&quot; title=&quot;suave/Web.fs at 8efe4b32ea0dc52f36c10c8d8fec8191c6ae901c · SuaveIO/suave&quot;&gt;suave/Web.fs at 8efe4b32ea0dc52f36c10c8d8fec8191c6ae901c · SuaveIO/suave&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;compressedFilesFolder &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;(home)
&lt;/code&gt;&lt;/pre&gt;&lt;h5 &gt;&lt;a name=&quot;Fake-DotNet&quot; href=&quot;#Fake-DotNet&quot;&gt;Fake.DotNet&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;&lt;code&gt;Fake.DotNet&lt;/code&gt; の使い方は &lt;a href=&quot;https://github.com/SAFE-Stack/SAFE-template&quot; title=&quot;SAFE-Stack のテンプレ&quot;&gt;SAFE-Stack のテンプレ&lt;/a&gt; が参考になる。
&lt;a href=&quot;https://github.com/SAFE-Stack/SAFE-template/blob/db892ace1ecd1589a9a03a484e388a97f3b71718/Build.fs#L70-L75&quot; title=&quot;SAFE-template/Build.fs at db892ace1ecd1589a9a03a484e388a97f3b71718 · SAFE-Stack/SAFE-template&quot;&gt;SAFE-template/Build.fs at db892ace1ecd1589a9a03a484e388a97f3b71718 · SAFE-Stack/SAFE-template&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;command&lt;/code&gt; と &lt;code&gt;args&lt;/code&gt; どう分けるか謎だが、あんまきにしなくていいっぽい。
現に ↓ のように &lt;code&gt;cmd&lt;/code&gt; に引数が混ざっていても動くという。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; cmd &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;fable src&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; args &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;--runScript dev&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; run script with development mode.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; result &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; DotNet.exec (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; { x &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; DotNetCliPath &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dotnet&amp;quot;&lt;/span&gt; }) cmd args
&lt;/code&gt;&lt;/pre&gt;&lt;h5 &gt;&lt;a name=&quot;Fable&quot; href=&quot;#Fable&quot;&gt;Fable&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;Fable に &lt;code&gt;--runScript&lt;/code&gt; をつけて呼び出したときに引数を与えられるのかについては、ドキュメントの記載は見つけられなかったがソースコードを見る限り与えることができる。
&lt;a href=&quot;https://github.com/fable-compiler/Fable/blob/ac4d44997f69d5b1b7109730ccb45e354a4ec368/src/Fable.Cli/Entry.fs#L390&quot; title=&quot;Fable/src/Fable.Cli/Entry.fs at ac4d44997f69d5b1b7109730ccb45e354a4ec368 · fable-compiler/Fable&quot;&gt;Fable/src/Fable.Cli/Entry.fs at ac4d44997f69d5b1b7109730ccb45e354a4ec368 · fable-compiler/Fable&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この形式なので、以下のようにコマンドを打てばよい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dotnet fable src --runScript dev
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;--runScript&lt;/code&gt; で実行するスクリプトの方では、 Node.js の引数の取り方を使えば良い。つまり &lt;code&gt;process.argv&lt;/code&gt; を使う。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fable-compiler/fable-node&quot; title=&quot;Fable.Node&quot;&gt;Fable.Node&lt;/a&gt; を使ってたら &lt;code&gt;process.argv&lt;/code&gt; が簡単に使える。
でも &lt;code&gt;process&lt;/code&gt; は F# の予約語で警告が出るので、気持ち悪いからそのうち自前で binding するように直すかも。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 18 Jun 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-06-11-rebuild-blog-with-fable-pt6.html</guid><link>https://krymtkts.github.io/posts/2023-06-11-rebuild-blog-with-fable-pt6.html</link><title>Fable でブログを再構築する pt.6</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築しようとしている。&lt;/p&gt;
&lt;p&gt;GitHub Actions で GitHub Pages のデプロイするようにした。
あと個人プロジェクトの repo を deploy したときの root 間違ってたので手直しする必要があった。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/16&quot; title=&quot;#16&quot;&gt;#16&lt;/a&gt;,
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/18&quot; title=&quot;#18&quot;&gt;#18&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GitHub Pages はこちら → &lt;a href=&quot;https://krymtkts.github.io/blog-fable/index.html&quot; title=&quot;Blog Title - February&quot;&gt;Blog Title - February&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GitHub Actions を使った GitHub Pages の deploy は現行ブログでもやりたかったネタで、長らく放置してた。
ブログ再構築のタイミングなら導入するのにちょうどよいので以下の記事を参考に導入した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#publishing-with-a-custom-github-actions-workflow&quot; title=&quot;Publishing with a custom GitHub Actions workflow - Configuring a publishing source for your GitHub Pages site - GitHub Docs&quot;&gt;Publishing with a custom GitHub Actions workflow - Configuring a publishing source for your GitHub Pages site - GitHub Docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mamezou-tech.com/blogs/2022/09/08/github-pages-new-deploy-method/&quot; title=&quot;カスタムワークフローで GitHub Pages デプロイが可能に | 豆蔵デベロッパーサイト&quot;&gt;カスタムワークフローで GitHub Pages デプロイが可能に | 豆蔵デベロッパーサイト&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;注意点は先述の通り、個人プロジェクトの場合は &lt;code&gt;{account}.github.io/{repo-name}/&lt;/code&gt; がページの root になる点くらい。
これは自動的に付与されるので、その前提でリンクやら調整する必要がある。
ただし開発サーバでは自動で付与されないので、 root は &lt;code&gt;docs&lt;/code&gt; にしつつ他は repo name のディレクトリを介すようにする。
今回のケースでは以下を調整していい感じにした。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;諸々のリンクに repo name のディレクトリを入れる&lt;/li&gt;&lt;li&gt;開発用サーバの index や 404 を repo name のディレクトリを介すよう調整する&lt;/li&gt;&lt;li&gt;&lt;code&gt;actions/upload-pages-artifact&lt;/code&gt; の &lt;code&gt;path&lt;/code&gt; は repo name のディレクトリにする ← 重要&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;いまの workflow と開発サーバの設定を転記しておく。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable/blob/4cb5d81ac8099889dd55e50ae39ebb20935e96f5/.github/workflows/gh-pages.yml&quot; title=&quot;blog-fable/gh-pages.yml at 4cb5d81ac8099889dd55e50ae39ebb20935e96f5 · krymtkts/blog-fable · GitHub&quot;&gt;blog-fable/gh-pages.yml at 4cb5d81ac8099889dd55e50ae39ebb20935e96f5 · krymtkts/blog-fable · GitHub&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deploy&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;GitHub&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Pages&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;on:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;push:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;branches:&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;main&amp;quot;&lt;/span&gt;]&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;workflow_dispatch:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;permissions:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;contents:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;read&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;pages:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;write&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;id-token:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;write&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;concurrency:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;group:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;pages&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;cancel-in-progress:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;jobs:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;build:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;runs-on:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;steps:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Checkout&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Setup&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Pages&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/configure-pages@v2&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Setup&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;.NET&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/setup-dotnet@v3&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;with:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;dotnet-version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;7.0&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.x&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/setup-node@v3&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;with:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;node-version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;18&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Install&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dependencies&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;install&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Build&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pages&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;build&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Upload&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;artifact&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/upload-pages-artifact@v1&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;with:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;docs/blog-fable/&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# ここ重要。 docs/ ではない&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;deploy:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;github-pages&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;url:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${{&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;steps.deployment.outputs.page_url&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;}}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;runs-on:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;needs:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;build&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;steps:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deploy&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;GitHub&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Pages&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;id:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;deployment&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/deploy-pages@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;開発サーバは今暫定的に &lt;a href=&quot;https://github.com/tapio/live-server&quot; title=&quot;live-server&quot;&gt;live-server&lt;/a&gt; を使っているが、その場合以下のように index と 404 を指定して起動する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;live-server docs --open=blog-fable/index.html --entry-file=blog-fable/404.html
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;長々と書いたが、個人ページを作るなら &lt;code&gt;{account}.github.io/&lt;/code&gt; の repo を使うだろうから、そんなに心配することはない。&lt;/p&gt;
&lt;p&gt;今回の GitHub Pages の対応でベタ書きだったパス類をエントリポイントへ全部まとめるようにしたので、幾分設定しやすくなった。
これでサイトマップとフィードの XML 、開発サーバの置き換えあたりに着手できる。一段落までもうちょいかな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 11 Jun 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-06-04-rebuild-blog-with-fable-pt5.html</guid><link>https://krymtkts.github.io/posts/2023-06-04-rebuild-blog-with-fable-pt5.html</link><title>Fable でブログを再構築する pt.5</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築しようとしている。&lt;/p&gt;
&lt;p&gt;雑多な更新 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/11&quot; title=&quot;#11&quot;&gt;#11&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/12&quot; title=&quot;#12&quot;&gt;#12&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/13&quot; title=&quot;#13&quot;&gt;#13&lt;/a&gt; 。
favicon が出てなかったの直したり、 404 ページ作ったり、あとやりたかった module の整理。&lt;/p&gt;
&lt;p&gt;ファイルは雑に 共通系 -&amp;gt; 生成系 -&amp;gt; アプリ の依存関係に切り分けて、それぞれのファイル内に雑多な module が詰まってるようにした。 元は 2 ファイルだったのでこれでもだいぶマシかな。でも module の整理は今結構雑な感じで置いていて、もうちょいと関数を細切れにできるのでその後また見直す。互いに変な依存関係してたり、 生成系関数のインタフェースが不一致だったりするのとか、気になるのが残ってる感じ。
それより優先して細々した直したい部分があってわざと置いてる。&lt;/p&gt;
&lt;p&gt;細々した直したい部分というのは navbar で、 Bulma (暫定的にこいつで行くことにしたから)の &lt;a href=&quot;https://bulma.io/documentation/components/navbar/&quot; title=&quot;Navbar Component&quot;&gt;Navbar Component&lt;/a&gt; 見てみたのだけどこんな複雑に使い分けなあかんの？みたいな div div した感じになってて、これ導入したくないなあと感じてた。
nav -&amp;gt; ul -&amp;gt; li でだめなんか。
&lt;a href=&quot;https://v1.tailwindcss.com/components/navigation&quot; title=&quot;Tailwind の Navigation&quot;&gt;Tailwind の Navigation&lt;/a&gt; だと思ったようなシンプルな感じのものが得られるのだけど、あの大量の class をつけるのもなあという感じだった。
世の中 Navbar はみんなグリグリ動いたり深ーい階層の div div したやつを、好きでやってんのかな。いやないはずだ。
とりあえず自分のやつではやりたくないなって感じの奴らなことは確かな感触を持った。
ちょうど &lt;a href=&quot;https://bulma.io/documentation/components/tabs/&quot; title=&quot;Tabs Component&quot;&gt;Tabs Component&lt;/a&gt; というもっとシンプルで ul -&amp;gt; li に被せられるスタイルがあったので、これを適用する感じにし、諸々調整した。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/14&quot; title=&quot;#14&quot;&gt;#14&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/15&quot; title=&quot;#15&quot;&gt;#15&lt;/a&gt;
Tailwind の Navigation で得られるシンプルなやつに近い感じ。モバイルなんかでもグリグリ UI が変わらず同じ見た目でスライドするだけなので、この方がいい。&lt;/p&gt;
&lt;p&gt;とはいえこういう div div したくないというのは &lt;a href=&quot;https://github.com/Zaid-Ajaj/Feliz&quot; title=&quot;Feliz&quot;&gt;Feliz&lt;/a&gt; で HTML を直書きする方向性を選んだから書くのがだるいのも多少ある。
もちろん生成物が div div してるとキモいなというのが一番だけど。
ここにきて&lt;a href=&quot;https://fulma.github.io/Fulma/#home&quot; title=&quot;Fulma&quot;&gt;Fulma&lt;/a&gt;を導入したら楽になるのか？というのを Navbar のくだりで多少試したのだけど、なんか Feliz より書き味良くなかった(慣れの問題かも)ので今は据え置きにしている。
仮に Fulma を導入するとなると、あの div div した生成物を受け入れるってことやからな。&lt;/p&gt;
&lt;p&gt;div div 書きまくってどれだけあれが好きでないかというのが伝わっただろうが、仕事ではそういう div div した構造を目当てのレイアウトを得るために書くこともあるということは断っておきたい。
必要な div なら仕方がない。でも自分の趣味プロで書くのであれば、仕事と同じことしても余白が狭すぎるし、極力簡素にしたいということでね。&lt;/p&gt;
&lt;p&gt;もう最近やったことまとめと化してるけど、これも振り返りにちょうどよいので悪くない。
ひとり(プラス GitHub Copilot サンと ChatGPT サン)で黙々とやってると、フィードバック得られるところも限られるからな。こういうことをダラダラと書き連ねるだけでも、次のアイデアにつながる。
ちょうどこの記事をしたためいている中で、 footer 要素がないわ...というのに気づけた。
とりあえずこの記事を push してから、それに取り掛かることとする。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 04 Jun 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-05-28-rebuild-blog-with-fable-pt4.html</guid><link>https://krymtkts.github.io/posts/2023-05-28-rebuild-blog-with-fable-pt4.html</link><title>Fable でブログを再構築する pt.4</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築しようとしている。&lt;/p&gt;
&lt;p&gt;YAML で書かれたメタデータ(Front Matter というらしい)の抽出を作った。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/5&quot; title=&quot;#5&quot;&gt;#5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;またそれに伴って記事へのリンクのタイトルに front matter が使えるようになったので諸々手直しした。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/10&quot; title=&quot;#10&quot;&gt;#10&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;front matter 抽出については、まず最初に remark 使ってみた。
けど、 &lt;a href=&quot;https://github.com/fable-compiler/ts2fable&quot; title=&quot;ts2fable&quot;&gt;ts2fable&lt;/a&gt; で binding を出力したところ &lt;a href=&quot;https://github.com/unifiedjs/unified&quot; title=&quot;unified&quot;&gt;unified&lt;/a&gt; 、 &lt;a href=&quot;https://github.com/remarkjs/remark&quot; title=&quot;remark&quot;&gt;remark&lt;/a&gt; とその Plugin たちの間で型の整合性が取れなかった。
整合取ろうとしたら自力で調整しないとどうにもならないので、とてもじゃないがすぐには使えないと判断して早々に諦めた。
remark のパーサを作る部分を JavaScript で書いて、それを import する形でやれば簡単にできるが、そこは F# で書いてこそ意味がある。&lt;/p&gt;
&lt;p&gt;というわけで marked のまま、 front matter の抽出を古典的な方法、つまり正規表現を使って自力でやった。
front matter 自体は YAML で書くので、 &lt;a href=&quot;https://github.com/eemeli/yaml&quot; title=&quot;eemeli/yaml&quot;&gt;eemeli/yaml&lt;/a&gt; を導入した。 yaml module は ts2fable で Fable の binding が生成されなかったので、雑なやつを手で書いた。&lt;/p&gt;
&lt;p&gt;front matter 抽出ができるようになると、 Archives や Tags で作ってたページリンクにメタデータのタイトルを使えるようになる。
タグ付けされたページにタグリンクもつけられるし。
それに伴い諸々の手直しをし、ついでに参照元のコードのまま使ってた CSS とかを最新のものまで更新した。とりまいまは CDN のを借りてる。
ついでに highlight.js の CSS を足した。
Index Archives Tags が出揃って、ページにタグが付き、 syntax highlighting も効くようになったから、結構ブログっぽくなってきたのでは？&lt;/p&gt;
&lt;p&gt;諸々のスタイル調整はぜんぜんやってないけど。
スタイル調整に対する欲求が低くて、どうしようか考えるとのがとてつもなくだるい。とりあえず色味だけは Solarized Dark でいこうと思ってるけど。ただ Solarized Dark のコンテンツに Solarized Dark の syntax highlighting だと境界ワカランのちゃうかな？というのはある。なので現にいまのブログでは Solarized Light をコンテンツに使ってるし。
スタイルに関してはこのまま Bulma でいくか決めないといけないのだけど、こういう感じの自分であまり考えたくないケースに案外ハマってるかも、しらんけど。&lt;/p&gt;
&lt;p&gt;最近の機能拡充に伴ってエントリーポイントである &lt;code&gt;App.fs&lt;/code&gt; と &lt;code&gt;Helpers.fs&lt;/code&gt; がむやみに肥大化しているので、そろそろ整理したいところ。
いまは &lt;code&gt;App.fs&lt;/code&gt; に色々書いてるけど、これ多分 &lt;code&gt;render&lt;/code&gt; 関数以外はもう module に切り出した方がいいねんよな。&lt;/p&gt;
&lt;p&gt;イメージ的には、 &lt;code&gt;render&lt;/code&gt; 関数で用意した関数を組み合わせるだけにする。
いま navbar に表示するページだったり index に最新のポストを表示するのが固定でやってるけど、こういうのも front matter に寄せたらスッキリするかな。
設定ファイルとかはなしで、ディレクトリ構造とコンテンツの front matter だけで制御できたら楽かなあ。&lt;/p&gt;
&lt;p&gt;道程は長い。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 28 May 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-05-20-bump-openssh-chocolatey.html</guid><link>https://krymtkts.github.io/posts/2023-05-20-bump-openssh-chocolatey.html</link><title>Chocolatey で Portable OpenSSH を更新する 2023</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;久しぶりに、 Chocolatey に OpenSSH の β が降ってきてた。&lt;/p&gt;
&lt;p&gt;前回は 2019 年だった。 &lt;a href=&quot;/posts/2019-03-31-win-openssh-is-gone.html&quot; title=&quot;Windows10 の更新で OpenSSH が逝った&quot;&gt;Windows10 の更新で OpenSSH が逝った&lt;/a&gt; &lt;a href=&quot;/posts/2019-06-29-season-of-openssh-error.html&quot; title=&quot;また OpenSSH が動かなくなる季節がやってきた&quot;&gt;また OpenSSH が動かなくなる季節がやってきた&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://community.chocolatey.org/packages/openssh#versionhistory&quot; title=&quot;Chocolatey Software | Win32 OpenSSH (Universal Installer) 9.2.2-beta1&quot;&gt;Chocolatey Software | Win32 OpenSSH (Universal Installer) 9.2.2-beta1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ので更新してみたところ、以下のエラーログが。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;ERROR: There is a configured instance of the SSHD service, please specify the /SSHServerFeature to confirm it is OK to shutdown and upgrade the SSHD service at this time.&lt;br /&gt;The upgrade of openssh was NOT successful.&lt;br /&gt;Error while running &amp;#x27;C:\ProgramData\chocolatey\lib\openssh\tools\chocolateyinstall.ps1&amp;#x27;.&lt;br /&gt; See log for details.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;はて？ &lt;code&gt;sshd&lt;/code&gt; 入れてたっけ？と思ったが見たら入ってた。 chocolatey で自動で入ったんやっけ？&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get-service&lt;/span&gt; *ssh*&lt;br /&gt;&lt;br /&gt;Status   Name               DisplayName&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt;   &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;               &lt;span class=&quot;hljs-literal&quot;&gt;-----------&lt;/span&gt;&lt;br /&gt;Running  ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;          ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;&lt;br /&gt;Running  sshd               sshd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;いる！しかも実行中なのがなんかキモい。&lt;/p&gt;
&lt;p&gt;こいつを停止させるのはあとにするとして、ひとまず &lt;code&gt;choco upgrade&lt;/code&gt; を成功させるにはどうしたら良いか。
こういうときはちゃんとマニュアルを読む。 Chocolatey の Package Source のリンクを辿れば良い。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gitlab.com/DarwinJS/ChocoPackages/-/tree/master/openssh#-params-sshserverfeature-install-and-uninstall&quot; title=&quot;openssh · master · DarwinJS / ChocoPackages · GitLab&quot;&gt;openssh · master · DarwinJS / ChocoPackages · GitLab&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;h3 &gt;&lt;a name=&quot;-params-39-quot-SSHServerFeature-quot-39-Install-and-Uninstall-&quot; href=&quot;#-params-39-quot-SSHServerFeature-quot-39-Install-and-Uninstall-&quot;&gt;-params &amp;#39;&amp;quot;/SSHServerFeature&amp;quot;&amp;#39; (Install and Uninstall)&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Also install sshd Windows Service - including opening port 22.
If this parameter is not included on an upgrade or uninstall and
the sshd server is installed - an error is generated. You must
use this switch to indicate you have made preparations for the
sshd service to be interrupted or removed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;どう見てもこれ。以下を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;choco upgrade openssh &lt;span class=&quot;hljs-literal&quot;&gt;-params&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;quot;/SSHServerFeature&amp;quot;&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この後再起動をして Windows Terminal で PowerShell を開くと作業が完了した。
すっかり忘れていが、わたしの &lt;code&gt;$PROFILE&lt;/code&gt; は「 &lt;code&gt;ssh-agent&lt;/code&gt; のサービスがいない ≒ Windows の OpenSSH が更新された」と判定し、インストールスクリプトを実行するのだった。
&lt;a href=&quot;https://gist.github.com/krymtkts/f8af667c32b16fc28a815243b316c5be#file-microsoft-powershell_profile-ps1-L910-L923&quot; title=&quot;ここ&quot;&gt;ここ&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# install ssh-agent service if not exists.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# it will be triggered after updating Windows OpenSSH.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (! (&lt;span class=&quot;hljs-variable&quot;&gt;$SshAgent&lt;/span&gt; = (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Service&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ssh-agent&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; SilentlyContinue))) {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;install-sshd&lt;/span&gt;.ps1&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Service&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ssh-agent&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-StartupType&lt;/span&gt; Automatic&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Start-Service&lt;/span&gt; ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;elseif&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$SshAgent&lt;/span&gt;.StartType &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Disabled&amp;#x27;&lt;/span&gt;) {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Service&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ssh-agent&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-StartupType&lt;/span&gt; Automatic&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Start-Service&lt;/span&gt; ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Start-Service&lt;/span&gt; ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;インストールスクリプトは Portable OpenSSH に提供されるもので &lt;code&gt;ssh-agent&lt;/code&gt; と &lt;code&gt;sshd&lt;/code&gt; が一緒くたにインストールされてたのね...なんか他にやりようないか考えても良いのかな。&lt;/p&gt;
&lt;p&gt;とりあえずこれで事なきを得た。 &lt;code&gt;sshd&lt;/code&gt; の起動タイプも手動になっておりヨシ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;get-service&lt;/span&gt; *ssh* | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name,Status,StartType&lt;br /&gt;&lt;br /&gt;Name       Status StartType&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;       &lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt;&lt;br /&gt;ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt; Running Automatic&lt;br /&gt;sshd      Stopped    Manual
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description><pubDate>Sat, 20 May 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-05-14-rebuild-blog-with-fable-pt3.html</guid><link>https://krymtkts.github.io/posts/2023-05-14-rebuild-blog-with-fable-pt3.html</link><title>Fable でブログを再構築する pt.3</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; でブログを再構築しようとしている。
こちらに手をかけてることで最近 &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; 触っておらず多少不安になってきたが、もう少し Fable に慣れるまではお預け。&lt;/p&gt;
&lt;p&gt;簡単に Index のページに最新ポストをコピるのと、 投稿一式から Archive ページを作るのをやってみている。 &lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/4&quot; title=&quot;#4&quot;&gt;#4&lt;/a&gt;
徐々にコード量が増えることでここは関数にしておいて～とか、コレコレをモジュールにしておいて～とか、楽しくなってきた。
一緒に Tags のページを作りたかったのだけど、いま Markdown 内のタグはじめとしたメタデータをパースしてないから作れない。
先に &lt;a href=&quot;https://github.com/remarkjs/remark&quot; title=&quot;remark&quot;&gt;remark&lt;/a&gt; の導入やらないと投稿のメタデータであるタグは(自力で書かない限り)抜けないから、後回しにしておいた。&lt;/p&gt;
&lt;p&gt;今回 Archive ページを作るにあたりコードを書いてると、設定で分ける想定をしてコードを汎化した方がスッキリする雰囲気になってきた。
元は完全に自分用のイメージで作っているので、設定に基づいて出力をどうこうするというのは考えてなかった。
現時点ではベタの部分と、設定(というか関数の引数)によって挙動を決める部分が混じり合っているので、徐々に後者に倒していく。&lt;/p&gt;
&lt;p&gt;とはいえまだ Tags ページと RSS ができてないので、今後の予定としては以下かなと。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/markedjs/marked&quot; title=&quot;marked&quot;&gt;marked&lt;/a&gt; → &lt;a href=&quot;https://github.com/remarkjs/remark&quot; title=&quot;remark&quot;&gt;remark&lt;/a&gt; へ移行する&lt;/li&gt;&lt;li&gt;Markdown ファイルのメタデータ(YAML)が読めるようになるので Tags ページが作れるようになる&lt;/li&gt;&lt;li&gt;RSS 機能を作成する&lt;/li&gt;&lt;li&gt;全体的な汎化で設定の切り出し&lt;/li&gt;&lt;li&gt;ブログのカラーテーマを作る(今は元コードから引き継いだ &lt;a href=&quot;https://bulma.io/&quot; title=&quot;Bulma&quot;&gt;Bulma&lt;/a&gt; のスタイルが適用されてるだけ)&lt;/li&gt;&lt;li&gt;既存ブログとの互換性調整 etc&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;いまんとこ毎週末のスキマ時間で亀進捗出してるので、多少作業が多かろうが大丈夫な気がしてきたな。
最後の互換性のやつだけあんま自信ないけど、リンク切れだけは起こらないように慎重に URL を調整する。
RSS フィードのは、わたしがリーダー側の仕組みがよくわかってなくて、どうなるかわからん。
実際過去に自分が購読してるフィードも全部再配信みたいになってることがあった。せめてそういうのはなくしたいが、先述の通りどうなるかわからん。
わたしの観測範囲ではわたし以外にも一人だけ RSS 購読者がいるっぽいし、たまーに記事が参照されてることもあるので、なるべき気をかけたい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと GitHub の streak 365 まで 100 日切ってた。残りも淡々と続けてこー。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 14 May 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-05-07-rebuild-blog-with-fable-pt2.html</guid><link>https://krymtkts.github.io/posts/2023-05-07-rebuild-blog-with-fable-pt2.html</link><title>Fable でブログを再構築する pt.2</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; の話。
Fable でブログを再構築しようとしている。&lt;/p&gt;
&lt;p&gt;repo 公開時点で &lt;code&gt;README.md&lt;/code&gt; をレンダリングするだけに留めていたので、ブログらしく post と固定ページ を出力できるように最低限手を加えた。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable/pull/2&quot; title=&quot;#2&quot;&gt;#2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;あと node module に型を与える Fable bindings を利用しようと思い、 &lt;a href=&quot;https://github.com/markedjs/marked&quot; title=&quot;markedjs/marked&quot;&gt;markedjs/marked&lt;/a&gt;, &lt;a href=&quot;https://github.com/highlightjs/highlight.js&quot; title=&quot;highlightjs/highlight.js&quot;&gt;highlightjs/highlight.js&lt;/a&gt; でそれを試した。
これが結構大変で、まだ慣れてない。&lt;/p&gt;
&lt;p&gt;bindings は自動生成できる。それには &lt;a href=&quot;https://github.com/fable-compiler/ts2fable&quot; title=&quot;fable-compiler/ts2fable&quot;&gt;fable-compiler/ts2fable&lt;/a&gt; を利用する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# こんなん。型定義されてない module には使えない。&lt;/span&gt;&lt;br /&gt;npx ts2fable node_modules\@types\marked\index.d.ts src/bindings/Marked.fs&lt;br /&gt;npx ts2fable node_modules\@types\highlightjs\index.d.ts src/bindings/HighlightJs.fs
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;で出力された型を Fable の F# コードで利用するのだけど、うまく使うために色々覚えないといけない Fable 独自の型・関数・演算子がある。
&lt;code&gt;ImportAttribute&lt;/code&gt; 、 Union Type の &lt;code&gt;U2&lt;/code&gt; その他大勢、動的キャスト演算子 &lt;code&gt;!!&lt;/code&gt; と Anonymous record の組み合わせ、 &lt;code&gt;jsOptions&amp;lt;&amp;#39;a&amp;gt;&lt;/code&gt; ...
まだ勉強中だが、早い話 &lt;a href=&quot;https://fable.io/docs/communicate/js-from-fable.html&quot; title=&quot;Fable · Call JS from Fable&quot;&gt;Fable · Call JS from Fable&lt;/a&gt; に載ってるの全部知っといた方というか知っとかないとキツイ雰囲気を感じている。
何故なら Fable の真髄であろう JavaScript と F# の型で守られた相互運用がそこに詰まっており、知らないとうまくできないから。&lt;/p&gt;
&lt;p&gt;寝かしつけ中にこのページ重要そうなの気づいて何度も読んだけど、実際に書いてみると全く活かせてない。また何度も読み直してる。
何の気なく書かれてる一行のサンプルコードが重要だったり。 JavaScript の Module system に詳しいとピンとくるんかなー。
このテーマに関しては GPT-4 に聞いたところでホラ吹いてくるので、自力で勉強せなあかん。&lt;/p&gt;
&lt;p&gt;あと ts2fable で自動生成できない場合は自力で bindings を書く必要があるところも、パンチが効いてる。
今の marked で Syntax Highlighting を使うには&lt;a href=&quot;https://github.com/markedjs/marked-highlight&quot; title=&quot;markedjs/marked-highlight: Add code highlighting to marked&quot;&gt;markedjs/marked-highlight: Add code highlighting to marked&lt;/a&gt; を使う。
けどこいつには Type Declarations &lt;code&gt;.d.ts&lt;/code&gt; が提供されてないので、今回は &lt;code&gt;Fable.Core.JsInterop&lt;/code&gt; の &lt;code&gt;importMember&lt;/code&gt; で茶を濁した。
highlight.js の方も、実は Type Definitions が古くて新しいインタフェースになってない。&lt;/p&gt;
&lt;p&gt;このように Fable の技術スタックは JavaScript のそれの上に乗っかって相互に混ざり合ってるので、両方に対して結構詳しくなるまで辛い気がする。
ただその頂きを超えたところに Fable の楽しみがあるのかも、しらんけど。
まあ書いていておもろいのは確かで、色々つまづきながら進めている。&lt;/p&gt;
&lt;p&gt;あとここまでやって気づいたのだけど、 marked 自体には Markdown 中に書かれた &lt;code&gt;title&lt;/code&gt; とか &lt;code&gt;tag&lt;/code&gt; とかを読み取る機能ないっぽい。
実現しようとしたらなんか自分で &lt;code&gt;---&lt;/code&gt; でファイルコンテンツ区切って YAML にパースするとかしないとだめみたい。
そもそもこのメタ情報の部分 YAML だとこの機会に初めて知ったわ。
自力で書いてもいいけど、この際 &lt;a href=&quot;https://github.com/remarkjs/remark&quot; title=&quot;remarkjs/remark&quot;&gt;remarkjs/remark&lt;/a&gt; みたいなプラグインでそれが実現できるやつを使うのもいいかなと思った。
Markdown のレンダリング部分を換装するのは大変じゃなさそうなので、 navbar 作るとか RSS 作るとかの後に回す。&lt;/p&gt;
&lt;p&gt;他にも、開発用途で問題ないとはいえ &lt;a href=&quot;https://github.com/tapio/live-server&quot; title=&quot;tapio/live-server&quot;&gt;tapio/live-server&lt;/a&gt; にいちいち脆弱性の警告出るのも煩わしく、ここを F# のスクリプトに置き換えたい。&lt;/p&gt;
&lt;p&gt;やりたいこと盛りだくさん。年内には SSG 乗り換え実施したいな...なんとなく。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 07 May 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-04-30-rebuild-blog-with-fable.html</guid><link>https://krymtkts.github.io/posts/2023-04-30-rebuild-blog-with-fable.html</link><title>Fable でブログを再構築する pt.1</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; の練習を始めた。&lt;/p&gt;
&lt;p&gt;Fable にしたのはフロントエンドのエコシステムと統合するのに良さそうだったから。
いまの Clojure 製 Cryogen はフロントエンドとは切り離された感じで、一応 Bootstrap を使ってりはしてるが module 管理とかしてない。なのでフロントエンドの依存性の管理みたいのも一緒にしたいなーと考えていた。&lt;/p&gt;
&lt;p&gt;今使ってる Clojure 製の &lt;a href=&quot;https://cryogenweb.org/&quot; title=&quot;Cryogen&quot;&gt;Cryogen&lt;/a&gt; と同じ雰囲気を F# で再現するなら &lt;a href=&quot;https://github.com/ionide/Fornax&quot; title=&quot;ionide/Fornax&quot;&gt;ionide/Fornax&lt;/a&gt; が正にそんな感じっぽかった。
でも折角なので HTML, JavaScript, CSS 共に F# へ統合した感じにしたい。 Fable ならそれができそうに思えた。&lt;/p&gt;
&lt;p&gt;実際のところ Fable は F# を他言語へ変換するトランスパイラなので、静的サイトジェネレーターとして使うにはオーバスペックな感じはある。
けど、こんな機会でもないと一生触らないテクノロジなので、やるならこっちやろ！と考えた。&lt;/p&gt;
&lt;p&gt;実現したいことは以下の通り。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Markdown で書いたコンテンツを静的サイトに変換する(Cryogen と同じ使用感)&lt;/li&gt;&lt;li&gt;RSS feed の XML を出す(Cryogen で出したのと同じやつ)&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;ここ 2, 3 週間ほど、子供の寝かしつけ中とかに片手間で Fable やその周辺ツール・モジュールのドキュメントとか諸々の repo を見ていた。けどあんまドキュメント充実しておらず、テンプレプロジェクトを生成して壊してを繰り返してようやく雰囲気がわかってきた。見た目は同じでも中身は違うわ、ってかんじ。&lt;/p&gt;
&lt;p&gt;色々試行錯誤した成果として先述の 1 を最小限に実現できたので、一旦日記にまとめる。
&lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;実現手段はいくつか調査した。
まず Fable 作者の Fable で静的サイトを作った例&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;が既にある。
でも激古なためかわたしが理解不足なのか、全くもって動かすことができなかった。
また &lt;a href=&quot;https://bulma.io/&quot; title=&quot;Bulma&quot;&gt;Bulma&lt;/a&gt; という CSS Framework の Fable wrapper である &lt;a href=&quot;https://fulma.github.io/Fulma/#home&quot; title=&quot;Fulma&quot;&gt;Fulma&lt;/a&gt; のテンプレ&lt;sup&gt;&lt;a id=&quot;footnote-ref-2&quot; href=&quot;#footnote-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;もあったのだけど、これも同様に動かし方がわからなかった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fable-compiler/fable-compiler.github.io&quot; title=&quot;Fable の site&quot;&gt;Fable の site&lt;/a&gt; で使われている &lt;a href=&quot;https://github.com/MangelMaxime/Nacara&quot; title=&quot;MangelMaxime/Nacara&quot;&gt;MangelMaxime/Nacara&lt;/a&gt; を試してみたけど、これ RSS 以外をほぼ自分で組り込むところがなくて F# で書く楽しさなさそうったので却下。&lt;/p&gt;
&lt;p&gt;ここまで来たら、自力で練習がてら Fable の無垢のテンプレに付け足ししていくしかあるまいなとなった。というか周辺ツールの不理解もあって 1 から自分でやらないと無理ゲーと化してた。&lt;/p&gt;
&lt;p&gt;まず &lt;a href=&quot;https://fable.io/docs/2-steps/your-first-fable-project.html&quot; title=&quot;Fable · Start a new project&quot;&gt;Fable · Start a new project&lt;/a&gt; で素朴なプロジェクトを作成しする。&lt;/p&gt;
&lt;p&gt;次に &lt;a href=&quot;https://github.com/fable-compiler/static-web-generator&quot; title=&quot;fable-compiler/static-web-generator&quot;&gt;fable-compiler/static-web-generator&lt;/a&gt; でやってることを移植していく。
ここではエントリポイントで Markdown などのコンテンツを読み込んでテンプレに埋め込み、 HTML にレンダリングした結果をファイル出力している。
なので、まずは素朴な手書きの HTML でいいからファイル出力できる状態にし、その後 React の wrapper を追加する形で進める。&lt;/p&gt;
&lt;p&gt;RSS は、 &lt;a href=&quot;https://fable.io/docs/dotnet/compatibility.html&quot; title=&quot;Fable · .NET and F# compatibility&quot;&gt;Fable · .NET and F# compatibility&lt;/a&gt; を見るに .NET の機能はまあ使えないので、 Node.js で xml を出力するやつを移植することになるハズ。
なんかハードな気配してきた。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;何度も作っては消しを繰り返して得た確かな手順は以下の通り。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fable のプロジェクト作成は &lt;a href=&quot;https://fable.io/docs/2-steps/your-first-fable-project.html&quot; title=&quot;Fable · Start a new project&quot;&gt;Fable · Start a new project&lt;/a&gt; を参照&lt;/li&gt;&lt;li&gt;.NET 系ツールの取り回しは以下を参照&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools&quot; title=&quot;How to manage .NET tools - .NET CLI | Microsoft Learn&quot;&gt;How to manage .NET tools - .NET CLI | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/tools/global-json&quot; title=&quot;global.json overview - .NET CLI | Microsoft Learn&quot;&gt;global.json overview - .NET CLI | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;(後述する) Femto は &lt;a href=&quot;https://fable.io/blog/2019/2019-06-29-Introducing-Femto.html&quot; title=&quot;Fable · Introducing Femto&quot;&gt;Fable · Introducing Femto&lt;/a&gt; を参照&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fsprojects/Paket&quot; title=&quot;Paket&quot;&gt;Paket&lt;/a&gt; を使うと依存関係の管理が楽になる(project ファイルから外に出せるから)のだけど、今回は導入しなかった。関係するツールが多すぎて腹いっぱいになってる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 無垢の Fable project 作成する。&lt;/span&gt;&lt;br /&gt;dotnet new install Fable.template&lt;br /&gt;dotnet new fable &lt;span class=&quot;hljs-literal&quot;&gt;--name&lt;/span&gt; blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; blog&lt;span class=&quot;hljs-literal&quot;&gt;-fable&lt;/span&gt;&lt;br /&gt;git init&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;--allow-empty&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Initial commit.&amp;#x27;&lt;/span&gt;&lt;br /&gt;git add .&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Add minimal Fable template.&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# dotnet tool を更新する。&lt;/span&gt;&lt;br /&gt;dotnet tool update fable&lt;br /&gt;dotnet tool update femto&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 動くことを確認する。&lt;/span&gt;&lt;br /&gt;npm install&lt;br /&gt;npm run &lt;span class=&quot;hljs-built_in&quot;&gt;start&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# global.json の更新方法わからないので力づくで書き換えて更新する。&lt;/span&gt;&lt;br /&gt;dotnet new globaljson &lt;span class=&quot;hljs-literal&quot;&gt;--sdk-version&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;7.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;203&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--roll-forward&lt;/span&gt; latestFeature &lt;span class=&quot;hljs-literal&quot;&gt;--force&lt;/span&gt;&lt;br /&gt;dotnet tool restore
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;build target が .Net Core 2.0 なので .Net 7 にする。
&lt;code&gt;src\App.fsproj&lt;/code&gt; を編集する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-patch&quot;&gt; &amp;lt;Project Sdk=&amp;quot;Microsoft.NET.Sdk&amp;quot;&amp;gt;&lt;br /&gt;   &amp;lt;PropertyGroup&amp;gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    &amp;lt;TargetFramework&amp;gt;netstandard2.0&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    &amp;lt;TargetFramework&amp;gt;net7&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;&lt;br /&gt;   &amp;lt;/PropertyGroup&amp;gt;&lt;br /&gt;   &amp;lt;ItemGroup&amp;gt;&lt;br /&gt;     &amp;lt;Compile Include=&amp;quot;App.fs&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Fable も最新版の 4 にする。
これには &lt;a href=&quot;https://github.com/Zaid-Ajaj/Femto&quot; title=&quot;Femto&quot;&gt;Femto&lt;/a&gt; という tool を使うみたい。 Femto は packet と npm の仲介役のようなやつで、 Nuget から Fable のモジュールを持ってきたらついでに npm してくれるようなやつっぽい。
さっぱりわからんが、コマンド打ったら確かに更新された。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;femto install Fable.Core .\src&lt;br /&gt;femto install Fable.Browser.Dom .\src
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;↓ こうなった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-patch&quot;&gt;   &amp;lt;ItemGroup&amp;gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    &amp;lt;PackageReference Include=&amp;quot;Fable.Browser.Dom&amp;quot; Version=&amp;quot;2.2.0&amp;quot; /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    &amp;lt;PackageReference Include=&amp;quot;Fable.Core&amp;quot; Version=&amp;quot;3.2.3&amp;quot; /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    &amp;lt;PackageReference Include=&amp;quot;Fable.Browser.Dom&amp;quot; Version=&amp;quot;2.14.0&amp;quot; /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    &amp;lt;PackageReference Include=&amp;quot;Fable.Core&amp;quot; Version=&amp;quot;4.0.0&amp;quot; /&amp;gt;&lt;/span&gt;&lt;br /&gt;   &amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;npm run start&lt;/code&gt; &lt;code&gt;npm run build&lt;/code&gt; あたりが動いてたら大丈夫だろう。
(&lt;code&gt;dotnet tool restore&lt;/code&gt; が &lt;code&gt;postinstall&lt;/code&gt; で走る記述になってる)&lt;/p&gt;
&lt;p&gt;webpack も古かったのでとりあえず上げておいたが、 SSG したいだけなのでこれらは後ほど消した。&lt;/p&gt;
&lt;p&gt;ついでに solution も作っとく。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet new sln&lt;br /&gt;dotnet sln add ./src
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ここまでやってまだテンプレが最新化されただけ...&lt;/p&gt;
&lt;p&gt;ここからが本番。
無味乾燥したテンプレに &lt;a href=&quot;https://github.com/fable-compiler/static-web-generator&quot; title=&quot;fable-compiler/static-web-generator&quot;&gt;fable-compiler/static-web-generator&lt;/a&gt; の要素を足していく。&lt;/p&gt;
&lt;p&gt;以下の Fable の package が使われており、そのうちいくつかは deprecated されてる。分割されている package を追うのは直に repo でコードを追うしかなく、なかなかハードな道のりだった。
そして調べた内容で書き換えをした。書き換えの内容は &lt;a href=&quot;https://github.com/krymtkts/blog-fable&quot; title=&quot;krymtkts/blog-fable&quot;&gt;krymtkts/blog-fable&lt;/a&gt; を直に見るのが良い(書くのめんどい)。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fable.PowerPack ← &lt;a href=&quot;https://github.com/fable-compiler/fable-powerpack&quot; title=&quot;fable-compiler/fable-powerpack: Utilities for Fable apps&quot;&gt;fable-compiler/fable-powerpack: Utilities for Fable apps&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fable-compiler/fable-powerpack/issues/63&quot; title=&quot;Split Fable.PowerPack in multiple packages? · Issue #63 · fable-compiler/fable-powerpack&quot;&gt;Split Fable.PowerPack in multiple packages? · Issue #63 · fable-compiler/fable-powerpack&lt;/a&gt; 分割された&lt;/li&gt;&lt;li&gt;そもそも使ってなくね？ということで移植しない&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;Fable.React ← &lt;a href=&quot;https://github.com/Zaid-Ajaj/Feliz&quot; title=&quot;Zaid-Ajaj/Feliz&quot;&gt;Zaid-Ajaj/Feliz&lt;/a&gt; 使えと&lt;/li&gt;&lt;li&gt;Fable.Import 系はデカすぎて repo が分かれた &lt;a href=&quot;https://github.com/fable-compiler/fable-import/issues/80&quot; title=&quot;Track repo splits · Issue #80 · fable-compiler/fable-import&quot;&gt;Track repo splits · Issue #80 · fable-compiler/fable-import&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;Fable.Import.Browser ← &lt;a href=&quot;https://github.com/fable-compiler/fable-browser&quot; title=&quot;fable-browser&quot;&gt;fable-browser&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Fable.Import.Node ← &lt;a href=&quot;https://github.com/fable-compiler/fable-node&quot; title=&quot;fable-compiler/fable-node: Bindings for node.js native modules&quot;&gt;fable-compiler/fable-node: Bindings for node.js native modules&lt;/a&gt; めちゃ古だがまだ動くらしい？&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;Fulma ← 今回は使わなかった&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;これら新しい package を移植し多少のコードを変更することで、やっと Markdown(今は &lt;code&gt;README.md&lt;/code&gt; のみ) → HTML とパースして表示できるようになった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;ひとまずここまで。&lt;/p&gt;
&lt;p&gt;まだたった 1 ページを出力できただけで先は長いが、 Fable の雰囲気わかってきてできそうな感触を得ている。&lt;/p&gt;
&lt;p&gt;やっぱ Node.js の変更周り全然わからんことだらけなので、そこは &lt;a href=&quot;https://github.com/MangelMaxime/Nacara/blob/master/src/Nacara.Core/Node.Extra.fs#L8&quot; title=&quot;Nacara/Node.Extra.fs at master · MangelMaxime/Nacara&quot;&gt;Nacara/Node.Extra.fs at master · MangelMaxime/Nacara&lt;/a&gt; のイケてる実装を参照するなどして組んでいけたら良さそう。&lt;/p&gt;
&lt;p&gt;あとやっぱ F# は .NET へ重依存なので .NET を部分的にしか使わない Fable だとかなり書き味が違う。これに慣れるのはちょっとかかりそう。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fable-compiler/static-web-generator&quot; title=&quot;fable-compiler/static-web-generator: Simple Fable Node.js app to generate static pages&quot;&gt;fable-compiler/static-web-generator: Simple Fable Node.js app to generate static pages&lt;/a&gt; &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;footnote-2&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://fulma.github.io/Fulma/#template&quot; title=&quot;Template - Fulma&quot;&gt;Template - Fulma&lt;/a&gt; &lt;a href=&quot;#footnote-ref-2&quot; data-footnote-backref aria-label=&quot;Back to reference 2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 30 Apr 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-04-23-1-year-of-pocof.html</guid><link>https://krymtkts.github.io/posts/2023-04-23-1-year-of-pocof.html</link><title>pocof の 1 年間</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;明日 2023-04-24 で pocof の開発を始めてから 1 年になるらしい。
開発しない週があったり、そもそも進捗は亀だが、続けてきたのは我ながらエライ。
折角なので Git の commit history を基に活動を振り返ってみる。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;書き捨てのスクリプトは以下。案外役に立ったのでなんか小綺麗にして使える感じにしてもいいな。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# merge commit 除く。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$logs&lt;/span&gt; = git log &lt;span class=&quot;hljs-literal&quot;&gt;--pretty&lt;/span&gt;=format:&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;%cd,%s&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--date&lt;/span&gt;=iso&lt;span class=&quot;hljs-literal&quot;&gt;-strict&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-Csv&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Header&lt;/span&gt; CommitDate, Message | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Message &lt;span class=&quot;hljs-operator&quot;&gt;-NotLike&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Merge pull request*&amp;#x27;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        CommitDate = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.CommitDate&lt;br /&gt;        Message = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Message&lt;br /&gt;    } }&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 年月ごとのコミット数。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$logs&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.CommitDate.ToString(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;yyyy-MM&amp;#x27;&lt;/span&gt;) } | &lt;span class=&quot;hljs-built_in&quot;&gt;Group-Object&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name, Count&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 追加・削除行数。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{}&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$stats&lt;/span&gt; = git log &lt;span class=&quot;hljs-literal&quot;&gt;--numstat&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--pretty&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;%cd&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--date&lt;/span&gt;=iso&lt;span class=&quot;hljs-literal&quot;&gt;-strict&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;) {&lt;br /&gt;        { &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\d{4}-\d{2}-\d{2}&amp;#x27;&lt;/span&gt; } {&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;        default {&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-split&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`t&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;.Count &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;) {&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;.ContainsKey(&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;)) {&lt;br /&gt;                    &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;]&lt;br /&gt;                    &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;] = [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;                        Add = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] + &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt;.Add&lt;br /&gt;                        Remove = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] + &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt;.Remove&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;                    &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;] = [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;                        Add = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]&lt;br /&gt;                        Remove = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;} &lt;span class=&quot;hljs-literal&quot;&gt;-End&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt; }&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$stats&lt;/span&gt;.GetEnumerator() | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{Add = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Value.Add; Remove = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.value.remove } } | &lt;span class=&quot;hljs-built_in&quot;&gt;Measure-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; add, remove &lt;span class=&quot;hljs-literal&quot;&gt;-Sum&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Format-Table&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 年月ごとの追加・削除行数。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{}&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$monthly&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$stats&lt;/span&gt;.GetEnumerator() | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{YM = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Key.ToString(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;yyyy-MM&amp;#x27;&lt;/span&gt;); Add = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Value.Add; remove = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.value.Remove } } | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;.ContainsKey(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.YM)) {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;.YM&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;.YM&lt;/span&gt;] = [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;            Add = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Add + &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt;.Add&lt;br /&gt;            Remove = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Remove + &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt;.Remove&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;.YM&lt;/span&gt;] = [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;            Add = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Add&lt;br /&gt;            Remove = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Remove&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;} &lt;span class=&quot;hljs-literal&quot;&gt;-End&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt; }&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$monthly&lt;/span&gt;.GetEnumerator() | &lt;span class=&quot;hljs-built_in&quot;&gt;Sort-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Key | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{YM = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Key; Add = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Value.Add; Remove = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.value.remove } }&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ファイルごとの追加・削除行数。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{}&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fileStats&lt;/span&gt; = git log &lt;span class=&quot;hljs-literal&quot;&gt;--numstat&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--pretty&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;%cd&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--date&lt;/span&gt;=iso&lt;span class=&quot;hljs-literal&quot;&gt;-strict&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-split&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`t&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;.Count &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;) {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;&lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;.ContainsKey(&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;)) {&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;]&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;] = [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;                Add = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] + &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt;.Add&lt;br /&gt;                Remove = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] + &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt;.Remove&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;] = [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;                Add = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]&lt;br /&gt;                Remove = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;} &lt;span class=&quot;hljs-literal&quot;&gt;-End&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt; }&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fileStats&lt;/span&gt;.GetEnumerator() | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{File = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Key; Add = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Value.Add; Remove = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Value.Remove } } | &lt;span class=&quot;hljs-built_in&quot;&gt;Sort-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Add, Remove &lt;span class=&quot;hljs-literal&quot;&gt;-Descending&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 年月・ファイルごとの追加・削除行数。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{}&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fileStats&lt;/span&gt; = git log &lt;span class=&quot;hljs-literal&quot;&gt;--numstat&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--pretty&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;%cd&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--date&lt;/span&gt;=iso&lt;span class=&quot;hljs-literal&quot;&gt;-strict&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;) {&lt;br /&gt;        { &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\d{4}-\d{2}-\d{2}&amp;#x27;&lt;/span&gt; } {&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$date&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;        default {&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-split&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`t&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;.Count &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;) {&lt;br /&gt;                &lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$date&lt;/span&gt;.ToString(&amp;#x27;yyyy-MM&amp;#x27;)) &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[2])&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;.ContainsKey(&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;)) {&lt;br /&gt;                    &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;]&lt;br /&gt;                    &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;] = [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;                        Add = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] + &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt;.Add&lt;br /&gt;                        Remove = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] + &lt;span class=&quot;hljs-variable&quot;&gt;$entry&lt;/span&gt;.Remove&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;                    &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt;[&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;] = [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;                        Add = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]&lt;br /&gt;                        Remove = [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$values&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;} &lt;span class=&quot;hljs-literal&quot;&gt;-End&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$ret&lt;/span&gt; }&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fileStats&lt;/span&gt;.GetEnumerator() | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{File = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Key; Add = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Value.Add; Remove = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Value.Remove } } | &lt;span class=&quot;hljs-built_in&quot;&gt;Sort-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; File, Add, Remove
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Merge commit を除いたコミット数が 113 。 2023 年に入ってからは前年より多少活発。&lt;/p&gt;
&lt;p&gt;以下は年月ごとのコミット数。
開発してない月あるんじゃないかって気がしてたが、ギリギリ毎月開発してた様子。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;YM&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Commit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;2022-04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-08&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-12&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-01&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;コードの変更を伴うコミットが今まで 109 あって、
追加された行が 6312 、削除された行が 2821 。44% 位を書き直してるのが意外だった。時期的にはテストコード拡充とそれによるリファクタが大きい要因か。&lt;/p&gt;
&lt;p&gt;以下が年月ごとの追加・削除行数。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;YM&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Add&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Remove&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;2022-04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;717&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;83&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1425&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;386&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-06&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;83&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-07&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;61&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;56&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-08&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;30&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;233&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;145&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;69&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;365&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;170&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-12&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;57&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-01&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;358&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;245&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;214&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;143&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2163&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1134&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;537&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;370&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;ファイル別の分析はちょっと面倒で、 rename したものやドキュメント類も含まれてしまってる。
が、 目 grep した感じだと最近テストを頑張って書いてた &lt;code&gt;Action.fs&lt;/code&gt;, &lt;code&gt;Data.fs&lt;/code&gt; あたりの新陳代謝ができており、それにつられて依存関係の &lt;code&gt;Library.fs&lt;/code&gt; の変更も多いと。
&lt;code&gt;Query.fs&lt;/code&gt; はコア部分なので削除少ないのはおっかなびっくりいじってるからかな？
&lt;code&gt;UI.fs&lt;/code&gt; なんかは全然いじれてないので削除行数少なめ。&lt;/p&gt;
&lt;p&gt;以下がファイルごとの追加・削除行数。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Add&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Remove&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;src/pocof.Test/Tests.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;798&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;798&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof.Test/PocofData.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;705&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;145&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof/Action.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;569&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;179&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof/Data.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;517&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;451&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;470&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;282&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof.Test/PocofQuery.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;459&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;131&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;430&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;261&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.gitignore&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;399&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof/pocof.dll-Help.xml&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;382&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tests/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;263&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;113&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;docs/Select-Pocof.md&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;260&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof/UI.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;238&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;112&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof/pocof.psd1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;231&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;99&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof.Test/PocofAction.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;171&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;psakefile.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;134&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof/{Action.fs =&amp;gt; Data.fs}&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;71&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;82&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof/pocof.fsproj&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;38&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pocof.sln&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;36&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof.Test/pocof.Test.fsproj&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;36&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;README.md&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;33&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.github/workflows/pr.yml&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;30&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LICENSE&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;test/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/pocof.Test/Program.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;{test =&amp;gt; tests}/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;以下が年月・ファイルごとの追加・削除行数。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Add&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Remove&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;2022-04 .gitignore&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;398&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-04 pocof.sln&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;27&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-04 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;57&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-04 src/pocof/pocof.dll-Help.xml&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-04 src/pocof/pocof.fsproj&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;22&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-04 src/pocof/pocof.psd1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;212&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 {test =&amp;gt; tests}/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 docs/Select-Pocof.md&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;181&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 LICENSE&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 pocof.sln&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 psakefile.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;90&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 README.md&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 src/pocof/{Action.fs =&amp;gt; Data.fs}&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;71&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;82&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 src/pocof/Action.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;346&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;46&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 src/pocof/Data.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;89&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;107&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;150&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;112&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 src/pocof/pocof.dll-Help.xml&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;261&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 src/pocof/pocof.fsproj&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 src/pocof/pocof.psd1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;39&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 src/pocof/UI.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;128&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 test/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05 tests/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-06 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-06 src/pocof/pocof.fsproj&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-06 src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;43&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-06 src/pocof/UI.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;34&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-07 src/pocof/Data.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-07 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-07 src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;41&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-07 src/pocof/UI.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-08 psakefile.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-08 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;27&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09 psakefile.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09 README.md&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09 src/pocof/Action.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09 src/pocof/Data.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;88&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;51&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09 src/pocof/pocof.fsproj&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09 src/pocof/pocof.psd1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09 src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09 src/pocof/UI.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-09 tests/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;38&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-10 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;19&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-10 src/pocof/pocof.fsproj&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-10 src/pocof/pocof.psd1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-10 src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-10 src/pocof/UI.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-10 tests/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;26&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11 docs/Select-Pocof.md&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;58&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11 src/pocof/Action.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11 src/pocof/Data.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;29&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11 src/pocof/pocof.dll-Help.xml&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;97&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;57&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11 src/pocof/pocof.fsproj&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11 src/pocof/pocof.psd1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11 src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;66&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;53&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11 src/pocof/UI.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11 tests/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;106&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-12 src/pocof/Data.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;13&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-12 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;23&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-12 src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-12 src/pocof/UI.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-01 src/pocof/Action.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-01 src/pocof/Data.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;204&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;154&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-01 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;14&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-01 src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;124&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-01 src/pocof/UI.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;13&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02 docs/Select-Pocof.md&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02 src/pocof/Action.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;9&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02 src/pocof/Data.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;21&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;22&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02 src/pocof/pocof.dll-Help.xml&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;23&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02 src/pocof/pocof.fsproj&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02 src/pocof/pocof.psd1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02 src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02 src/pocof/UI.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-02 tests/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;81&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 .gitignore&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 pocof.sln&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 psakefile.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 src/pocof.Test/pocof.Test.fsproj&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;36&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 src/pocof.Test/PocofAction.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;113&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 src/pocof.Test/PocofData.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;530&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 src/pocof.Test/PocofQuery.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;404&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;118&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 src/pocof.Test/Program.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 src/pocof.Test/Tests.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;798&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;798&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 src/pocof/Action.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;161&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 src/pocof/Data.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;81&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;112&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-03 tests/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04 .github/workflows/pr.yml&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;30&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04 psakefile.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04 src/pocof.Test/PocofAction.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;58&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04 src/pocof.Test/PocofData.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;175&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;143&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04 src/pocof.Test/PocofQuery.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;55&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04 src/pocof/Action.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;38&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04 src/pocof/Data.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;55&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;42&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04 src/pocof/Library.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;55&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;46&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04 src/pocof/Query.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;53&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04 src/pocof/UI.fs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;7&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04 tests/pocof.Tests.ps1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;2 年目も細々と開発を続けていく。他にやることで Fable でブログ再構築する際の調べ物あるけど、直感ではそんなに失速しないんじゃないかなという気がしている(気だけかも)。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 23 Apr 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-04-16-writing-cmdlet-in-fsharp-pt19.html</guid><link>https://krymtkts.github.io/posts/2023-04-16-writing-cmdlet-in-fsharp-pt19.html</link><title>F#でコマンドレットを書いてる pt.19</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;本当は Fable のメモを記録したかった。 Fable の練習を始めようと思って &lt;a href=&quot;https://fable.io/docs/2-steps/your-first-fable-project.html&quot; title=&quot;Fable · Start a new project&quot;&gt;Fable · Start a new project&lt;/a&gt; を参考にプロジェクトを作成(以下)した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet new fable &lt;span class=&quot;hljs-literal&quot;&gt;--name&lt;/span&gt; krymtkts.github.io
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;その後作成されたプロジェクトを VS Code で開いたら OOM で VS Code がお亡くなりになったので、また今度やるか...という気持ちに切り替わってしまった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;閑話休題。&lt;/p&gt;
&lt;p&gt;また &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;もう 2023-04 も半ばを過ぎ、前回の pocof 0.4.0-alpha から 2 ヶ月経とうとしてるが、粛々とテスト追加と書き直しをしている。&lt;/p&gt;
&lt;p&gt;以前 GitHub Actions の Workflow を作成した時に、 &lt;code&gt;ubuntu_latest&lt;/code&gt; つまり非 Windows でも &lt;a href=&quot;https://github.com/pester/Pester&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; のテストが問題なく緑になるんだなというのがわかった。
これを機に OS の build matrix を組んで Windows, Linux, Mac の 3 つのプラットフォームのテストを有効にしてみた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/48&quot; title=&quot;#48&quot;&gt;#48&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;すべてのプラットフォームでテストが成功したのを見て、 .NET 良く出来てるなあと思った(小並感)。
とはいえ実際に PowerShell on Ubuntu でインタラクティブな動作テストしたわけじゃないし、 .NET はキー周りが大変だと聞く。
わたしが持っているこの辺の知識はこれしかないけど →
&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/console-readkey-improvements-in-net-7/&quot; title=&quot;Console.ReadKey improvements in .NET 7 - .NET Blog&quot;&gt;Console.ReadKey improvements in .NET 7 - .NET Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;なので、いつか時間を取って人力で確認しないといけないのではと思っている。
実際問題、例えば Ubuntu に PowerShell 入れるのって相当動機づけされてないとやらなそうなのだけど、機が熟しつつある。
良いのか悪いのかは知らん。ただ面白そうではある。&lt;/p&gt;
&lt;p&gt;pocof の機能追加はやってなくて、 CLI の UI をいじるところ以外はテストも揃ってきたので、リファクタリングと称して主に構造変換をそれほど伴わない書き直しをしている。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/49&quot; title=&quot;#49&quot;&gt;#49&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;pocof は PowerShell で書かれた &lt;a href=&quot;https://github.com/jasonmarcher/poco&quot; title=&quot;poco&quot;&gt;poco&lt;/a&gt; を F# で写経するところから始まっているので、あまり F# ぽくない感じの箇所が多々ある。その環境の中にコードを足していってるので周りに引きづられて F# ぽくない部分も多かった。&lt;/p&gt;
&lt;p&gt;それらは例えば &lt;code&gt;string&lt;/code&gt; じゃなくて &lt;code&gt;ToString&lt;/code&gt; メソッドを使ってるとか、一番気になってたのは conditional expression の &lt;code&gt;if&lt;/code&gt; をいっぱい使ってた点。
別に &lt;code&gt;if&lt;/code&gt; の方が短く済むときもあるし使っても構わんのだけど、式としてじゃなくて制御構文として使ったときの &lt;code&gt;else&lt;/code&gt; が必須じゃないのが気になってた。また match expression と違って網羅できてるか人目でわからないのが一番心配で、結局これらを &lt;code&gt;match ... with&lt;/code&gt; で書き直すことにした。
その結果、一部には active pattern も利用したりして、パッと見わかりやすくなった気がする。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;if ... then&lt;/code&gt; を &lt;code&gt;match ... with&lt;/code&gt; に書き換えたら以下のようになって、 &lt;code&gt;true&lt;/code&gt; がなんか判然とせんなーという気は多少あるので、自前のロジックに関しては判別共用体に直すとか検討するとより良いのかも知れん。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// before&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; nanigashi x &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;(x)&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// after&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; nanigashi x &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;(x) &lt;span class=&quot;hljs-comment&quot;&gt;// この true ってのもなーんか気に食わん&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こういうところにも active pattern を積極的に使っていったら良いのかもやけど、今回はまだ使わなかった。
データの変換・分解を伴うようなパターンだとバッチリハマった感じだったが、単純なケースに使うと記述量だけ増えて表現力変わらないなとい感触だったため(書き方がまずいのか)。
とはいえ積極的に使いたいものではあった。&lt;/p&gt;
&lt;p&gt;コードの見通しも良くなってきて、そろそろ積み残しタスクにも着手しやすくなってきた感じがする。次やるとしたら &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/35&quot; title=&quot;#35&quot;&gt;#35&lt;/a&gt; あたりかな。&lt;/p&gt;
&lt;p&gt;でもテスト追加とリファクタリングはまだやりたいところが残っていて、悩ましい。 UI のテストを入れて置きたいのと、 &lt;code&gt;PocofQuery&lt;/code&gt; をシンプルにするのと、 &lt;code&gt;Library.fs&lt;/code&gt; から極力ロジックを引き剥がす点だ。
なんかダルそうだなというのもあって手が出しにくいので、積み残しタスク減らしてからやると気分転換になるのかも知れん。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 16 Apr 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-04-09-writing-cmdlet-in-fsharp-pt18.html</guid><link>https://krymtkts.github.io/posts/2023-04-09-writing-cmdlet-in-fsharp-pt18.html</link><title>F#でコマンドレットを書いてる pt.18</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PocofQuery.run&lt;/code&gt; のテストをそれなりに足した。
多少テストが増えてきたので CI が欲しくなってきた。ここで以前立てた Issue &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/34&quot; title=&quot;#34&quot;&gt;#34&lt;/a&gt; を回収しておくとことにした。&lt;/p&gt;
&lt;p&gt;Issue にも書いてたけど、基本 GitHub Docs に書いてたやつをなぞるだけ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net&quot; title=&quot;Building and testing .NET - GitHub Docs&quot;&gt;Building and testing .NET - GitHub Docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-powershell&quot; title=&quot;Building and testing PowerShell - GitHub Docs&quot;&gt;Building and testing PowerShell - GitHub Docs&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;runner image は今の開発環境に合わせて &lt;code&gt;windows-latest&lt;/code&gt; にしておく。 pocof 自体は今後他の OS でも動くことを保証してみたいけど、最初なのでシンプルにいく。
この記事を書いた時点の &lt;code&gt;windows-latest&lt;/code&gt; に含まれるツール類は以下を参照した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/actions/runner-images/blob/main/images/win/Windows2022-Readme.md&quot; title=&quot;runner-images/Windows2022-Readme.md at main · actions/runner-images · GitHub&quot;&gt;runner-images/Windows2022-Readme.md at main · actions/runner-images · GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dotnet&lt;/code&gt; のセットアップは必須のよう。 pocof はまだ 6 なのでそれを使う。&lt;/p&gt;
&lt;p&gt;PowerShell はデフォで 7.2.10 が入ってるらしい。いろんなバージョンで動くことをチェックするのであれば PowerShell の version で &lt;code&gt;matrix&lt;/code&gt; 組むのが妥当だが、これも最初なので簡単に。&lt;/p&gt;
&lt;p&gt;pocof のテストに必要な PowerShell モジュール Pester, PSScriptAnalyzer あたりも入ってるが、肝心の &lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;psake&quot;&gt;psake&lt;/a&gt; が入ってない。ならば workflow で全部ひっくるめで force install するようにしておく。
このへんも &lt;a href=&quot;https://github.com/RamblingCookieMonster/PSDepend&quot; title=&quot;PSDepend&quot;&gt;PSDepend&lt;/a&gt; を使うようにしておけば YAML にかき分ける必要もないし良さげか。&lt;/p&gt;
&lt;p&gt;ここまでやれば &lt;code&gt;psakefile.ps1&lt;/code&gt; に書いた全テストタスクを実行すれば完了する。キャッシュあった方が速いだろうけど、そもそもそんなに時間かからんので対応しないでおく。&lt;/p&gt;
&lt;p&gt;あと一番重要な GitHub Actions の YAML のファイル名と名前の部分、結構いろんな repo みても付け方がバラバラでイケてるパクリ元がない。
ここは GitHub の Pull Request や Actions の画面で見られることを考えてない名称は避けたかった。
最終的に、 &lt;a href=&quot;https://github.com/fsprojects/FSharp.Formatting/tree/3fdd5b9a186e35798d87ceee4bee692374304bed/.github/workflows&quot; title=&quot;FSharp.Formatting&quot;&gt;FSharp.Formatting&lt;/a&gt; の命名規則が気に入ったのでそれを模した。
ファイル名は &lt;code&gt;pull-requests.yml&lt;/code&gt; を短縮して &lt;code&gt;pr.yml&lt;/code&gt; で、名前は &lt;code&gt;Build and Test on Pull Request&lt;/code&gt; だ。これなら GitHub の画面で見ても自然だ。&lt;/p&gt;
&lt;p&gt;出来上がった素朴な YAML はこちら。 &lt;a href=&quot;https://github.com/krymtkts/pocof/blob/1dda928ff1ae56938a26ae70568a9a05807f0852/.github/workflows/pr.yml&quot; title=&quot;pocof/pr.yml&quot;&gt;pocof/pr.yml&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Build&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Test&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Pull&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Request&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;on:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;pull_request:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;branches:&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;main&amp;quot;&lt;/span&gt;]&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;jobs:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;test:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;runs-on:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;windows-latest&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;steps:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Setup&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;.NET&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;actions/setup-dotnet@v3&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;with:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;dotnet-version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6.0&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.x&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Install&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;modules&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PSGallery&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pwsh&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|&lt;br /&gt;          Set-PSRepository PSGallery -InstallationPolicy Trusted&lt;br /&gt;          Install-Module Psake,Pester,PSScriptAnalyzer -Scope CurrentUser -Force&lt;br /&gt;&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Execute&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;All&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Tests&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;shell:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;pwsh&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Invoke-Psake&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;-taskList&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TestAll&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;GitHub Actions の難点としてテストしにくい点があるが、&lt;a href=&quot;https://github.com/nektos/act&quot; title=&quot;nektos/act&quot;&gt;nektos/act&lt;/a&gt; を使えば &lt;code&gt;ubuntu-*&lt;/code&gt; の runner に限ればテストできる。
仕事では act を使ってるが自機には積んでなかったんで、この際に Chocolaty で入れた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dos&quot;&gt;choco install act-cli
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ではテストとばかりに &lt;code&gt;windows-latest&lt;/code&gt; を &lt;code&gt;ubuntu-latest&lt;/code&gt; に変えて実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; act pull_request &lt;span class=&quot;hljs-literal&quot;&gt;--verbose&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--platform&lt;/span&gt; windows&lt;span class=&quot;hljs-literal&quot;&gt;-latest&lt;/span&gt;=catthehacker/ubuntu:act&lt;span class=&quot;hljs-literal&quot;&gt;-latest&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ...省略&lt;/span&gt;&lt;br /&gt;| OCI runtime exec failed: exec failed: unable to &lt;span class=&quot;hljs-built_in&quot;&gt;start&lt;/span&gt; container &lt;span class=&quot;hljs-keyword&quot;&gt;process&lt;/span&gt;: exec: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;pwsh&amp;quot;&lt;/span&gt;: executable file not found &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$PATH:&lt;/span&gt; unknown&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ...省略&lt;/span&gt;&lt;br /&gt;Error: Job &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;test&amp;#x27;&lt;/span&gt; failed
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;なん...だと...
&lt;code&gt;pwsh&lt;/code&gt; コマンドが無いと言われた... &lt;code&gt;act&lt;/code&gt; のセットアップ時に MEDIUM 選んだらどうも入ってないっぽい。
流石は minority の PowerShell 、参ったね。&lt;/p&gt;
&lt;p&gt;しかし &lt;code&gt;act&lt;/code&gt; が使うイメージを見てたら &lt;code&gt;pwsh&lt;/code&gt; というキーワード付きの image があるじゃないの。 &lt;a href=&quot;https://github.com/catthehacker/docker_images#images-available&quot; title=&quot;catthehacker/docker_images: Docker images&quot;&gt;catthehacker/docker_images: Docker images&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;/linux/ubuntu/pwsh - ghcr.io/catthehacker/ubuntu:act-* but with pwsh tools and modules installed&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;こりゃきたな。試す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; act pull_request &lt;span class=&quot;hljs-literal&quot;&gt;--verbose&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--platform&lt;/span&gt; windows&lt;span class=&quot;hljs-literal&quot;&gt;-latest&lt;/span&gt;=ghcr.io/catthehacker/ubuntu:pwsh&lt;span class=&quot;hljs-literal&quot;&gt;-latest&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ...省略&lt;/span&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;Build&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Test&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Pull&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Request&lt;/span&gt;/&lt;span class=&quot;hljs-type&quot;&gt;test&lt;/span&gt;] 🏁  Job succeeded
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;おーいけた。 6 分超かかったけど。
これでなんとか PowerShell の場合でもローカルテストできそう。
Docker Hub に同じイメージ &lt;a href=&quot;https://hub.docker.com/layers/catthehacker/ubuntu/pwsh-latest/images/sha256-3b4b83b4458dd875509bc74b9f1d4ecaa57101c65ec529cb463fed2d859228e4?context=explore&quot; title=&quot;catthehacker/ubuntu:pwsh-latest&quot;&gt;catthehacker/ubuntu:pwsh-latest&lt;/a&gt; あったので、これを使っていこう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;act pull_request &lt;span class=&quot;hljs-literal&quot;&gt;--verbose&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--platform&lt;/span&gt; windows&lt;span class=&quot;hljs-literal&quot;&gt;-latest&lt;/span&gt;=catthehacker/ubuntu:pwsh&lt;span class=&quot;hljs-literal&quot;&gt;-latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;...でもいちいちこのクソながオプション書きたく無いなあ...設定ファイルとかはなさそう。関数にするか psake のタスクにするしかないか。なんか大げさな気がするけど。&lt;/p&gt;
&lt;p&gt;そんなこんなで &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/45&quot; title=&quot;#45&quot;&gt;#45&lt;/a&gt; を作れた。
matrix はまだ設定してないけど、少なくともテスト類は ubuntu でも動くことわかったし、追々対応していく。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;おまけ。&lt;/p&gt;
&lt;p&gt;DockerDesktop でログインしてると、 &lt;code&gt;act&lt;/code&gt; 実行中にある DockerHub から &lt;code&gt;catthehacker/ubuntu:act-latest&lt;/code&gt; を pull するのができなかった。ログアウトしてるといける。↓ このへんの関係ぽいが深く追ってない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nektos/act/discussions/1165&quot; title=&quot;m1: act fails to pull with unauthorized: incorrect username or password · nektos/act · Discussion #1165&quot;&gt;m1: act fails to pull with unauthorized: incorrect username or password · nektos/act · Discussion #1165&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;あとなんか知らんが &lt;code&gt;act&lt;/code&gt; 実行後に &lt;code&gt;[45;3R&lt;/code&gt; って謎キーワードが terminal の input に出てくる、必ず。 ansi escape sequences ぽいけどよくわからん。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 09 Apr 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-04-02-oauth-with-pwsh-to-download-gss-as-csv.html</guid><link>https://krymtkts.github.io/posts/2023-04-02-oauth-with-pwsh-to-download-gss-as-csv.html</link><title>PowerShell で OAuth して Google Sheet を CSV で DL する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;最近役目を終えたスクリプトに、 Google Sheet を CSV でダウンロードするやつがいた。考慮不足等、諸々至らぬ点あろうが、スクリプトを供養するため日記にする。&lt;/p&gt;
&lt;p&gt;モジュール導入したくないなーという事情があったので、下記を見てヒイヒイ言いながら実装した記憶がある。
「Google Sheet から CSV をダウンロードする」には &lt;code&gt;https://www.googleapis.com/auth/drive&lt;/code&gt; のスコープがいるみたい。てっきりスプシのスコープと勘違いして、無駄に時間かかった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/63125283/how-to-connect-api-from-powershell-with-oauth-2-0&quot; title=&quot;How to connect API from PowerShell with OAUTH 2.0? - Stack Overflow&quot;&gt;How to connect API from PowerShell with OAUTH 2.0? - Stack Overflow&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lazyadmin.nl/it/connect-to-google-api-with-powershell/&quot; title=&quot;Connect to Google API with Powershell — LazyAdmin&quot;&gt;Connect to Google API with Powershell — LazyAdmin&lt;/a&gt; して - &lt;a href=&quot;https://stackoverflow.com/questions/37705553/how-to-export-a-csv-from-google-sheet-api/61107170#61107170&quot; title=&quot;r googlesheets - How to export a csv from Google Sheet API? - Stack Overflow&quot;&gt;r googlesheets - How to export a csv from Google Sheet API? - Stack Overflow&lt;/a&gt; する&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;スクリプトは Gist に登録しておいた。
それに伴い Comment-Based Help を書いたり、関数の名前を変えたりした。Google Sheets ってサービス名に対してスプシ自体は spreadsheet だったりしてマジでややこしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/krymtkts/0618fe495df0d3e567e9fb18ca2e308b&quot; title=&quot;GoogleSpreadSheetOAuth.ps1&quot;&gt;GoogleSpreadSheetOAuth.ps1&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;#&lt;br /&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;.SYNOPSIS&lt;/span&gt;&lt;br /&gt;Download Google Sheet as CSV.&lt;br /&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;.DESCRIPTION&lt;/span&gt;&lt;br /&gt;Download Google Sheet as CSV using GCP OAuth Client.&lt;br /&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;.PARAMETER OAuthClientSecretsPath&lt;/span&gt;&lt;br /&gt;The path to the JSON file for the OAuth 2.0 Client Secrets created on GCP.&lt;br /&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;.PARAMETER OAuthStorePath&lt;/span&gt;&lt;br /&gt;The path to save authentication tokens.&lt;br /&gt;&lt;span class=&quot;hljs-doctag&quot;&gt;.EXAMPLE&lt;/span&gt;&lt;br /&gt;. ./GoogleSheetsOAuth.ps1 `&lt;br /&gt;    -OAuthClientSecretsPath &amp;#x27;./client-secrets.json&amp;#x27; `&lt;br /&gt;    -OAuthStorePath &amp;#x27;./gss-credential&amp;#x27;&lt;br /&gt;Get-GoogleSpreadSheetAsCsv `&lt;br /&gt;    -SpreadSheet &amp;#x27;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&amp;#x27; `&lt;br /&gt;    -SheetId &amp;#x27;000000000&amp;#x27; `&lt;br /&gt;    -OutFile &amp;#x27;./test.csv&amp;#x27;&lt;br /&gt;#&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;)]&lt;br /&gt;    [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthClientSecretsPath&lt;/span&gt;,&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;)]&lt;br /&gt;    [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthStorePath&lt;/span&gt;&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;OAuthCredentialStore&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;SecureString&lt;/span&gt;] &lt;span class=&quot;hljs-variable&quot;&gt;$AccessToken&lt;/span&gt;&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;SecureString&lt;/span&gt;] &lt;span class=&quot;hljs-variable&quot;&gt;$RefreshToken&lt;/span&gt;&lt;br /&gt;    OAuthCredentialStore(&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;SecureString&lt;/span&gt;] &lt;span class=&quot;hljs-variable&quot;&gt;$AccessToken&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;SecureString&lt;/span&gt;] &lt;span class=&quot;hljs-variable&quot;&gt;$RefreshToken&lt;/span&gt;&lt;br /&gt;    ) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;$this&lt;/span&gt;.AccessToken = &lt;span class=&quot;hljs-variable&quot;&gt;$AccessToken&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;$this&lt;/span&gt;.RefreshToken = &lt;span class=&quot;hljs-variable&quot;&gt;$RefreshToken&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$script:OAuthCredential&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Get-GoogleSheetsAuthInitToken&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;SupportsShouldProcess&lt;/span&gt;)]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; ()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Split-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthStorePath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parent&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt;)) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{OAuthStorePath} not found.&amp;quot;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthClientSecretsPath&lt;/span&gt;)) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{OAuthClientSecretsPath} not found.&amp;quot;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$secrets&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthClientSecretsPath&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-Json&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; installed&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$Scope&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;System.Web.HttpUtility&lt;/span&gt;]::UrlEncode(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.googleapis.com/auth/drive&amp;#x27;&lt;/span&gt;)&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$ClientID&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$secrets&lt;/span&gt;.client_id&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$ClientSecret&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$secrets&lt;/span&gt;.client_secret&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$RedirectUri&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$secrets&lt;/span&gt;.redirect_uris[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$Uri&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://accounts.google.com/o/oauth2/v2/auth?response_type=code&amp;amp;client_id=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{ClientID}&amp;amp;redirect_uri=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{RedirectUri}&amp;amp;scope=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{Scope}&amp;amp;access_type=offline&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Start-Process&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Uri&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$AuthorizationCode&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Read-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;paste auth code here!&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$AuthData&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        code = &lt;span class=&quot;hljs-variable&quot;&gt;$AuthorizationCode&lt;/span&gt;;&lt;br /&gt;        client_id = &lt;span class=&quot;hljs-variable&quot;&gt;$ClientID&lt;/span&gt;;&lt;br /&gt;        client_secret = &lt;span class=&quot;hljs-variable&quot;&gt;$ClientSecret&lt;/span&gt;;&lt;br /&gt;        redirect_uri = &lt;span class=&quot;hljs-variable&quot;&gt;$RedirectUri&lt;/span&gt;;&lt;br /&gt;        grant_type = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;authorization_code&amp;#x27;&lt;/span&gt;;&lt;br /&gt;        access_type = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;offline&amp;#x27;&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;try to get access token...&amp;#x27;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$TokenResponse&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-RestMethod&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Method&lt;/span&gt; Post &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.googleapis.com/oauth2/v4/token&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Body&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$AuthData&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;?) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;request failed.&amp;#x27;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;done.&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$script:OAuthCredential&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;OAuthCredentialStore&lt;/span&gt;]::new(&lt;br /&gt;        (&lt;span class=&quot;hljs-variable&quot;&gt;$TokenResponse&lt;/span&gt;.access_token | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-SecureString&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AsPlainText&lt;/span&gt;),&lt;br /&gt;        (&lt;span class=&quot;hljs-variable&quot;&gt;$TokenResponse&lt;/span&gt;.refresh_token | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-SecureString&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AsPlainText&lt;/span&gt;)&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$store&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        AccessToken = &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthCredential&lt;/span&gt;.AccessToken | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-SecureString&lt;/span&gt;;&lt;br /&gt;        RefreshToken = &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthCredential&lt;/span&gt;.RefreshToken | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-SecureString&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$PSCmdlet&lt;/span&gt;.ShouldProcess(&lt;span class=&quot;hljs-variable&quot;&gt;$OAuthStorePath&lt;/span&gt;)) {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;New-Item&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthStorePath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$store&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-Json&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Compress&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthStorePath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthCredential&lt;/span&gt;.AccessToken, &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthCredential&lt;/span&gt;.RefreshToken&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Get-GoogleSheetsAuthToken&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;SupportsShouldProcess&lt;/span&gt;)]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; ()&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Verbose&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$OAuthStorePath&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$content&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthStorePath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; Ignore&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; ([&lt;span class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;]::IsNullOrEmpty(&lt;span class=&quot;hljs-variable&quot;&gt;$content&lt;/span&gt;)) {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$token&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-GoogleSheetsAuthInitToken&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$token&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$cred&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$content&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-Json&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$script:OAuthCredential&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;OAuthCredentialStore&lt;/span&gt;]::new(&lt;br /&gt;            (&lt;span class=&quot;hljs-variable&quot;&gt;$cred&lt;/span&gt;.AccessToken | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-SecureString&lt;/span&gt;),&lt;br /&gt;            (&lt;span class=&quot;hljs-variable&quot;&gt;$cred&lt;/span&gt;.RefreshToken | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-SecureString&lt;/span&gt;)&lt;br /&gt;        )&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Invalid SecureString stored for this module. Remove gs-credential and try again.&amp;#x27;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$RefreshToken&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$script:OAuthCredential&lt;/span&gt;.RefreshToken | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-SecureString&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AsPlainText&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$RefreshToken&lt;/span&gt;) {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$token&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-GoogleSheetsAuthInitToken&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$token&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$secrets&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$OAuthClientSecretsPath&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-Json&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; installed&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$RefreshData&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        refresh_token = &lt;span class=&quot;hljs-variable&quot;&gt;$RefreshToken&lt;/span&gt;&lt;br /&gt;        client_id = &lt;span class=&quot;hljs-variable&quot;&gt;$secrets&lt;/span&gt;.client_id&lt;br /&gt;        client_secret = &lt;span class=&quot;hljs-variable&quot;&gt;$secrets&lt;/span&gt;.client_secret&lt;br /&gt;        grant_type = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;refresh_token&amp;#x27;&lt;/span&gt;&lt;br /&gt;        access_type = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;offline&amp;#x27;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$Response&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-RestMethod&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Method&lt;/span&gt; Post &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.googleapis.com/oauth2/v4/token&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Body&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$RefreshData&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;?) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;request failed.&amp;#x27;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Response&lt;/span&gt;.access_token | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-SecureString&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AsPlainText&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Get-GoogleSpreadSheetAsCsv&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$SpreadSheet&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$SheetId&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$OutFile&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$accessToken&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$refreshToken&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-GoogleSheetsAuthToken&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;?) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$Params&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        Uri = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://docs.google.com/spreadsheets/d/&lt;span class=&quot;hljs-variable&quot;&gt;$SpreadSheet&lt;/span&gt;/gviz/tq?tqx=out:csv&amp;amp;gid=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.SheetId)&amp;quot;&lt;/span&gt;&lt;br /&gt;        Method = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;GET&amp;#x27;&lt;/span&gt;&lt;br /&gt;        Authentication = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Bearer&amp;#x27;&lt;/span&gt;&lt;br /&gt;        Token = &lt;span class=&quot;hljs-variable&quot;&gt;$accessToken&lt;/span&gt;&lt;br /&gt;        OutFile = &lt;span class=&quot;hljs-variable&quot;&gt;$ExecutionContext&lt;/span&gt;.SessionState.Path.GetUnresolvedProviderPathFromPSPath(&lt;span class=&quot;hljs-variable&quot;&gt;$OutFile&lt;/span&gt;)&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; @Params | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このスクリプトでは認証コードを得るのに手でコピってる。
これを &lt;code&gt;System.Net.HttpListener&lt;/code&gt; で自鯖を立てて取る方式にしたかったけど、コピペするのは初回だけだし放置してたらそのままスクリプトの寿命が来てしまった。
自動で認証コードを得る方式は以前ググってそれっぽいの見つけてたはずだが、 URL を失念してしまった。
今なら ChatGPT サンにお願いしたら書いてくれそうな雰囲気するなと思い試したらそれっぽいのが出たが、 OAuth client の Redirect URL を変えるのが手間で検証しなかった。怠けてる。
次にやる機会が来るその日まで、自鯖で認証コード取る方式は寝かせておく(やる日は来るのか)。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 02 Apr 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-03-26-writing-cmdlet-in-fsharp-pt17.html</guid><link>https://krymtkts.github.io/posts/2023-03-26-writing-cmdlet-in-fsharp-pt17.html</link><title>F#でコマンドレットを書いてる pt.17</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;もう 4 月なのでそろそろ Fable Compiler を試してみたいと思ってるが、 pocof のテスト書くのと bugfix が落ち着かず、できていない。
ちょっと今までのテストを小綺麗にする作業にも取り組んだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2023-03-19-writing-cmdlet-in-fsharp-pt16.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;、 &lt;code&gt;module&lt;/code&gt; を多層化することでテストケースをグルーピングしている話を書いた。
その時はテストケースを 1 つのファイルにまとめて書いていたのだけど、 &lt;code&gt;PocofQuery.run&lt;/code&gt; のテストを書き始めるにあたり、テストケースが爆増するのに備えてファイルを分割したいと思っていた。&lt;/p&gt;
&lt;p&gt;はじめ F# ではどうテストプロジェクトのファイル分割をするのかわからなかったが、 F# の repo をいくつか参照してみて &lt;a href=&quot;https://github.com/fsprojects/FSharp.Data.Adaptive&quot; title=&quot;fsprojects/FSharp.Data.Adaptive&quot;&gt;fsprojects/FSharp.Data.Adaptive&lt;/a&gt; が参考になりそうとわかった。
それを pocof に提供したところ、上手く分割できた。要は普通の F# Project と同じようにするだけだった。コミットは &lt;a href=&quot;https://github.com/krymtkts/pocof/commit/dff10c89963cdca60cd6ca9e7afeb7f7915e2ff4&quot; title=&quot;krymtkts/pocof@dff10c8&quot;&gt;krymtkts/pocof@dff10c8&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fsprojects/FSharp.Data.Adaptive/tree/5e92ab426e5a438d70986cefff638ecf2acef576/src/Test/FSharp.Data.Adaptive.Tests&quot; title=&quot;FSharp.Data.Adaptive/src/Test/FSharp.Data.Adaptive.Tests&quot;&gt;FSharp.Data.Adaptive/src/Test/FSharp.Data.Adaptive.Tests&lt;/a&gt; がテストプロジェクトのディレクトリ。
ここに分割されたテストコードのファイルが色々あるのと、テストプロジェクトのエントリポイントになる &lt;code&gt;Program.fs&lt;/code&gt; が配置されている。
プロジェクト &lt;a href=&quot;https://github.com/fsprojects/FSharp.Data.Adaptive/blob/5e92ab426e5a438d70986cefff638ecf2acef576/src/Test/FSharp.Data.Adaptive.Tests/FSharp.Data.Adaptive.Tests.fsproj&quot; title=&quot;FSharp.Data.Adaptive.Tests.fsproj&quot;&gt;FSharp.Data.Adaptive.Tests.fsproj&lt;/a&gt; を参照するとエントリポイント &lt;code&gt;Program.fs&lt;/code&gt; が最後の読み込みなっているのがわかる。
それ以前のファイルにモジュールを小分けにしたテストを書いたら良い。&lt;/p&gt;
&lt;p&gt;ファイル分割の粒度はモジュール別に 1 ファイルした。
あまり細かく分けると何処にテストを書くか悩みがちなので、シンプルにモジュールと対にしている。複雑なクエリのテストを書くとまた量が増えて更にファイルを分割したくなるだろうが、今ではない。&lt;/p&gt;
&lt;p&gt;ひとまず満足な形に分解できたのでヨシ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あとこの &lt;a href=&quot;https://github.com/fsprojects/FSharp.Data.Adaptive&quot; title=&quot;fsprojects/FSharp.Data.Adaptive&quot;&gt;fsprojects/FSharp.Data.Adaptive&lt;/a&gt; を参考にしたとき気づいたのだけど、 &lt;a href=&quot;https://github.com/fscheck/FsCheck&quot; title=&quot;FsCheck&quot;&gt;FsCheck&lt;/a&gt; というモジュールを使ってるようだった。 Property-based Testing をするためのやつだ(今書いてるのは所謂「おなじみ」の Example-based Testing という)。
&lt;a href=&quot;https://fsharpforfunandprofit.com/series/property-based-testing/&quot; title=&quot;The &amp;#39;Property Based Testing&amp;#39; series | F# for fun and profit&quot;&gt;The &amp;#39;Property Based Testing&amp;#39; series | F# for fun and profit&lt;/a&gt; が参考になった。&lt;/p&gt;
&lt;p&gt;実際 pocof でもテストケースが貧弱で、テストは成功するがバグってたようなケースがもちらほらあるので、こういうより強力な方法を使うのが良いかもなーと興味深く思っている。
とはいえ興味の範囲で無限にやること増えていく。
かなりやってみたいのだけど、キャッチアップのほうが追いついてない感じ。&lt;/p&gt;
&lt;p&gt;まずは所謂「おなじみ」の Example-based Testing である程度カバーしてから、 FsCheck で強化するってステップを踏むのが良さげ。徐々に... ひとまず今ある draft の pull request を merge してから、今後どう取り組んでいくか考えよかな(タスクを未来にブン投げる)。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 26 Mar 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-03-19-writing-cmdlet-in-fsharp-pt16.html</guid><link>https://krymtkts.github.io/posts/2023-03-19-writing-cmdlet-in-fsharp-pt16.html</link><title>F#でコマンドレットを書いてる pt.16</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fsprojects.github.io/FsUnit/xUnit.html&quot; title=&quot;FsUnit x xUnit&quot;&gt;FsUnit x xUnit&lt;/a&gt; を使ったテストコード追加とリファクタはまだ続けていて、前回から引き続きバグがもりもり見つかる。
&lt;code&gt;PocofData.invokeAction&lt;/code&gt; はアクションに対応づいた各ロジックを呼び出して、内部状態を担うレコードを変更して返すだけの処理だけど、油断ならん。
&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/39&quot; title=&quot;#39&quot;&gt;#39&lt;/a&gt;, &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/40&quot; title=&quot;#40&quot;&gt;#40&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;まだ合計時間にしたら 10 時間も FsUnit(というか &lt;a href=&quot;https://fsprojects.github.io/FsUnit/FsUnitTyped.html&quot; title=&quot;FsUnitTyped&quot;&gt;FsUnitTyped&lt;/a&gt;) 使ってないし、なんなら &lt;code&gt;shouldEqual&lt;/code&gt; と &lt;code&gt;shouldFail&lt;/code&gt; くらいしか使ってない。
けど、手になじんできた気がする。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;shouldEqual&lt;/code&gt; 使っていて良いのは、型間違うことがないところ(当たり前すぎるか)。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fsprojects/FsUnit/blob/d8b95201efc7f478da3d677215291b5aa5487185/src/FsUnit.Xunit/FsUnit.fs#L32&quot; title=&quot;&lt;code&gt;should&lt;/code&gt;&quot;&gt;&lt;code&gt;should&lt;/code&gt;&lt;/a&gt; の関数シグネチャがこう &lt;code&gt;obj&lt;/code&gt; になってる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;inline&lt;/span&gt; should (f&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;^b&lt;/span&gt;) x (actual&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;obj&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;片や &lt;a href=&quot;https://github.com/fsprojects/FsUnit/blob/d8b95201efc7f478da3d677215291b5aa5487185/src/FsUnit.Xunit/FsUnitTyped.fs#L13&quot; title=&quot;shouldEqual&quot;&gt;shouldEqual&lt;/a&gt;はジェネリックになってる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; shouldEqual&lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; (expected&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt;) (actual&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当然ながらその分テストを書くときに楽ができる。実際には以下のような一見して間違いがわかる派手な例はないだろうけど。
テストコードのバグも有り得るので、とにかく安全な方に激ぶりしてかつ楽ができるのは、良い。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;a&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; should equal &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// エラーじゃない。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;a&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; shouldEqual &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// 型不一致のエラー。良い。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あとは、パイプ演算子のお陰で「英文ぽい」順番で記述できるのも良い。ただこの文脈でいえば、FsUnit の見た目に分がある。 &lt;code&gt;should&lt;/code&gt; と &lt;code&gt;equal&lt;/code&gt; 等分かち書きできるからな。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;actual &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; shouldEqual expected&lt;br /&gt;actual &lt;span class=&quot;hljs-operator&quot;&gt;|&amp;gt;&lt;/span&gt; should equal expected &lt;span class=&quot;hljs-comment&quot;&gt;// &amp;lt;- 見た目とても良いけど型検査できなくて片手落ち。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;OOP なんかでも &lt;code&gt;test(actual).shouldEqual(expected)&lt;/code&gt; みたいな形式なら同じ感覚だろうけど、個人的にカッコがなくより自然(Lisper みたいに熟達すればカッコが透けて見える可能性もあろうが)。&lt;/p&gt;
&lt;p&gt;とはいえ良いこと尽くめではない。ちょっと困ったのはテストのグループ化。
例えば同じ関数に対するテストとか、関連あるグループをまとめたら平置きじゃない分だけ注力スべきコードが絞られて見やすくなるので、個人的には積極的にグループ化する。&lt;/p&gt;
&lt;p&gt;FsUnit というか xUnit だと、 F# ではこんな感じに &lt;code&gt;module&lt;/code&gt; を多層化するか &lt;code&gt;module&lt;/code&gt; と &lt;code&gt;type&lt;/code&gt; を使うか 2 通りの手法があるみたい。以下にその 2 通りのテストコードもどき。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Tests&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// module と type。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``PocofAction Tests``&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``toKeyPattern should returns``&lt;/span&gt; () &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Fact&amp;gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;member&lt;/span&gt; x.&lt;span class=&quot;hljs-variable&quot;&gt;``A without modifiers.``&lt;/span&gt; () &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// 以下略。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// module 多層化。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``PocofAction Tests``&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``toKeyPattern should returns``&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Fact&amp;gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``A without modifiers.``&lt;/span&gt; () &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// 以下略。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;pocof ではまだテストで状態を持つことないのと、単にカッコや自己識別子を書く回数が減るってだけで &lt;code&gt;module&lt;/code&gt; で多層化してる。&lt;/p&gt;
&lt;p&gt;まあここまでは良い。これを &lt;code&gt;dotnet test --list-tests&lt;/code&gt; したときにでるテストケースごとの名称のつなぎ方？が気に入らなくて、なんとかならんのかなと思ってる。
先述の例の場合だと、 &lt;code&gt;Tests+PocofAction Tests+toKeyPattern shoud returns.A without modifiers.&lt;/code&gt; のようなテストケース名になる。これ &lt;code&gt;+&lt;/code&gt; とか &lt;code&gt;.&lt;/code&gt; とかどうにかならんのかな。理想は whitespace で繋いでほしい。
単に制御可能でその設定方法を知らないだけという可能性もあるので、追って調べたい。&lt;/p&gt;
&lt;p&gt;多少気に入らないところを愚痴ったが、概ね満足している。今後もテストを足していってもりもりバグを洗い出す。かなーりテストコードに時間かかってる気がするけど、マイペースに。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 19 Mar 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-03-12-writing-cmdlet-in-fsharp-pt15.html</guid><link>https://krymtkts.github.io/posts/2023-03-12-writing-cmdlet-in-fsharp-pt15.html</link><title>F#でコマンドレットを書いてる pt.15</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;前回困ってた Ionide 、理解が難しくあんまわかってないけどこれっぽい。
&lt;a href=&quot;https://github.com/ionide/ionide-vscode-fsharp/issues/1756&quot; title=&quot;Test Explorer doesn&amp;#39;t support tests with &lt;code&gt;TestCaseAttribute&lt;/code&gt; · Issue #1756 · ionide/ionide-vscode-fsharp&quot;&gt;Test Explorer doesn&amp;#39;t support tests with &lt;code&gt;TestCaseAttribute&lt;/code&gt; · Issue #1756 · ionide/ionide-vscode-fsharp&lt;/a&gt;
Subscribe して様子を見る。&lt;/p&gt;
&lt;p&gt;FsUnit を使ったテストコード追加とリファクタをほそぼそと続けている。 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/32&quot; title=&quot;#32&quot;&gt;#32&lt;/a&gt;, &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/37&quot; title=&quot;#37&quot;&gt;#37&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;テストをあとから書いてると、ケアレスミスの bug ポツポツ見つかる。わたしは練習不足なのかテストファーストどうしてもできないのであとがきでもいいかと思ってるが、こう bug が多いとちょっとドキッとする。 main branch へ merge する前にあとがきテストを添えるようにして減らそう。&lt;/p&gt;
&lt;p&gt;いま簡単なところからテストを書いてるので、本丸である &lt;code&gt;Query.fs&lt;/code&gt; のところを書けたらかなりいい感じ。 &lt;code&gt;UI.fs&lt;/code&gt; に関してはどないしょ...という感じになってるけど。
いま直で &lt;code&gt;Console.Write&lt;/code&gt; へアクセスするような形になってるの、差し替え可能にしておいた方がいいんやろな。&lt;/p&gt;
&lt;p&gt;また、 &lt;code&gt;psakefile.ps1&lt;/code&gt; にも unit test や coverage 用のタスクを追加した。というかそれ以外のタスクも見直す必要があった。
というのも、 &lt;code&gt;src&lt;/code&gt; ディレクトリ配下からビルド対象のプロジェクトを見つけるスクリプトが単一のプロジェクトしか想定してなかったので、そのまま使えなかったからだ。この度アプリとテストの 2 プロジェクトができたので、指定のプロジェクトのみ対象とするよう変更した。&lt;/p&gt;
&lt;p&gt;まだ頻出ワードを変数にしておくとかの最適化してなかったり、タスクランナー自体小綺麗にできるんじゃないかなーというのはあるが、無闇に依存関係を増やすのもなと思って手を出せてない。
&lt;a href=&quot;https://github.com/psake/PowerShellBuild&quot; title=&quot;PowerShellBuild&quot;&gt;PowerShellBuild&lt;/a&gt;, &lt;a href=&quot;https://github.com/RamblingCookieMonster/PSDepend&quot; title=&quot;PSDepend&quot;&gt;PSDepend&lt;/a&gt; あたりの導入できれいになるかも知れんけど、なるべく依存関係をなくす方が結果的にシンプルなプロジェクトになるのを知ってるし。
現時点でも psake PSScriptAnalyzer Pester PowerShellGet に依存してるから、四の五の言わずに PSDepend だけでもはよ入れろよという感じはある。
だが、覚悟ができてからやる(先延ばし)。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;おまけ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;最近になって仕事でも AI チャットを使う流れがきており、練習がてら &lt;a href=&quot;https://github.com/dfinke/PowerShellAI&quot; title=&quot;PowerShellAI&quot;&gt;PowerShellAI&lt;/a&gt; と一緒に仕事し始めてみた。 VS Code Extension はちょっと種類が多すぎてどれが信頼できるかいちいち調べられてないし、やってない。
上手く使えて、わたし・ Tabnine ・ OpenAI の三人力な感じを出せると良いが。
ちょっと使ってみた感覚的に、仕事で使うような特定用途に特化した回答をさせたい時と普段遣いで雑に使う感じでは、 prompt に結構差がある感触。
これほんま練習になるんかな。&lt;/p&gt;
&lt;p&gt;にしても OpenAI の token がガリガリ消費されるのを見てると「ﾋｪｴ...」となる。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 12 Mar 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-03-05-writing-cmdlet-in-fsharp-pt14.html</guid><link>https://krymtkts.github.io/posts/2023-03-05-writing-cmdlet-in-fsharp-pt14.html</link><title>F#でコマンドレットを書いてる pt.14</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;以下を参考に xUnit と FsUnit を導入した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/core/testing/unit-testing-fsharp-with-dotnet-test&quot; title=&quot;dotnet テストと xUnit を使用した .NET Core での単体テスト F# - .NET | Microsoft Learn&quot;&gt;dotnet テストと xUnit を使用した .NET Core での単体テスト F# - .NET | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://fsprojects.github.io/FsUnit/xUnit.html&quot; title=&quot;FsUnit for xUnit&quot;&gt;FsUnit for xUnit&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://fsprojects.github.io/FsUnit/FsUnitTyped.html&quot; title=&quot;What is FsUnitTyped?&quot;&gt;What is FsUnitTyped?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/core/testing/unit-testing-code-coverage?tabs=windows#code-coverage-tooling&quot; title=&quot;単体テストにコードカバレッジを使用する - .NET | Microsoft Learn&quot;&gt;単体テストにコードカバレッジを使用する - .NET | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;repo ルートを作業ディレクトリとする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; (mkdir pocof.Test)&lt;br /&gt;dotnet new xunit &lt;span class=&quot;hljs-literal&quot;&gt;-lang&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;F#&amp;quot;&lt;/span&gt;&lt;br /&gt;dotnet add reference ../pocof/pocof.fsproj&lt;br /&gt;dotnet sln ../../pocof.sln add .\pocof.Test.fsproj&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; ../../&lt;br /&gt;dotnet build
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;一応ここでちゃんとテストできるか確認をする。&lt;code&gt;Tests.fs&lt;/code&gt; のコードを単純なのに書き換える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; Tests&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; System&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; Xunit&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Fact&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;``My test``&lt;/span&gt; () &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Assert.True(&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;VS Code からでもよし、 CLI でなら repo のルートで以下の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; dotnet test&lt;br /&gt;  Determining projects to restore...&lt;br /&gt;  All projects are up&lt;span class=&quot;hljs-literal&quot;&gt;-to-date&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; restore.&lt;br /&gt;  pocof -&amp;gt; C:\Users\takatoshi\dev\github.com\krymtkts\pocof\src\pocof\bin\Debug\net6.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\pocof.dll&lt;br /&gt;C:\Users\takatoshi\dev\github.com\krymtkts\pocof\src\pocof.Test\Tests.fs(&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;39&lt;/span&gt;): warning FS0988: Main module of program is empty: noth&lt;br /&gt;ing will happen when it is run [&lt;span class=&quot;hljs-type&quot;&gt;C&lt;/span&gt;:\&lt;span class=&quot;hljs-type&quot;&gt;Users&lt;/span&gt;\&lt;span class=&quot;hljs-type&quot;&gt;takatoshi&lt;/span&gt;\&lt;span class=&quot;hljs-type&quot;&gt;dev&lt;/span&gt;\&lt;span class=&quot;hljs-type&quot;&gt;github.com&lt;/span&gt;\&lt;span class=&quot;hljs-type&quot;&gt;krymtkts&lt;/span&gt;\&lt;span class=&quot;hljs-type&quot;&gt;pocof&lt;/span&gt;\&lt;span class=&quot;hljs-type&quot;&gt;src&lt;/span&gt;\&lt;span class=&quot;hljs-type&quot;&gt;pocof.Test&lt;/span&gt;\&lt;span class=&quot;hljs-type&quot;&gt;pocof.Test.fsproj&lt;/span&gt;]&lt;br /&gt;  pocof.Test -&amp;gt; C:\Users\takatoshi\dev\github.com\krymtkts\pocof\src\pocof.Test\bin\Debug\net6.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\pocof.Test.dll&lt;br /&gt;Test run &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; C:\Users\takatoshi\dev\github.com\krymtkts\pocof\src\pocof.Test\bin\Debug\net6.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\pocof.Test.dll (.NETCoreApp,Version=v6.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;br /&gt;Microsoft (&lt;span class=&quot;hljs-built_in&quot;&gt;R&lt;/span&gt;) Test Execution Command Line Tool Version &lt;span class=&quot;hljs-number&quot;&gt;17.5&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; (x64)&lt;br /&gt;Copyright (c) Microsoft Corporation.  All rights reserved.&lt;br /&gt;&lt;br /&gt;Starting test execution, please wait...&lt;br /&gt;A total of &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; test files matched the specified pattern.&lt;br /&gt;&lt;br /&gt;Passed!  - Failed:     &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, Passed:     &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, Skipped:     &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, Total:     &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, Duration: &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; ms - pocof.Test.dll (net6.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あと &lt;code&gt;dotnet new xunit -lang &amp;quot;F#&amp;quot;&lt;/code&gt; で生成された &lt;code&gt;Program.fs&lt;/code&gt; は不要なので削除、 &lt;code&gt;pocof.Text.fsproj&lt;/code&gt; からも削除する。&lt;/p&gt;
&lt;p&gt;次に FsUnit を追加する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet add ./src/pocof.Test/pocof.Test.fsproj package FsUnit.xUnit
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;テストをこんな感じで書き換え、 &lt;code&gt;dotnet test&lt;/code&gt; が成功したら完了。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt; module Tests&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-open System&lt;/span&gt;&lt;br /&gt; open Xunit&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+open FsUnitTyped&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-[&amp;lt;Fact&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-let ``My test`` () = Assert.True(true)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+module ``Pocof Tests`` =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    [&amp;lt;Fact&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    let ``Sample test should equals 1`` () = 1 |&amp;gt; shouldEqual 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+[&amp;lt;EntryPoint&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+let main argv = 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/dotnet/fsharp/issues/2669&quot; title=&quot;&amp;quot;Main module of program is empty: nothing will happen when it is run&amp;quot; warning when running xunit tests on .net core. · Issue #2669 · dotnet/fsharp&quot;&gt;&amp;quot;Main module of program is empty: nothing will happen when it is run&amp;quot; warning when running xunit tests on .net core. · Issue #2669 · dotnet/fsharp&lt;/a&gt; で知ったが、 テストプロジェクトはコンソールアプリなので &lt;code&gt;&amp;lt;EntryPoint&amp;gt;&lt;/code&gt; を必ず持たないと警告がでる。 xUnit 追加後シンプルにしたテストコードでは &lt;code&gt;&amp;lt;EntryPoint&amp;gt;&lt;/code&gt; がなかったので警告が出てた。&lt;/p&gt;
&lt;p&gt;ちょっとわからないのが VS Code からの実行だとハングしてるようだった。
テストを実行するための DotNet CLI が後ろで実行されるみたいだが、そのプロセスは上手く行ってそうに見える。でも GUI がずっとくるくる止まる。どうも Inonide がエラーしてるっぽい。 xUnit の実行確認のときはいけたので FsUnit 起因か？ちょっと調べる必要ありだが、今回は先送りにする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;2023-03-04 15:50:47.005 [error] Error:&lt;br /&gt;    at MapTreeModule_find (c:\Users\takatoshi\.vscode\extensions\ionide.ionide-fsharp-7.5.1\webpack:\out\fable_modules\fable-library.4.0.0-theta-018\Map.js:245:15)&lt;br /&gt;    at FSharpMap__get_Item (c:\Users\takatoshi\.vscode\extensions\ionide.ionide-fsharp-7.5.1\webpack:\out\fable_modules\fable-library.4.0.0-theta-018\Map.js:1179:12)&lt;br /&gt;    at f (c:\Users\takatoshi\.vscode\extensions\ionide.ionide-fsharp-7.5.1\webpack:\out\fable_modules\fable-library.4.0.0-theta-018\Map.js:1297:12)&lt;br /&gt;    at Kt (c:\Users\takatoshi\.vscode\extensions\ionide.ionide-fsharp-7.5.1\webpack:\out\fable_modules\fable-library.4.0.0-theta-018\Array.js:70:21)&lt;br /&gt;    at c:\Users\takatoshi\.vscode\extensions\ionide.ionide-fsharp-7.5.1\webpack:\out\Components\TestExplorer.js:138:27&lt;br /&gt;    at processTicksAndRejections (node:internal/process/task_queues:96:5)&lt;br /&gt;    at async Promise.all (index 0)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コードカバレッジは xUnit のテンプレなら初めから統合されてるらしくて、すぐ出せる。これはめちゃくちゃ楽。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet test &lt;span class=&quot;hljs-literal&quot;&gt;--collect&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;XPlat Code Coverage&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こんな感じでレポート出力できる。出力しておいたら VS Code の &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters&quot; title=&quot;Coverage Gutters&quot;&gt;Coverage Gutters&lt;/a&gt; で取り込めるしこりゃいいな。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;reportgenerator &lt;span class=&quot;hljs-literal&quot;&gt;-reports&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.\src\pocof.Test\TestResults\*\coverage.cobertura.xml&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-targetdir&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;coverage&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-reporttypes&lt;/span&gt;:Html
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;p&gt;昔は Visual Studio からしか Solution とか作るしかなかったようなキヲクをがある(無能だっただけやも知れんが)。
いまの DotNet CLI ある時代めちゃくちゃ便利でびっくりした。&lt;/p&gt;
&lt;p&gt;あと FsUnit 非常によい。
入力キーから処理を導くところのリファクタするのに役立っている。
サクサク書けるし、バグってた状態で放置してるとこが見つかったり(&lt;a href=&quot;https://github.com/krymtkts/pocof/pull/33&quot; title=&quot;#33&quot;&gt;#33&lt;/a&gt;)いまのところ良いことしか無い。&lt;/p&gt;
&lt;p&gt;いい感じにテスト揃ってきたら、 GitHub Actions で FsUnit と Pester 実行するようにしよう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 05 Mar 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-02-26-writing-cmdlet-in-fsharp-pt13.html</guid><link>https://krymtkts.github.io/posts/2023-02-26-writing-cmdlet-in-fsharp-pt13.html</link><title>F#でコマンドレットを書いてる pt.13</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。
&lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.4.0-alpha&quot; title=&quot;pocof 0.4.0-alpha&quot;&gt;pocof 0.4.0-alpha&lt;/a&gt; を公開した。&lt;/p&gt;
&lt;p&gt;諸々の bugfix を主として行った。
&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/28&quot; title=&quot;#28&quot;&gt;#28&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/25&quot; title=&quot;#25&quot;&gt;#25&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/23&quot; title=&quot;#23&quot;&gt;#23&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/21&quot; title=&quot;#21&quot;&gt;#21&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/20&quot; title=&quot;#20&quot;&gt;#20&lt;/a&gt; &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/18&quot; title=&quot;#18&quot;&gt;#18&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;修正自体は軽微だが、結構使っていてイヤーな感じをもたらす bug が多かったし、直して良かった。
機能的なところでは入力中のプロパティ候補の表示非表示を切り替えるオプションを付与したのみに留まる。&lt;/p&gt;
&lt;p&gt;正直なところプロパティの TAB 補完できてから公開したかったが、先送りにした。
こいつをやるには内部的な状態を増やす必要があると思っていて、そのためにはリファクタリングをしてから着手する方が良い。
要はリファクタリングしだすと、色々気になって手を入れてしまいズルズルとリリースを遅らせがちなので、切の良いタイミングで公開しておいたという算段だ。&lt;/p&gt;
&lt;p&gt;増やす状態は、カーソルがクエリの分かち書きの何個目にいるか、単語の何文字目にいるとかを指す。 TAB 補完したときにクエリの書き換えとカーソル末尾への移動をするが、その計算にこれらの状態があると良い。
今の実装だと単純にクエリ文字列と検索中のプロパティを保持しているだけなので、そこを小綺麗に整理した後にそれらを付与するようなイメージ。判別共用体を上手く使ってできる感覚を持っている。&lt;/p&gt;
&lt;p&gt;ただしデータ構造の変更に伴いクエリ実行そのものも書き換える必要がある。
&lt;a href=&quot;/posts/2023-02-05-writing-cmdlet-in-fsharp-pt12.html&quot; title=&quot;前の日記&quot;&gt;前の日記&lt;/a&gt; でも触れてたように、やっぱこのタイミングで &lt;a href=&quot;https://github.com/fsprojects/FsUnit&quot; title=&quot;FsUnit&quot;&gt;FsUnit&lt;/a&gt; 導入して動作保証しながらの開発は必須、避けられない。&lt;/p&gt;
&lt;p&gt;話は逸れるが、FsUnit 使うに当たり .NET のテストライブラリを入れる必要があるのだけど、全然知らん。
&lt;a href=&quot;https://fsprojects.github.io/FsUnit/index.html&quot; title=&quot;What is FsUnit?&quot;&gt;What is FsUnit?&lt;/a&gt; を見るに &lt;a href=&quot;https://github.com/xunit/xunit&quot; title=&quot;xunit&quot;&gt;xunit&lt;/a&gt; 、 &lt;a href=&quot;https://github.com/nunit/nunit&quot; title=&quot;nunit&quot;&gt;nunit&lt;/a&gt; と &lt;a href=&quot;https://github.com/microsoft/testfx&quot; title=&quot;MSTest&quot;&gt;MSTest&lt;/a&gt; がある。
FsUnit からはどれでも使えるけどそれぞれの推しどころわからず、どれを使えばいいかわからんというアレな状態。
GitHub の star 見るに xUnit が人気ぽいが、 &lt;a href=&quot;https://github.com/fsprojects/fantomas/blob/a7ed99fb74fee6db55487f315005c0200d19a0b4/src/Fantomas.Tests/Fantomas.Tests.fsproj&quot; title=&quot;fantomas&quot;&gt;fantomas&lt;/a&gt; は FsUnit と NUnit の組み合わせっぽかった。
FsUnit のドキュメント見てたら、強力な型付きの &lt;a href=&quot;https://fsprojects.github.io/FsUnit/FsUnitTyped.html&quot; title=&quot;FsUnitTyped&quot;&gt;FsUnitTyped&lt;/a&gt; は NUnit か xUnit しかサポートしてないって書いてるし、なんとか二択までは絞れた...こっからがだるい。&lt;/p&gt;
&lt;p&gt;話を戻して、クエリの内部状態以外にも判別共用体で書き直したい箇所があって、それは入力時のキー判定や今は文字列で保持しているキーマップだったりだ。
キーマップの方は外部保存した設定ファイルを読み込む方式も検討したいのでハマるかわからんけど。入力時のキー判定の方は、いま if 式をこねくっているのもあって、パターンマッチング式に置き換えられるからハマるなという感覚がある。&lt;/p&gt;
&lt;p&gt;また機能追加が滞りそうではあるが、あと 2 ヶ月ほどで pocof の initial commit から 1 年経つのもあり、掃除するにはちょうどいい頃合いではないかと。ちょっとは F# Ninja Level も上がったやろ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 26 Feb 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-02-19-aws-ssm-session-manager-with-powershell.html</guid><link>https://krymtkts.github.io/posts/2023-02-19-aws-ssm-session-manager-with-powershell.html</link><title>AWS SSM Session Manager を PowerShell で</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;AWS SSM Session Manager を使って EC2 Instance とかに接続するやつがある。
AWS CLI であれば Session Mangger plugin&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; を入れておけば &lt;code&gt;aws ssm start-session&lt;/code&gt; で SSH 感覚でつなげる。 Security Group に自分とこの外部 IP を含めなくていいし、最高のやつだ。&lt;/p&gt;
&lt;p&gt;だが AWS Tools for PowerShell で対になる &lt;code&gt;Start-SSMSession&lt;/code&gt;は &lt;a href=&quot;https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_StartSession.html&quot; title=&quot;StartSession API&quot;&gt;StartSession API&lt;/a&gt; の戻り値を返すだけ。
(公式回答なのか？) AWS dev サポの方が AWS Tools for PowerShell の Issue&lt;sup&gt;&lt;a id=&quot;footnote-ref-2&quot; href=&quot;#footnote-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; にて Session Manager plugin に対応してなさそうなコメントしてる。
また Session Manager plugin 自体、その本丸である WebSocket の URL やらをどのようにこねくり回して渡せばいいかが文書化されてない。&lt;/p&gt;
&lt;p&gt;PowerShell では Session Manager 無理かな...半ば諦めていたところに、なんと Remote Desktop で繋げられたという記事を発見した。
これはマジですごい。 Linux 上で &lt;code&gt;aws ssm start-session&lt;/code&gt; を &lt;code&gt;strace&lt;/code&gt; して解析したらしい。鬼テク。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cloudsoft.io/blog/remote-access-to-windows-ec2-instances-the-easy-and-secure-way&quot; title=&quot;Remote Access to Windows EC2 instances, the easy (and secure) way&quot;&gt;Remote Access to Windows EC2 instances, the easy (and secure) way&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;解析結果から作成され接続確認された PowerShell モジュールが GitHub に公開されている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cloudsoft/EC2Access/blob/v1.0.0/EC2Access.psm1#L170-L243&quot; title=&quot;EC2Access/EC2Access.psm1 at v1.0.0 · cloudsoft/EC2Access&quot;&gt;EC2Access/EC2Access.psm1 at v1.0.0 · cloudsoft/EC2Access&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;元記事は RemoteDesktop を対象としているが、ぱっと見 SSH でも同様のことができそう。
コミットが 1 年半くらい前なので Session Manager の API に変更がなければ、やけど。
Session Manager plugin にパラメータを渡す部分を参考に、接続を試行してみる。
&lt;a href=&quot;https://github.com/cloudsoft/EC2Access/blob/v1.0.0/LICENSE&quot; title=&quot;ライセンスは Apache License 2&quot;&gt;ライセンスは Apache License 2&lt;/a&gt; なので無償利用・改変もヨシ。&lt;/p&gt;
&lt;p&gt;試してみる。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;まず AWS CLI の場合だが以下のような感じで使ってた。
見やすさのために改行成分多く含んでいる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-EC2Instance&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Filter&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;    Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;tag:Name&amp;#x27;&lt;/span&gt;&lt;br /&gt;    Values = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;instance-name&amp;#x27;&lt;/span&gt;&lt;br /&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; Instances &lt;span class=&quot;hljs-literal&quot;&gt;-First&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;    aws ssm &lt;span class=&quot;hljs-built_in&quot;&gt;start-session&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--target&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.InstanceId &lt;span class=&quot;hljs-comment&quot;&gt;# ここを変えたいんや&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これを一先ずこんな風に使えるような関数を作成してみてはどうか？(&lt;code&gt;ForEach-Object&lt;/code&gt; 要らんが SSH は単発でつなぎたいし一先ず)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-EC2Instance&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Filter&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;    Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;tag:Name&amp;#x27;&lt;/span&gt;&lt;br /&gt;    Values = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;instance-name&amp;#x27;&lt;/span&gt;&lt;br /&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; Instances &lt;span class=&quot;hljs-literal&quot;&gt;-First&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Start-SSMSshSession&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Instance&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.InstanceId &lt;span class=&quot;hljs-comment&quot;&gt;# こういう関数がほしい&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;先述の &lt;a href=&quot;https://github.com/cloudsoft/EC2Access/blob/v1.0.0/EC2Access.psm1#L170-L243&quot; title=&quot;EC2Access.psm1&quot;&gt;EC2Access.psm1&lt;/a&gt; からコードを拝借する。
&lt;code&gt;Start-SSMSession&lt;/code&gt; の戻り値をこねくる部分と、 Session Manager plugin を取り扱う箇所が対象だ。
コメントも処理の解析に有用なのでそのまま残させていただく。&lt;/p&gt;
&lt;p&gt;元コードは RemoteDesktop を対象にしているので、認証情報の作成、 port forwarding 、あと最後の接続の箇所だけ SSH 用に書き換える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Start-SSMSshSession&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;SupportsShouldProcess&lt;/span&gt;)]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;ValidateNotNullOrEmpty&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$InstanceId&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;ValidateNotNullOrEmpty&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Region&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ap-northeast-1&amp;#x27;&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;ValidateNotNullOrEmpty&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$SshUser&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ec2-user&amp;#x27;&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;ValidateNotNullOrEmpty&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$CertPath&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$LocalPort&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;10022&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$PortForwardParams&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{ portNumber = (, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;22&amp;#x27;&lt;/span&gt;); localPortNumber = (, &lt;span class=&quot;hljs-variable&quot;&gt;$LocalPort&lt;/span&gt;.ToString()) }&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$session&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Start-SSMSession&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Target&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$InstanceId&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-DocumentName&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;AWS-StartPortForwardingSession&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parameters&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$PortForwardParams&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# We now need to emulate awscli - it invokes session-manager-plugin with the new session information.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# AWS Tools for PowerShell don&amp;#x27;t do this. Also some of the objects seem to look a bit different, and the&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# plugin is pernickety, so we have to jump through some hoops to get all the objects matching up as close&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# as we can.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$SessionData&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        SessionId = &lt;span class=&quot;hljs-variable&quot;&gt;$session&lt;/span&gt;.SessionID;&lt;br /&gt;        StreamUrl = &lt;span class=&quot;hljs-variable&quot;&gt;$session&lt;/span&gt;.StreamUrl;&lt;br /&gt;        TokenValue = &lt;span class=&quot;hljs-variable&quot;&gt;$session&lt;/span&gt;.TokenValue;&lt;br /&gt;        ResponseMetadata = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;            RequestId = &lt;span class=&quot;hljs-variable&quot;&gt;$session&lt;/span&gt;.ResponseMetadata.RequestId;&lt;br /&gt;            HTTPStatusCode = &lt;span class=&quot;hljs-variable&quot;&gt;$session&lt;/span&gt;.HttpStatusCode;&lt;br /&gt;            RetryAttempts = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;&lt;br /&gt;            HTTPHeaders = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;                server = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;server&amp;#x27;&lt;/span&gt;;&lt;br /&gt;                &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;content-type&amp;#x27;&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;application/x-amz-json-1.1&amp;#x27;&lt;/span&gt;;&lt;br /&gt;                &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;content-length&amp;#x27;&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$session&lt;/span&gt;.ContentLength;&lt;br /&gt;                connection = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;keep-alive&amp;#x27;&lt;/span&gt;;&lt;br /&gt;                &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x-amzn-requestid&amp;#x27;&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$session&lt;/span&gt;.ResponseMetadata.RequestId;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$RequestData&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        Target = &lt;span class=&quot;hljs-variable&quot;&gt;$InstanceId&lt;/span&gt;;&lt;br /&gt;        DocumentName = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;AWS-StartPortForwardingSession&amp;#x27;&lt;/span&gt;;&lt;br /&gt;        Parameters = &lt;span class=&quot;hljs-variable&quot;&gt;$PortForwardParams&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$Arguments&lt;/span&gt; = (&lt;br /&gt;        (&lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-Json&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$SessionData&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Compress&lt;/span&gt;),&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Region&lt;/span&gt;,&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;StartSession&amp;#x27;&lt;/span&gt;,&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;,&lt;br /&gt;        (&lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-Json&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$RequestData&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Compress&lt;/span&gt;),&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://ssm.&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$Region&lt;/span&gt;).amazonaws.com&amp;quot;&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# Now we have to do some PowerShell hacking. Start-Process takes an array of arguments, which is great,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# but it doesn&amp;#x27;t actually do what we expect it to - see https://github.com/PowerShell/PowerShell/issues/5576.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# So instead we have to turn it into an escaped string ourselves...&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$EscapedArguments&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$Arguments&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$escaped&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`&amp;quot;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\`&amp;quot;&amp;quot;&lt;/span&gt;; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$escaped&lt;/span&gt;)`&amp;quot;&amp;quot;&lt;/span&gt; }&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$ArgumentString&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$EscapedArguments&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27; &amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# Start the Session Manager plugin:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$PSCmdlet&lt;/span&gt;.ShouldProcess(&lt;span class=&quot;hljs-variable&quot;&gt;$session&lt;/span&gt;.SessionId, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Start Session Manager plugin&amp;#x27;&lt;/span&gt;)) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$Process&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Start-Process&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-FilePath&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;session-manager-plugin.exe&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ArgumentList&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$ArgumentString&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NoNewWindow&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-PassThru&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Error&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Unable to start the process session-manager-plugin.exe. Have you installed the Session Manager Plugin as described in https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html#install-plugin-windows ?&amp;#x27;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;exit&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;# Wait a moment for it to connect to the session and open up the local ports&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Start-Sleep&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Seconds&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;# The port should be open now - let&amp;#x27;s connect&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$PSCmdlet&lt;/span&gt;.ShouldProcess(&lt;span class=&quot;hljs-variable&quot;&gt;$InstanceId&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Start SSH client&amp;#x27;&lt;/span&gt;)) {&lt;br /&gt;            ssh &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{SshUser}@127.0.0.1&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$LocalPort&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$CertPath&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;# Once the ssh session has finished, kill the session manager plugin&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Process&lt;/span&gt;.Kill()&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;aws ssm start-session&lt;/code&gt; だと &lt;code&gt;ssm-user&lt;/code&gt; でつなぐことになるが、自前で接続する場合このユーザの認証情報がわからなかった。
代わりに &lt;code&gt;ec2-user&lt;/code&gt; を使い、合わせて鍵も渡すようにした。
結果、当初の想定よりパラメータが増えてしまうが、致し方なし。&lt;/p&gt;
&lt;p&gt;できたら試す。 IP 等の一部の情報は伏せ字とする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-EC2Instance&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Filter&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;&amp;gt;     Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;tag:Name&amp;#x27;&lt;/span&gt;&lt;br /&gt;&amp;gt;     Values = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;instance-name&amp;#x27;&lt;/span&gt;&lt;br /&gt;&amp;gt; } | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; Instances &lt;span class=&quot;hljs-literal&quot;&gt;-First&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;&amp;gt;     &lt;span class=&quot;hljs-built_in&quot;&gt;Start-SSMSshSession&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-InstanceId&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.InstanceId &lt;span class=&quot;hljs-literal&quot;&gt;-CertPath&lt;/span&gt; ~/.ssh/instance&lt;span class=&quot;hljs-literal&quot;&gt;-name&lt;/span&gt;.pem&lt;br /&gt;&amp;gt; }&lt;br /&gt;&lt;br /&gt;Starting session with SessionId: krymtkts&lt;span class=&quot;hljs-literal&quot;&gt;-031e957031cdcb25c&lt;/span&gt;&lt;br /&gt;Port &lt;span class=&quot;hljs-number&quot;&gt;10022&lt;/span&gt; opened &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; sessionId krymtkts&lt;span class=&quot;hljs-literal&quot;&gt;-031e957031cdcb25c&lt;/span&gt;.&lt;br /&gt;Waiting &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; connections...&lt;br /&gt;&lt;br /&gt;Connection accepted &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; session [&lt;span class=&quot;hljs-type&quot;&gt;krymtkts&lt;/span&gt;-&lt;span class=&quot;hljs-number&quot;&gt;031&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;e957031cdcb25c&lt;/span&gt;]&lt;br /&gt;Last login: Sun Feb &lt;span class=&quot;hljs-number&quot;&gt;19&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;06&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;09&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;45&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt; from localhost&lt;br /&gt;&lt;br /&gt;       __|  __|_  )&lt;br /&gt;       _|  (     /   Amazon Linux &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; AMI&lt;br /&gt;      ___|\___|___|&lt;br /&gt;&lt;br /&gt;https://aws.amazon.com/amazon&lt;span class=&quot;hljs-literal&quot;&gt;-linux-2&lt;/span&gt;/&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt; package(s) needed &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; security, out of &lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt; available&lt;br /&gt;Run &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;sudo yum update&amp;quot;&lt;/span&gt; to apply all updates.&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;ec2&lt;/span&gt;-&lt;span class=&quot;hljs-type&quot;&gt;user&lt;/span&gt;@&lt;span class=&quot;hljs-type&quot;&gt;ip&lt;/span&gt;-&lt;span class=&quot;hljs-type&quot;&gt;xxx&lt;/span&gt;-&lt;span class=&quot;hljs-type&quot;&gt;xxx&lt;/span&gt;-&lt;span class=&quot;hljs-type&quot;&gt;xxx&lt;/span&gt;-&lt;span class=&quot;hljs-type&quot;&gt;xxx&lt;/span&gt; ~]&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;exit&lt;/span&gt;&lt;br /&gt;logout&lt;br /&gt;Connection to &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0.1&lt;/span&gt; closed.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;見事つなげる事ができた。すーご。&lt;/p&gt;
&lt;p&gt;非公式とはいえ、 AWS CLI だけでしかできかなったことが PowerShell でもできるというのがわかるのは、一ユーザとして喜ばしいこっちゃな。
&lt;a href=&quot;https://cloudsoft.io/blog/remote-access-to-windows-ec2-instances-the-easy-and-secure-way&quot; title=&quot;元記事&quot;&gt;元記事&lt;/a&gt; の Great work に感謝やな。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html&quot; title=&quot;(Optional) Install the Session Manager plugin for the AWS CLI - AWS Systems Manager&quot;&gt;(Optional) Install the Session Manager plugin for the AWS CLI - AWS Systems Manager&lt;/a&gt; 入れておけばというか入れてないと無理 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;footnote-2&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-tools-for-powershell/issues/283#issuecomment-1247377153&quot; title=&quot;Support for interactive Start-SSMSession · Issue #283 · aws/aws-tools-for-powershell&quot;&gt;Support for interactive Start-SSMSession · Issue #283 · aws/aws-tools-for-powershell&lt;/a&gt; で(AWS Tools for PowerShell は)外部プログラムに依存できないし、 Session Manager plugin は AWS CLI 専用て言ってる &lt;a href=&quot;#footnote-ref-2&quot; data-footnote-backref aria-label=&quot;Back to reference 2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 19 Feb 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-02-12-change-display-langualge-completely-to-en.html</guid><link>https://krymtkts.github.io/posts/2023-02-12-change-display-langualge-completely-to-en.html</link><title>Windows 11 の表示言語を完全に英語にする</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;Windows 10 からデフォルト言語が日本の状態の PC でも表示言語を変えられる。
極力英語 UI を使うようにしているのもあって、今の Razer Blade Stealth を買ったころから英語表示で利用している。 Windows 11 にアップグレードしてからも同じだ。&lt;/p&gt;
&lt;p&gt;設定自体は、ここに書いてる方法で表示言語を日本語から英語に変えられる。
&lt;a href=&quot;https://support.microsoft.com/en-us/windows/manage-the-input-and-display-language-settings-in-windows-12a10cb4-8626-9b77-0ccb-5013e0c7c7a2#WindowsVersion=Windows_10&quot; title=&quot;Manage the input and display language settings in Windows - Microsoft Support&quot;&gt;Manage the input and display language settings in Windows - Microsoft Support&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;あと重要なのが、 Time &amp;amp; Language → Language &amp;amp; region のところの Preferred languages の順番。ここでちゃんと先頭を英語にしておかないといけない。
例えば &lt;a href=&quot;https://github.com/microsoft/PowerToys&quot; title=&quot;PowerToys&quot;&gt;PowerToys&lt;/a&gt; や &lt;a href=&quot;https://github.com/microsoft/terminal&quot; title=&quot;Windows Terminal&quot;&gt;Windows Terminal&lt;/a&gt; といったツール。
これらは最優先される言語でコマンドパレットや UI を表示したりする仕組みになってるようで&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;、日本語を最優先にしていると部分的に表示言語が日本語になり、使いにくいことこの上なくなる。
これに従うとデフォルトのキーボードが英語になるデメリットがあるが、インスタントに切り替えられない UI の方を尊重して、 起動後は毎回 Win + Space で英語 → 日本語に切り替えている。&lt;/p&gt;
&lt;p&gt;こんな感じでちまちま英語 UI を使えるように調整していたのだけど、最近困った事が起こった。
ここ数ヶ月のどっかの Windows Update のタイミング以降、ログイン画面やシャットダウン・再起動時の表示言語が日本語になる事象が発生した。
先述の表示言語の設定で、英語 → 日本語としたあとで再起動後また英語にするとか、色々やっても解消しないので何なんや...と思っていた。&lt;/p&gt;
&lt;p&gt;ついに先日、その解消方法を見つけた。
しかも身近な Time &amp;amp; Language → Language &amp;amp; region の中にある。たまたまポチっては画面を眺めてを繰り返していたときに見つけた。&lt;/p&gt;
&lt;p&gt;Administrative language settings だ。&lt;/p&gt;
&lt;p&gt;キーワードさえわかればこのように類似ケースを探すのも容易い。でも Microsoft の文書がヒットしないのはなんでや...
&lt;a href=&quot;https://www.windowscentral.com/how-change-system-language-windows-10&quot; title=&quot;How to change system language on Windows 11 | Windows Central&quot;&gt;How to change system language on Windows 11 | Windows Central&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ここ 2 つのセクションがあって、両方を英語に変えた。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Welcome screen and new user accounts&lt;/li&gt;&lt;li&gt;Language for non-Unicode programs&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;1 では Current user から Welcome screen, New user accounts の 2 つの言語設定に設定をコピーできて、その内の Welcome screen の言語設定がログイン画面に効いた様子。
また英語表示が戻ってきて、うれしい。
更に、 Windows Update 後に足した覚えのないキーボードが復活する現象にも悩まされていた。
New user accounts にその足した覚えのないキーボードが割あたってたので、多分犯人はこいつ。
これも解消できそう。&lt;/p&gt;
&lt;p&gt;2 の方は何に効いてるのかわからん。 non-Unicode なアプリがあったらわかるんかな。&lt;/p&gt;
&lt;p&gt;手順がわかってしまえば、もしまた表示言語が日本語に戻ったとしても、この設定をやり直せば良いので安心できる。
理想はスクリプト化しておきたいが、まだ Registry の該当箇所を調べてない。&lt;/p&gt;
&lt;p&gt;という具体で久しぶりのフル英語表示にできて満足した。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;要出典。昔 Windows Terminal にコマンドパレットが導入されたときにそんな Issue を見たが忘れた。 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 12 Feb 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-02-05-writing-cmdlet-in-fsharp-pt12.html</guid><link>https://krymtkts.github.io/posts/2023-02-05-writing-cmdlet-in-fsharp-pt12.html</link><title>F#でコマンドレットを書いてる pt.12</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;プロパティ指定検索をおおむね実装できて、バグ取りに勤しんでいる。バグ取りしたので割とまともに動いてるな～という感じ。&lt;/p&gt;
&lt;p&gt;また、 &lt;code&gt;Ctrl+Space&lt;/code&gt; で入力候補の表示非表示切り替え、プロパティ名の自動補完もやりたいけど、 &lt;a href=&quot;https://github.com/krymtkts/pocof/pull/14&quot; title=&quot;Pull Request&quot;&gt;Pull Request&lt;/a&gt; がずっと開きっぱなしで締まりがないし別の Issue に切り分けた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/19&quot; title=&quot;#19&quot;&gt;#19&lt;/a&gt;, &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/20&quot; title=&quot;#20&quot;&gt;#20&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;一旦プロパティ指定検索が完成したら &lt;code&gt;main&lt;/code&gt; branch に合流する。&lt;/p&gt;
&lt;p&gt;手が空いた時しか趣味プロやらないので、小分けにして取り組まないと何やってたかわからなくなる。これは今回デカめの feature にしてしまったことで当初の予定より大幅に長く開発してる。もっと小気味好いリズムを刻みたいので反省点として次に活かす。&lt;/p&gt;
&lt;p&gt;...という計画で進めているのでテストケースを書いてたら、エグいバグに気づいた。これ &lt;code&gt;PSCustomObject&lt;/code&gt; 利用した際に描画できないし、何なら戻り値が破壊される。やば。&lt;/p&gt;
&lt;p&gt;ちょうどプロパティ指定検索でテストケースを書くときに &lt;code&gt;PSCustomObject&lt;/code&gt; 使ってたら、期待の通り動かず、気づいた。このままやとテスト書けへんやん。&lt;/p&gt;
&lt;p&gt;ちょっとショッキングなバグだったので初めからか？いつからか？と混乱したが、よくよく考えると普段自分で作った &lt;code&gt;PSCustomObject&lt;/code&gt; に対してインタラクティブな絞り込みやってないわ...と気づいた。なんで使ってなかったのか？自分で定義するからインタラクティブに調べるほどでもなかったからか。
普段使ってない＆テストザルで見落としてたのか～かっこ悪う...&lt;/p&gt;
&lt;p&gt;とりあえず最低限の原因調査として、PowerShell Gallery から &lt;code&gt;pocof&lt;/code&gt; の旧版をインストールしテストしたところ、 &lt;code&gt;hahstable&lt;/code&gt; をサポートした &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.2.0-alpha&quot; title=&quot;pocof 0.2.0-alpha&quot;&gt;pocof 0.2.0-alpha&lt;/a&gt; でぶっ壊れた模様。
&lt;code&gt;PSObject&lt;/code&gt; の wrapping を引き剥がすあたりでやってもーてそう。&lt;/p&gt;
&lt;p&gt;再現コード。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;pscustomobject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;a&amp;#x27;&lt;/span&gt;=&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;b&amp;#x27;&lt;/span&gt;=&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# a b&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# - -&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 1 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$b&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt; | pocof &lt;span class=&quot;hljs-literal&quot;&gt;-NonInteractive&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$b&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 虚無が出力される。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;なんか &lt;code&gt;NoteProperty&lt;/code&gt; が吹っ飛んでるっぽいのよね。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt;.psobject.Members | ? &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; MemberType &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; NoteProperty | &lt;span class=&quot;hljs-built_in&quot;&gt;Format-list&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# MemberType      : NoteProperty&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# IsSettable      : True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# IsGettable      : True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Value           : 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# TypeNameOfValue : System.Int32&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name            : a&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# IsInstance      : True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# MemberType      : NoteProperty&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# IsSettable      : True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# IsGettable      : True&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Value           : 2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# TypeNameOfValue : System.Int32&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name            : b&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# IsInstance      : True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$b&lt;/span&gt;.psobject.Members | ? &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; MemberType &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; NoteProperty | &lt;span class=&quot;hljs-built_in&quot;&gt;Format-list&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 無&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このままだとプロパティ指定検索のテストが書けないので、この bugfix を優先する。
Issue 立てた。 &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/21&quot; title=&quot;not work with &lt;code&gt;PSCustomObject&lt;/code&gt; · Issue #21 · krymtkts/pocof&quot;&gt;not work with &lt;code&gt;PSCustomObject&lt;/code&gt; · Issue #21 · krymtkts/pocof&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;テストに関してももうちょい強化が必要かもな。今のところ &lt;a href=&quot;https://github.com/pester/Pester&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt; で書いてる E2E テストのみなのだけど、 &lt;code&gt;PSCustomObject&lt;/code&gt; 使ったケースなかったし。&lt;/p&gt;
&lt;p&gt;コード自体もグチャァ...としてきたから &lt;a href=&quot;https://github.com/fsprojects/FsUnit&quot; title=&quot;FsUnit&quot;&gt;FsUnit&lt;/a&gt; 導入してもう少し丁寧にやったほうが良さげ。
&lt;a href=&quot;/posts/2022-05-07-start-to-write-cmdlet-by-fsharp.html&quot; title=&quot;&lt;code&gt;pocof&lt;/code&gt; 書き始めた頃&quot;&gt;&lt;code&gt;pocof&lt;/code&gt; 書き始めた頃&lt;/a&gt;に「可能な限りテストを書きたい所存」て書いてたけど有言不実行になってて笑える(笑えない)。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 05 Feb 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-01-29-things-related-to-cvs2git.html</guid><link>https://krymtkts.github.io/posts/2023-01-29-things-related-to-cvs2git.html</link><title>cvs2git にまつわるアレコレ</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;ちょっとだけ CVS から Git に変換するときの事がわかった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2023-01-22-want-to-comvert-migu-cvs-to-git-and-failed.html&quot; title=&quot;先日の日記&quot;&gt;先日の日記&lt;/a&gt;にも追記したが、 remote repo の本体にファイルアクセスできないと使えない。それはつまり repo 所有者じゃないと git repo への変換ができないんだ。
もうこれだけで、自分で手を動かしてどうこうする計画は終了やなというところだが、なんか調べたことを供養するために記しておく。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;cvs2svn は今や GitHub repo を残すのみ。多くのドキュメントに参照されているであろう &lt;code&gt;http://cvs2svn.tigris.org/&lt;/code&gt; はもう閉鎖されている。
&lt;a href=&quot;https://github.com/mhagger/cvs2svn&quot; title=&quot;mhagger/cvs2svn: Migrate CVS repositories to Subversion or Git. This site supersedes the old tigris.org site, which has shut down.&quot;&gt;mhagger/cvs2svn: Migrate CVS repositories to Subversion or Git. This site supersedes the old tigris.org site, which has shut down.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;で、この GitHub repo に cvs2git 含む cvs2svn を動かすための Dockerfile もある。
わたしはそれを知る前に、 Ubuntu 18 であればパッケージが提供されてるのを知ったのでとりあえずそれを使う Dockerfile を書いたのだけど、本家を使う方が良いだろう。&lt;/p&gt;
&lt;p&gt;書いた Dockerfile の repo は供養のため public にした。&lt;a href=&quot;https://github.com/krymtkts/ubuntu-cvs2git&quot; title=&quot;krymtkts/ubuntu-cvs2git&quot;&gt;krymtkts/ubuntu-cvs2git&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;更に、 PowerShell でこの Docker image をビルドし実行するにあたって、どうでもいい気付きを得た。&lt;/p&gt;
&lt;p&gt;PowerShell で Docker の &lt;code&gt;--mount&lt;/code&gt; オプションを使う場合は、オブションに渡すパラメータ全体を文字列にしてやる必要があった。
昔は &lt;code&gt;--volume&lt;/code&gt; 使ってたし、ビルド関係は &lt;code&gt;COPY&lt;/code&gt; で済ますし、何なら最近触ってなかったから気づきになって良かったわ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.docker.com/storage/bind-mounts/#start-a-container-with-a-bind-mount&quot; title=&quot;Bind mounts | Docker Documentation&quot;&gt;Bind mounts | Docker Documentation&lt;/a&gt; には bash かなんかの shell の例があるが、これは PowerShell では NG 。&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt; docker run -d \&lt;br /&gt;  -it \&lt;br /&gt;  --name devtest \&lt;br /&gt;  --mount &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;hljs-built_in&quot;&gt;bind&lt;/span&gt;,&lt;span class=&quot;hljs-built_in&quot;&gt;source&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(pwd)&lt;/span&gt;&amp;quot;&lt;/span&gt;/target,target=/app \&lt;br /&gt;  nginx:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;PowerShell の流儀に従えばこうなる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-pwsh&quot;&gt;docker run &lt;span class=&quot;hljs-literal&quot;&gt;-d&lt;/span&gt; `&lt;br /&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;-it&lt;/span&gt; `&lt;br /&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;--name&lt;/span&gt; devtest `&lt;br /&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;--mount&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;type=bind,source=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;((pwd).Path)/target,target=/app&amp;quot;&lt;/span&gt; `&lt;br /&gt;  nginx:latest
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;因みに、 Windows の場合は Path の delimiter が &lt;code&gt;\&lt;/code&gt; なので &lt;code&gt;/&lt;/code&gt; に変換する必要がある、という情報を Web でよく見る。
のだけど、 &lt;code&gt;\&lt;/code&gt; &lt;code&gt;/&lt;/code&gt; にかかわらずマウントできた(更新されて変わったのかな)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-pwsh&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# こうしてもしなくてもどっちでもよい&lt;/span&gt;&lt;br /&gt;docker run &lt;span class=&quot;hljs-literal&quot;&gt;-d&lt;/span&gt; `&lt;br /&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;-it&lt;/span&gt; `&lt;br /&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;--name&lt;/span&gt; devtest `&lt;br /&gt;  &lt;span class=&quot;hljs-literal&quot;&gt;--mount&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;type=bind,source=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;((pwd).Path -replace &amp;#x27;\\&amp;#x27;,&amp;#x27;/&amp;#x27;)/target,target=/app&amp;quot;&lt;/span&gt; `&lt;br /&gt;  nginx:latest
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;p&gt;今回調べたことで改めて知ったが、CVS/SVN -&amp;gt; Git の変換はもうみんな興味なく、情報は陳腐化してるしツールは放棄されかかってるようだった。
作ってる人含め誰も使わなくなったらまあそうなるわ、という感じ。
でもその変換の過渡期に行動を起こさなかった repo てまだありそう。頭の片隅においておこう。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;(2023-02-05 追記)&lt;/p&gt;
&lt;p&gt;後でから気づいたが、この Docker の &lt;code&gt;--mount&lt;/code&gt; オプションみたいな回避方法って PowerShell で Maven のオプション使うときにも似たようなのあったわと思い出した。
最近出くわしてなくてすっかり忘れてたみたい(老化現象か)。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 29 Jan 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-01-22-want-to-comvert-migu-cvs-to-git-and-failed.html</guid><link>https://krymtkts.github.io/posts/2023-01-22-want-to-comvert-migu-cvs-to-git-and-failed.html</link><title>Migu の CVS repo を Git repo に変換したい(そして失敗)</title><description>&lt;div class=&quot;section&quot;&gt;&lt;h4 &gt;&lt;a name=&quot;2023-01-29-&quot; href=&quot;#2023-01-29-&quot;&gt;2023-01-29 追記&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;これ上手くいかないの当然で、サーバにある repo 本体に対してこれを実行しないといけない。
centralized VCS 久しぶりだったので、仕組みをすっかり忘れていた。
この日記は間違いの記録となった。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Migu フォントが好きでずっと使っている。
それこそ &lt;a href=&quot;/posts/2021-05-30-maybe-completed-refining-migu-nerd-font.html&quot; title=&quot;Migu で PowerLine を使うためにパッチスクリプトを改修する&quot;&gt;Migu で PowerLine を使うためにパッチスクリプトを改修する&lt;/a&gt;くらいには気に入っている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mix-mplus-ipa.osdn.jp/migu/&quot; title=&quot;Migu フォント : M+と IPA の合成フォント&quot;&gt;Migu フォント : M+と IPA の合成フォント&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今後も使い続けるにあたって、この度 Migu のグリフやコードを読んでみたいと思ったのだけど、 Migu は OSDN の CVS で管理されているので、なかなか読み辛い。
自分が VCS を使い始めたのは SVN からだったりするので、 CVS わからない事が多い。
なのでこの度 Git の repo に変換しようと考えている。&lt;/p&gt;
&lt;p&gt;方法を調べているが、もう時代的に cvs → git の変換なんてあまり行われてないようだ。
情報を調べてみても流石に最近のものはなく、いまんところ 2020 頃の記事が参考になるか。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://alpha3166.github.io/blog/20200523.html&quot; title=&quot;CVS リポジトリを Git リポジトリに変換する | アルファのブログ&quot;&gt;CVS リポジトリを Git リポジトリに変換する | アルファのブログ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ひとまず &lt;a href=&quot;https://osdn.net/cvs/view/mix-mplus-ipa/&quot; title=&quot;Index of /mix-mplus-ipa - mixfont-mplus-ipa - OSDN&quot;&gt;Index of /mix-mplus-ipa - mixfont-mplus-ipa - OSDN&lt;/a&gt; にアクセスし repo の tarball を download してある。&lt;/p&gt;
&lt;p&gt;これに対して、 WSL の Ubuntu 20 で &lt;a href=&quot;https://gitlab.com/esr/cvs-fast-export&quot; title=&quot;cvs-fast-export&quot;&gt;cvs-fast-export&lt;/a&gt; をインストールして &lt;code&gt;cvsconvert&lt;/code&gt; かけてみたのだけどエラーになってしまった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;hljs-meta prompt_&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt;cvsconvert -pvn mix-mplus-ipa/mixfont-mplus-ipa&lt;/span&gt;&lt;br /&gt;2023-01-22T07:25:17Z: Reading file list...done, 0.000KB in 0 files (0.581sec)&lt;br /&gt;2023-01-22T07:25:17Z: Analyzing masters with 16 threads...done, 0 revisions (0.002sec)&lt;br /&gt;2023-01-22T07:25:17Z: Make DAG branch heads...done  (0.000sec)&lt;br /&gt;2023-01-22T07:25:17Z: Sorting...done        after parsing:      0.583   1456KB&lt;br /&gt;after branch collation: 0.583   1456KB&lt;br /&gt;               total:   0.583   1456KB&lt;br /&gt;0 commits/0.000M text, 0 atoms at 0 commits/sec.&lt;br /&gt;fatal: stream ends early&lt;br /&gt;fast-import: dumping crash report to .git/fast_import_crash_50&lt;br /&gt;cvsconvert: cat mix-mplus-ipa-mixfont-mplus-ipa.git.fi | (cd mix-mplus-ipa-mixfont-mplus-ipa-git &amp;gt;/dev/null; git fast-import --quiet --done &amp;amp;&amp;amp; git checkout) returned 128.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;さっぱりわからん。&lt;/p&gt;
&lt;p&gt;他にもツールがあるのでを試してみたいが、 &lt;code&gt;cvs2git&lt;/code&gt; が同梱される &lt;a href=&quot;https://github.com/mhagger/cvs2svn&quot; title=&quot;cvs2svn&quot;&gt;cvs2svn&lt;/a&gt; は Ubuntu 20 で提供されておらず。
&lt;a href=&quot;https://packages.ubuntu.com/search?keywords=cvs2svn&quot; title=&quot;Ubuntu – Package Search Results -- cvs2svn&quot;&gt;Ubuntu – Package Search Results -- cvs2svn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;また &lt;code&gt;git cvsimport&lt;/code&gt; はインストール済みの &lt;code&gt;git&lt;/code&gt; とバージョン競合してしまった。&lt;/p&gt;
&lt;p&gt;こうなったら Dockerfile 書いて Ubuntu 18 で &lt;code&gt;cvs2git&lt;/code&gt; インストールする方が良いか？
ちゃっちゃと終えられるかと思ったけど全然そうじゃなかった。
どうでもいい系のタスクをまた積んでしまったけど、一度手を出したからには最後までやらないと気が済まない。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 22 Jan 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-01-15-writing-cmdlet-in-fsharp-pt11.html</guid><link>https://krymtkts.github.io/posts/2023-01-15-writing-cmdlet-in-fsharp-pt11.html</link><title>F#でコマンドレットを書いてる pt.11</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;年末年始思ったほど時間取れなかったが、 pocof のプロパティ指定検索はちょっとずつ進んでいる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2022-12-18-writing-cmdlet-in-fsharp-pt10.html&quot; title=&quot;前&quot;&gt;前&lt;/a&gt;は入力できるプロパティの候補が表示されるだけだったが、最近ようやく入力できるプロパティの絞り込みと、プロパティを指定した検索ができるようになった。&lt;/p&gt;
&lt;p&gt;プロパティ名は case insensitive に指定できる。まだ複数条件入れたときが buggy でうまく動いてないけど、あとプロパティ入力候補の表示非表示と Ctrl+space での補完ができたら、
ほしいものが出揃うかなーというところだ。&lt;/p&gt;
&lt;p&gt;F# でオブジェクトのプロパティを動的に取得する方法としては、リフレクションを利用した。
これが妥当な実装なのかわからないが、現時点では一番シンプルだ。
オブジェクトに &lt;code&gt;GetType().GetProperty()&lt;/code&gt; してプロパティを特定、 &lt;code&gt;PropertyInfo&lt;/code&gt; を介してクエリで指定されたプロパティ名の文字列を使ってプロパティの値を取得している。&lt;/p&gt;
&lt;p&gt;元々 F# のシンボルには動的にプロパティを参照する &lt;code&gt;?&lt;/code&gt; が書いてある&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;けど実装は提供されてない。
そういうモジュール(&lt;a href=&quot;https://github.com/fsprojects/FSharp.Interop.Dynamic&quot; title=&quot;fsprojects/FSharp.Interop.Dynamic&quot;&gt;fsprojects/FSharp.Interop.Dynamic&lt;/a&gt;)はある。
けど、依存を増やしたくないのと、利用する範囲のコードはすぐ書けるレベルなので自分で実装することにした(使えるか検証してないのもあるし)。&lt;/p&gt;
&lt;p&gt;簡単なはずなんだが、結構自身の F# 力不足に起因して困る場面が多かったので、その内容を記す。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;結論からいうと、自前の &lt;code&gt;?&lt;/code&gt; 演算子を定義しようとしたところ、 &lt;code&gt;?&lt;/code&gt; 演算子を中置演算子として使ったときに想定外の挙動があったので、結局 &lt;code&gt;/?&lt;/code&gt; みたいな謎の組み合わせの演算子を自作した。&lt;/p&gt;
&lt;p&gt;こういうコードがあるとする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;inline&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;?&lt;/span&gt;) (x&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt;) (prop&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; propInfo &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; x.GetType().GetProperty(prop)&lt;br /&gt;        &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;(propInfo.GetValue(x, &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;:?&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;b&lt;/span&gt;)&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;先述のコードを利用した場合、プロパティ名の変数を中置演算子と共に利用すると、変数の名前が引き渡されたパラメータとして認識されてしまい、変数の値が展開されなかった。
通常の関数として呼び出すとこのようなことはないのだけど...
なんか言語仕様を読み落としてる気がする。もうちょっと真面目に追い込んでみる必要があるか。以下は REPL(&lt;code&gt;dotnet fsi&lt;/code&gt;) で試してみた結果。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; str &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;;;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; p &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Length&amp;quot;&lt;/span&gt;;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; a&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; str &lt;span class=&quot;hljs-operator&quot;&gt;?&lt;/span&gt; p;; &lt;span class=&quot;hljs-comment&quot;&gt;// プロパティ p を探しに逝って無いから None&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; a&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; a&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;?&lt;/span&gt;) str p;; &lt;span class=&quot;hljs-comment&quot;&gt;// ちゃんと変数 p の値である Length の値を取れる&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; a&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;結局これの解消ができないので &lt;code&gt;?&lt;/code&gt; を諦めて &lt;code&gt;/?&lt;/code&gt; としたのだが、その前に &lt;code&gt;!?&lt;/code&gt; とか使ってみても駄目だったので妥協してこうなった。
この場合はシンボルの組み合わせに何らかの制限があるようだが、確証を持てるドキュメントが見つけられず。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;inline&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;!?&lt;/span&gt;) (x&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt;) (prop&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;     &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;         &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; propInfo &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; x.GetType().GetProperty(prop)&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;         &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;(propInfo.GetValue(x, &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;:?&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;b&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;     &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;     &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; ;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;inline&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;!?&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; x&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; prop&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;b&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; a&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;!?&lt;/span&gt;) str p;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; a&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; a&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; str &lt;span class=&quot;hljs-operator&quot;&gt;!?&lt;/span&gt; p;; &lt;span class=&quot;hljs-comment&quot;&gt;// なんでエラーになるのかわかってない&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; a&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; str &lt;span class=&quot;hljs-operator&quot;&gt;!?&lt;/span&gt; p;;&lt;br /&gt;  &lt;span class=&quot;hljs-operator&quot;&gt;--------------------^^^&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;stdin(&lt;span class=&quot;hljs-number&quot;&gt;51&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;21&lt;/span&gt;)&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; error FS0003&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; This value is &lt;span class=&quot;hljs-built_in&quot;&gt;not&lt;/span&gt; a &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; cannot be applied.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;inline&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;/?&lt;/span&gt;) (x&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt;) (prop&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;     &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;         &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; propInfo &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; x.GetType().GetProperty(prop)&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;         &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt;(propInfo.GetValue(x, &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;:?&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;b&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;     &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;     &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; ;;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;inline&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;/?&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; x&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;a&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; prop&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&amp;#x27;b&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; a&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; str &lt;span class=&quot;hljs-operator&quot;&gt;/?&lt;/span&gt; p;; &lt;span class=&quot;hljs-comment&quot;&gt;// こっちはいける&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; a&lt;span class=&quot;hljs-operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;Some&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この辺を理解していってもうちょい pocof の開発をスムースに行いたいところやなー。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/fsharp/language-reference/symbol-and-operator-reference/#dynamic-lookup-operators&quot; title=&quot;シンボルと演算子のリファレンス - F# | Microsoft Learn&quot;&gt;シンボルと演算子のリファレンス - F# | Microsoft Learn&lt;/a&gt; &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sun, 15 Jan 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2023-01-08-planning.html</guid><link>https://krymtkts.github.io/posts/2023-01-08-planning.html</link><title>2023</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;例年通り目標をたてる。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;テーマ: 不惑&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;2023 年で遂に本物の四十不惑になる。
惑わずなので基本的に今までの方向性を維持したまま更に歩みを進めるのみ。&lt;/p&gt;
&lt;p&gt;ただの予想だが、当面は腰を落ち着けて物事に取り組める年となるかな？という感じがしている。 2022 年までに続けていたことを深化させられるタイミングかなと。
例えば 2022 年から書き始めた F# はまだまだ書いてきた量が少なく手に馴染んでないので、もう少し書く量を増すとか。&lt;/p&gt;
&lt;p&gt;あと人間四十ともなれば経年劣化がそこそこに出てきてるので、それのメンテナンスを本格に開始することに決めた。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2023-&quot; href=&quot;#2023-&quot;&gt;2023 年の目標&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;基本は継続するテーマ。
新しいテーマも去年中に思いついたもので、既に継続中だったりする。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;転居先を決める&lt;ul&gt;
&lt;li&gt;実家のアレコレがあったりしてやっぱ難しいかもなーというのもあるが、ちょっとずつ条件からでも調整する。もう数年もすれば固定資産の整理とか出てきてこれまた手が空かなそうやが&lt;/li&gt;&lt;li&gt;薪ストーブの生活に憧れてるんやけど薪の調達ルート開拓とか考えると結構重いのが悩み。人脈と軽トラは最低限必須ぽいからなあ...都市圏の場合は廃材をもらったり、田舎であれば森林組合に行く等&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;積読消化 2022 年 の実績 0.5 冊/月を超える&lt;ul&gt;
&lt;li&gt;2022 年末から(仕事上必要になった)全文検索の本を読んでるので、それを勢いづけに習慣化する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;自作ツールの開発&lt;ul&gt;
&lt;li&gt;メインは &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; 。 &lt;code&gt;prerelease&lt;/code&gt; を外す&lt;/li&gt;&lt;li&gt;他ネタは余力があればやる。&lt;a href=&quot;https://cloud.ouraring.com/v2/docs#section/Authentication&quot; title=&quot;Oura API (2.0)&quot;&gt;Oura API (2.0)&lt;/a&gt; で自分ダッシュボードを作るとか&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;F# を学ぶ&lt;ul&gt;
&lt;li&gt;pocof も F# だが他にも書く。ブログ乗せ替えたいなあという気持ちがふつふつとあるので &lt;a href=&quot;https://fable.io/&quot; title=&quot;Fable&quot;&gt;Fable&lt;/a&gt; 使えないかなーとか検討する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;GitHub のストリークを継続する&lt;ul&gt;
&lt;li&gt;commit, issue 何でもいいので継続する。今のまま継続できれば 2023 年中に 180 日、 365 日のストリークを迎えることになるが、その先に何があるか知らん&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;毎週ブログを書く&lt;ul&gt;
&lt;li&gt;2022 は出来たので 2023 も無理やりにでも書く&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;ギター練習を 30 分/毎日&lt;/li&gt;&lt;li&gt;深酒で怪我をしない&lt;ul&gt;
&lt;li&gt;年々減らせてるが、 2022 は 1 回怪我した。今年 2023 は 0 にする&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;自分メンテナンス開始&lt;ul&gt;
&lt;li&gt;人生 100 年死ぬまで労働時代なので、メンテナンスする。まずは肌。ここ数年で顔にシミが目立ちだしたが、あるだけでめちゃくちゃ年老いて見える。これらを物理的に除去するのを考えている。金がかかるが身体の乗り捨てはまだできそうにないし、やむなし&lt;/li&gt;&lt;li&gt;神経を抜いた歯もどうにかしておきたいが、どうにかできるのかこれ...&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;</description><pubDate>Sun, 08 Jan 2023 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-12-31-retrospective2022.html</guid><link>https://krymtkts.github.io/posts/2022-12-31-retrospective2022.html</link><title>振り返り 2022 年</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;2022 年を振り返る。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2022-01-09-planning.html&quot; title=&quot;2022 年のテーマ&quot;&gt;2022 年のテーマ&lt;/a&gt;は「自分の人生は自分で決める」だった。&lt;/p&gt;
&lt;p&gt;手を放れかけた人生の制御権を自分に引き戻すのを目標にしていたところ、おおよそ手元に引き戻せてきたのではないかと感じる。
ここ数年は、年に 1 回は仕事上インパクトのあるネガティブイベントがあった。今年はそれ程のイベントはなかったので、それが起因しての結果だろう。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2022-&quot; href=&quot;#2022-&quot;&gt;2022 年目標と成果&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;今年も 50% 超えでぼちぼち。いい加減に完全勝利もほしい。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ 住みたい場所を決める&lt;ul&gt;
&lt;li&gt;理想と利便性など意見が擦り合わず&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;❌ 積ん読の消化 1 冊/月&lt;ul&gt;
&lt;li&gt;多少ペースを上げたが 0.5 冊 / 月くらいで未達。おしいなあ&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕ 自作ツールの更新&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/mccall-bot&quot; title=&quot;マッコールさん&quot;&gt;マッコールさん&lt;/a&gt;は使う機会がなくて放置してるが、新しく &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; 、 &lt;a href=&quot;https://github.com/krymtkts/PSJobCanAttendance&quot; title=&quot;PSJobCanAttendance&quot;&gt;PSJobCanAttendance&lt;/a&gt; が増えたので -1 + 2 = 1 だし ⭕ にする&lt;/li&gt;&lt;li&gt;自己満足だが PSJobCanAttendance でパイプラインに対応したことで月々の勤怠入力楽すぎてヤバかった(語彙力)&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕ ギター練習を 30 分/毎日&lt;ul&gt;
&lt;li&gt;継続危うかったけど、土壇場で &lt;a href=&quot;/posts/2022-12-25-bought-ouraring-gen3.html&quot; title=&quot;Oura Ring を購入した&quot;&gt;Oura Ring を購入した&lt;/a&gt;ことで習慣化に成功した&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕ &lt;a href=&quot;https://krymtkts.github.io/&quot; title=&quot;このブログ&quot;&gt;このブログ&lt;/a&gt;。毎月の更新リズムを維持する&lt;ul&gt;
&lt;li&gt;毎月どころかリズムを掴んで毎週に発展した&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;❌ 深酒で怪我をしない&lt;ul&gt;
&lt;li&gt;未達。夏に怪我をした&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕ 知らない言語を学ぶ F#&lt;ul&gt;
&lt;li&gt;学んだ結果で &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; を F# で書いてるので当初の目標は ⭕&lt;/li&gt;&lt;li&gt;踏み込んだ言語機能を使えてないのとスタイルもまだ身についていないので、今後も継続する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;以下、当初の予定になかったことのダイジェストだ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;転職&lt;/li&gt;&lt;li&gt;週 1 ブログ&lt;/li&gt;&lt;li&gt;GitHub の草ストリーク 100 突破&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;大きな流れは去年から変わらなかったが、停滞しかけた良い流れを&lt;a href=&quot;/posts/2022-04-09-jobchange-2022.html&quot; title=&quot;今年の 4 月に転職した&quot;&gt;今年の 4 月に転職した&lt;/a&gt;ことで加速できたかなと感じている。今年の転職はほんと運が良かった。
GitHub の個人垢を使っていい会社なのもあり、活動を可視化しやすくなった。&lt;/p&gt;
&lt;p&gt;基本的に、自分の目標のうち殆どは自身に制御権があるものだ。
自身の MP (気力とも) を如何に保ち適切なタイミングで呪文を唱えるか、にかかってる。
そういう目標は、自身のコンディションを維持さえできればどうにでもなるもんやなあと改めて理解した。
週 1 ブログ書いたり、毎日コミットしたり、多少 OSS へのコントリしたり、気持ちの余裕があればできるもんやなあというのが今年の大きな気付きだ。&lt;/p&gt;
&lt;p&gt;そりゃ現職でも大変やな～というような仕事は多いが、基本的に自分でどうにかする仕事しかなく、そこが精神衛生上良く働いている気がする。
新しい何かを決める・調整する・理解するとかは、メンバに頼れるけど頼ったとてそのメンバの仕事が止まるので、結局自分がやるしか無い。腹をくくり自分が責任を持ってやるだけ。
それによって自分が誰かのボトルネックになることやその逆もないので、とてもシンプルだ。弊害として自分以上のパフォーマンスは望めないけど。&lt;/p&gt;
&lt;p&gt;また現職は、振る舞いや能力のミスマッチに起因してチームメンバが飛ばされるとか「You&amp;#39;re fired!」みたいな事故も起こってない。これとても重要。
去年・一昨年は年に 1 度はそういうのがあったから、それ相応に MP を消費していたのだろう。今年は MP 足りず ≒ 意欲が湧かず何も出来ないようなことが起こらなかった。&lt;/p&gt;
&lt;p&gt;自身に制御権がある目標はこの通りだが、逆に自分だけで決められないこと、例えば家庭に関する目標なんかをうまく進められなかった。
ここ数年はタイミング的には相当転居やら移住し易いはずやけど、利便性、子供の養育環境、地理的な人間関係とか諸々、この地に縛り付けるものがあり、なかなか進められない。
座して待ったとしても、そのうち決断の時は必ず来る。それまでにはなんか方向性だけでも出したいなあ。&lt;/p&gt;
&lt;p&gt;あと酒との付き合いは、コントロールが難しく失敗してる。飲酒で怪我をするの、今年は軽いものだったけどやっぱり怪我したので、いい歳だし楽し過ぎて暴走しないようより自制心を持とう。
健康面の訴求から平日の飲酒は控えめ或いはナシにできてるので、この流れで来年は怪我ゼロにつなげたい。&lt;/p&gt;
&lt;p&gt;今年 Oura Ring を購入したこともあって、自身の身体的なコンディションを可視化するのが容易になった。先述の深酒が睡眠のスコアの低さで可視化されて注意しやすくなったり、また運動やギター練習がアクティビティとして見えるので実績回収的なノリで生活に取り入れやすくなる。意図せず好影響を得た形だ。来年はもしやクソチョロなのでは(油断は禁物)。&lt;/p&gt;
&lt;p&gt;運動というか身体的なメンテナンスに関しては、齢四十を迎えるにあたりすごく重要になってきた。健康診断結果を見てガタが来てる部分を見つけたり「今年の冬は肌の乾燥がひどいな～いや歳やこれ」みたいな日々の気付きから、経年劣化を感じている。
日本の状況を鑑みるに今後の人生は甘くなくて、人生 100 年その終わりまで働き続けるのは目に見えてるからこそ、自身のハードウェアのメンテナンスも欠かさないのが重要なんやと今更気付いた。まだサイバーパンク的世界観でインスタントにパーツ交換出来ないので、壊れないように注意しないと(はよきて)。
これまでソフトウェア ≒ 精神の方は相応にメンテしてきてるから、その経験をハードウェア ≒ 肉体の方にも応用できると良いが。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;まとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;来年いよいよ本物の不惑なので、自己が揺らがないように集中していこう。
毎年なんか新しいチャレンジをするのがプログラマの嗜みだと思うけど、ネタをまだ考えついてないので、なんかひねり出したい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 31 Dec 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-12-25-bought-ouraring-gen3.html</guid><link>https://krymtkts.github.io/posts/2022-12-25-bought-ouraring-gen3.html</link><title>Oura Ring Gen3 を買った</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;前から欲しかった &lt;a href=&quot;https://ouraring.com/&quot; title=&quot;Oura Ring&quot;&gt;Oura Ring&lt;/a&gt; を購入した。 買ったのは第 3 世代(Gen3)だ。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;事の起こりから購入まで&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ほしいな～と思い出したのは大体 1 年くらい前。 &lt;a href=&quot;https://techcrunch.com/2021/12/02/oura-ring-3-review/&quot; title=&quot;TechCrunch で Oura Ring 3 review&quot;&gt;TechCrunch で Oura Ring 3 review&lt;/a&gt; を読んだらへん。
スマートリングにも色々あるが、 NFC がついたようなのはあまりに仰々しく邪魔そうでナシ。単純にバイタルデータを取るだけのために腕時計型のウェアラブルデバイスをつけるのも好きじゃない。 Oura Ring はちょうど良い感がある唯一のデバイスとして気になり始めた。&lt;/p&gt;
&lt;p&gt;2022-04 から勤めている現職がヘルステックなのもあって、健康関連の経費補助(満額ではないが)があるので、転職を機にこれは買うしかあるまいなと心を決めた。
また、過去に Gen2 から Gen3 への転換期に&lt;a href=&quot;https://rcmdnk.com/blog/2021/11/01/computer-iot-shopping/&quot; title=&quot;買い替えユーザのメンバーシップを無償にするオファーがあったらしい&quot;&gt;買い替えユーザのメンバーシップを無償にするオファーがあったらしい&lt;/a&gt;。
当面は経費補助で落とすにしても、いつかチャンスが来るかもということで更に背中を押してくれた。&lt;/p&gt;
&lt;p&gt;ところが、 2022 年は記録的な円安になったこともあり、思い立った 5 月頃からずっと変えずにいた。もう仕方がないので 12 月になってやっと自分用のクリスマスプレゼントという建前で多少高くても買うことにした。&lt;/p&gt;
&lt;p&gt;マットでシンプルな &lt;a href=&quot;https://ouraring.com/product/horizon-stealth&quot; title=&quot;Horizon Stealth&quot;&gt;Horizon Stealth&lt;/a&gt; がいいかなーと思ったが、為替によるパンチ力を極力抑えるために、&lt;a href=&quot;https://ouraring.com/product/heritage-black&quot; title=&quot;Heritage Black&quot;&gt;Heritage Black&lt;/a&gt; にした。&lt;/p&gt;
&lt;p&gt;Oura Ring の購入は 12/05 。指輪のサイズなんかわからないので Sizing Kit ありで購入。購入時のコストは以下の通り。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;購入価格 43,200 JPY&lt;ul&gt;
&lt;li&gt;本体 299.00 USD&lt;/li&gt;&lt;li&gt;送料 15.00 USD&lt;/li&gt;&lt;li&gt;換算レートは 2022-12-06 で 1 USD = 137.581 JPY&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;プラス関税で DHL に 3,400.00 JPY&lt;/li&gt;&lt;li&gt;合計 46,600 JPY&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;決して安くない買い物だ。経費補助の残額的に 17,000 円位は補填できるが、自腹で 3 万かー。ちょうどこの時期日本ではソフトバンクでの取り扱いが始まったが、そっちよりは安い(ソフトバンクで買う意味あるんかが謎)。
このガジェットはゴリゴリに使い倒さねばなるまい。&lt;/p&gt;
&lt;p&gt;因みに Heritage Black は、商品ページで見るよりもかなりメタリックだ。黒というよりもガンメタリックでちょっと想像よりもチャラかった。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;購入から本体到着まで&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;購入後の流れは非常にスムーズだった。概要は以下の通り。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;12/05 購入&lt;/li&gt;&lt;li&gt;12/07 Sizing Kit 到着。 9 で検証&lt;/li&gt;&lt;li&gt;12/08 8 で検証&lt;/li&gt;&lt;li&gt;12/09 8 で確定&lt;/li&gt;&lt;li&gt;12/12 本体到着&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;購入の 12/05 から 2 日後の 12/07 に Sizing Kit が届く。
Oura 推奨の利き手の逆の人差し指だとギターが弾けなくなるので、右手人差し指を基準をに考えて 9 で検証はじめた(実際に左手人差し指につけてギターを弾いたら指の腹でネックを握れないのでこの判断は正しい)。
ところが翌朝まで 1 日つけてみていまいちなのではと思い始めた。 9 は朝の時間帯でも少し緩い。&lt;/p&gt;
&lt;p&gt;利手の右手だと、皿洗いや風呂洗い等あらゆる家事をする時にぶつかる、また食事の時は箸にぶつかるなど、大いに支障があるとわかってきた。左手だと皿洗い時に食器の底の凶悪なザラザラに接触する機会があるのだが、他はさして支障にならなかった。
(Oura Ring はチタン製らしい。モース硬度 4 と仮定すると茶碗などの磁器はモース硬度 7 相当であることを考えれば、皿洗いで Oura Ring が傷つくのは想像するに易い)&lt;/p&gt;
&lt;p&gt;同時並行して、使用レビューを Web で漁り、体の変化等で人差し指が多少きつめになったときでも中指に逃げる運用があると知った。実際に自分の人差し指のサイズだと左右で結構差があるが、左手だと人差し指と中指は 8 で運用できるのがわかった。右手人差し指にずっと 8 をはめているのは窮屈だが、ギターを引くときだけはめるとかなら全然いける。
なのでサイズは 8 で決定した。&lt;/p&gt;
&lt;p&gt;決めたのは 12/09 で、待ちに待った本体到着が 12/12 。普段海外のサプリ購入で感じてるリードタイムに比べると相当に早かった。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;運用を始めてみた&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;12/12 の午後くらいから運用している。
つまり本日 12/25 時点で およそ 2 習慣運用した上での感想を記しておく。&lt;/p&gt;
&lt;p&gt;選択している focus area ? は &lt;code&gt;Be productive and energetic&lt;/code&gt; 。なんとなく。これ他のも試してみたいがトレンド？のビューが変わる以外どこに影響あるかわかってない。&lt;/p&gt;
&lt;p&gt;Readiness, Sleep, Activity いずれも概ね 90% 前後で推移しており、数値上は非常に健康であると言えるだろう。&lt;/p&gt;
&lt;p&gt;というのも、 Oura アプリの Insight ？ 画面が非常によくできていて、スコアを落とすことに何らかの罪悪感のようなものを抱かせるようになっているからだ。
例えば、全体的に青い色調のビジュアルをしているが、スコアが低い要素は赤くなって不安感を煽られる(現に 「Pay attention」 と言われるし)。
また Activity が取れていないとアプリの通知で「足をストレッチする時間ちゃうか？」と ~~~脅して~~ 教えてくれるので、強制的に動くような生活リズムが形成されてくる。これが自身で設定した focus area に対応した &lt;del&gt;仕打ち&lt;/del&gt; アプローチなのかは不明だが。&lt;/p&gt;
&lt;p&gt;先にアメとムチで言うところの鞭面について触れたが、アメ面でいえば Readiness, Sleep, Activity の各スコアで 85 以上を叩き出せばクラウンをもらうことができる。クラウンはスコアの横にちょこんと表示されるのだけでなく、カレンダーでそれまで得たクラウンを確認することもできる。
クラウンを得たとてどうということないのだが、ゲーマーなら一種のトロコンのような満足感を得られるだろう。現に 1 週目はクラウンが 1 つの日もあったが、 2 週目は最低でもクラウン 2 つ。来たる 3 週目は間違いなく全冠とれるだろう。&lt;del&gt;アプリに人間が操られていると言っても過言ではない。&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;お陰で装着 1 週目から、 Readiness と Sleep のスコアを改善するために夜更かしせず寝ると決めたら即寝る、 Activity のスコアを改善するために 1 時間毎にこまめに運動する等、生活習慣を改善し始めれた。このまま継続していけば、その手に勝利をつかむ日も遠くないだろう(何と戦ってる？)。&lt;/p&gt;
&lt;p&gt;あと 3 週程で無料のメンバーシップ期間が切れてしまうのだけど、その時アプリがどれだけ使いにくくなるのか検証してみる。それでメンバーシップの継続をするか決めたらいい。現状のレポートに結構満足してるので、多分継続しそうやけど。&lt;/p&gt;
&lt;p&gt;台座みたいな充電器は USB Type-C を接続するやつなのだけど、中の基盤が遊んでるっぽくてちょっとガタツキがある。 Oura Ring 自体はそうそう壊れそうに無いけど、充電器の方は丁寧に扱わないと割とすぐ逝ってしまわれるかも。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-Oura-Ring-&quot; href=&quot;#-Oura-Ring-&quot;&gt;プログラマからみた Oura Ring の楽しみ方&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;もう 1 つ Oura Ring の楽しめる点がある。それは API が充実している点だ。&lt;/p&gt;
&lt;p&gt;ほんまか知らんがアプリで提供される数値は全て API で取ることができるらしい。名称の表記が Oura Cloud API だったり Oura API だったりどっちやねんというところではあるが、ここでは簡単のため Oura API と呼ぶことにする。
現状 Oura API には &lt;a href=&quot;https://cloud.ouraring.com/docs/&quot; title=&quot;Oura API V1&quot;&gt;Oura API V1&lt;/a&gt; と &lt;a href=&quot;https://cloud.ouraring.com/v2/docs&quot; title=&quot;Oura API V2&quot;&gt;Oura API V2&lt;/a&gt; が存在する。 V1 は 2023 年初頭に廃止されるらしい。もうすぐやないか。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The current timeline to sunset the Oura API V1 is early 2023. We are not planning any updates—outside of required maintenance—to the Oura API V1 moving forward. A migration guide for users to transition from V1 to V2 of the Oura API will be available in February 2022.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;API を利用するにあたり認証の手段は 2 つある。
1 つは Personal Access Token 、 もう 1 つは OAuth の API Application だ。
自分のデータにアクセスする場合は Personal Access Token で良いが、複数ユーザのデータを扱うような場合は API Application を使うらしい。でもデフォでは MAX 10 人しか扱えないようなので、より多くのユーザを扱う場合には審査を経て承認が必要だと。はいはい 〇〇 Ads とかの API 利用でもそういうのあったわ。&lt;/p&gt;
&lt;p&gt;Oura API V2 では &lt;a href=&quot;https://cloud.ouraring.com/v2/static/json/openapi.json&quot; title=&quot;OpenAPI spec&quot;&gt;OpenAPI spec&lt;/a&gt; が公開されているので、アプリに組み込むだとかのときも安心に使えそう。
Open API Generator とかで生成したやつが使いやすいかどうかは Schema が丁寧に作られてるか次第だったりするので、いつか試してみるのも良いだろう。&lt;/p&gt;
&lt;p&gt;今日この記事を書くにあたり、 Personal Access Token を用いて自分のデータを取得してみた。&lt;/p&gt;
&lt;p&gt;まずは &lt;a href=&quot;https://cloud.ouraring.com/personal-access-tokens&quot; title=&quot;Personal Access Tokens - Oura Developer API&quot;&gt;Personal Access Tokens - Oura Developer API&lt;/a&gt; で Personal Access Token を発行する。&lt;/p&gt;
&lt;p&gt;疎通確認の為に、自分の Personal Info を取得してみる。 Oura API V2 は Stripe の API Document のように激イケではないものの、見た目はそこそこ親切で好感が持てる。
&lt;a href=&quot;https://cloud.ouraring.com/v2/docs#operation/personal_info_route_get&quot; title=&quot;Get Personal Info&quot;&gt;Get Personal Info&lt;/a&gt; に cURL の例があるのでそれをコピり、 PowerShell 用に書き換える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;curl --location --request GET &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://api.ouraring.com/v2/usercollection/personal_info?start_date=2021-11-01&amp;amp;end_date=2021-12-01&amp;#x27;&lt;/span&gt; \&lt;br /&gt;--header &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Authorization: Bearer &amp;lt;token&amp;gt;&amp;#x27;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ドキュメントには書いてないクエリ文字列がついててなんか怪しい。
試しに今月始めから今までで取得する。といっても配列が得られるわけではないらしい。期間指定するのはなんでだ？まあいい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$Token&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-SecureString&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;!!!PERSONAL_ACCESS_TOKEN!!!&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AsPlainText&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-RestMethod&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Method&lt;/span&gt; Get &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://api.ouraring.com/v2/usercollection/personal_info?start_date=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;((Get-Date -Day 1).ToString(&amp;#x27;yyyy-MM-dd&amp;#x27;))&amp;amp;end_date=&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;((Get-Date).toString(&amp;#x27;yyyy-MM-dd&amp;#x27;))&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Authentication&lt;/span&gt; Bearer &lt;span class=&quot;hljs-literal&quot;&gt;-Token&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Token&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# こんなのが取れる&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# age            : 39&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# weight         : 61&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# height         : 1.8&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# biological_sex : male&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# email          : メアド&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ドキュメントによると身長は 1m を 1 と扱う。体重は Kg らしい。ただ謎なのは 62 Kg で登録してるのに何故 61 ? 連携してるサービス由来か？と思ったが Google Fit も 62 、 Health Connect はどうかわからない。もしやゼロオリジン？わからん。今後調査を進めよう。&lt;/p&gt;
&lt;p&gt;配列じゃないのになんで日を指定するんやろか、と思ってパラメータ削って実行してもデータ取れた。これドキュメントのサンプルコードが間違ってそうやな。ドキュメント自体はあってるので単にケアレスミスやろか。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-RestMethod&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Method&lt;/span&gt; Get &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://api.ouraring.com/v2/usercollection/personal_info&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Authentication&lt;/span&gt; Bearer &lt;span class=&quot;hljs-literal&quot;&gt;-Token&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Token&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 取れるんかい！&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;認証できない時どうなるんだろうと思って &lt;code&gt;Authentication&lt;/code&gt; 外してみたら &lt;code&gt;Internal Server Error&lt;/code&gt; が帰ってきた。まじか。コレジャナイ感がある。試しに V1 で同じことをしてみたらちゃんと 401 が返ってくるので、 V2 まだ未完成なんかなって察する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-RestMethod&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Method&lt;/span&gt; Get &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://api.ouraring.com/v2/usercollection/personal_info&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Invoke-RestMethod: Internal Server Error&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$res&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Method&lt;/span&gt; Get &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://api.ouraring.com/v2/usercollection/personal_info&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-SkipHttpErrorCheck&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$res&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# StatusCode        : 500&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# StatusDescription : InternalServerError&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Content           : Internal Server Error&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-RestMethod&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Method&lt;/span&gt; Get &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://api.ouraring.com/v1/userinfo&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Invoke-RestMethod: {&amp;quot;status&amp;quot;: 401, &amp;quot;title&amp;quot;: &amp;quot;Invalid Access Token&amp;quot;, &amp;quot;detail&amp;quot;: &amp;quot;The access token provided is expired, revoked, malformed, or invalid for other reasons.&amp;quot;, &amp;quot;error&amp;quot;: &amp;quot;invalid_token&amp;quot;, &amp;quot;error_description&amp;quot;: &amp;quot;The access token provided is expired, revoked, malformed, or invalid for other reasons.&amp;quot;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最後に Readiness, Sleep, Activity あたりのデータを取得してみる。期間なしで。アラフォーの赤裸々なバイタルデータだ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-RestMethod&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Method&lt;/span&gt; Get &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://api.ouraring.com/v2/usercollection/daily_readiness&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Authentication&lt;/span&gt; Bearer &lt;span class=&quot;hljs-literal&quot;&gt;-Token&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Token&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-json&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Depth&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   &amp;quot;data&amp;quot;: [&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;contributors&amp;quot;: {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;activity_balance&amp;quot;: 84,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;body_temperature&amp;quot;: 100,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;hrv_balance&amp;quot;: 87,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;previous_day_activity&amp;quot;: 81,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;previous_night&amp;quot;: 96,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;recovery_index&amp;quot;: 100,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;resting_heart_rate&amp;quot;: 100,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;sleep_balance&amp;quot;: 90&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       },&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;day&amp;quot;: &amp;quot;2022-12-24&amp;quot;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;score&amp;quot;: 91,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;temperature_deviation&amp;quot;: -0.08,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;temperature_trend_deviation&amp;quot;: -0.02,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;timestamp&amp;quot;: &amp;quot;2022-12-24T09:00:00+09:00&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     },&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;contributors&amp;quot;: {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;activity_balance&amp;quot;: 85,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;body_temperature&amp;quot;: 96,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;hrv_balance&amp;quot;: 85,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;previous_day_activity&amp;quot;: 94,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;previous_night&amp;quot;: 100,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;recovery_index&amp;quot;: 96,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;resting_heart_rate&amp;quot;: 76,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;sleep_balance&amp;quot;: 92&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       },&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;day&amp;quot;: &amp;quot;2022-12-25&amp;quot;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;score&amp;quot;: 90,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;temperature_deviation&amp;quot;: 0.09,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;temperature_trend_deviation&amp;quot;: 0.06,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;timestamp&amp;quot;: &amp;quot;2022-12-25T09:00:00+09:00&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   ],&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   &amp;quot;next_token&amp;quot;: null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-RestMethod&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Method&lt;/span&gt; Get &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://api.ouraring.com/v2/usercollection/daily_sleep&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Authentication&lt;/span&gt; Bearer &lt;span class=&quot;hljs-literal&quot;&gt;-Token&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Token&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-json&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Depth&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   &amp;quot;data&amp;quot;: [&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;contributors&amp;quot;: {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;deep_sleep&amp;quot;: 99,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;efficiency&amp;quot;: 98,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;latency&amp;quot;: 75,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;rem_sleep&amp;quot;: 100,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;restfulness&amp;quot;: 88,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;timing&amp;quot;: 76,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;total_sleep&amp;quot;: 94&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       },&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;day&amp;quot;: &amp;quot;2022-12-24&amp;quot;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;score&amp;quot;: 91,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;timestamp&amp;quot;: &amp;quot;2022-12-24T09:00:00+09:00&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     },&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;contributors&amp;quot;: {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;deep_sleep&amp;quot;: 100,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;efficiency&amp;quot;: 93,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;latency&amp;quot;: 91,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;rem_sleep&amp;quot;: 100,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;restfulness&amp;quot;: 88,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;timing&amp;quot;: 83,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;total_sleep&amp;quot;: 96&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       },&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;day&amp;quot;: &amp;quot;2022-12-25&amp;quot;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;score&amp;quot;: 94,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;timestamp&amp;quot;: &amp;quot;2022-12-25T09:00:00+09:00&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   ],&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   &amp;quot;next_token&amp;quot;: null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-RestMethod&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Method&lt;/span&gt; Get &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://api.ouraring.com/v2/usercollection/daily_activity&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Authentication&lt;/span&gt; Bearer &lt;span class=&quot;hljs-literal&quot;&gt;-Token&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Token&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-json&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Depth&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   &amp;quot;data&amp;quot;: [&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;class_5_min&amp;quot;: &amp;quot;1111111111111111111111111111111111111111111112211223333333323233333233333332222222211322222232222222232332322333234222223233223332222322222&amp;quot;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;score&amp;quot;: 90,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;active_calories&amp;quot;: 179,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;average_met_minutes&amp;quot;: 1.46875,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;contributors&amp;quot;: {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;meet_daily_targets&amp;quot;: 78,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;move_every_hour&amp;quot;: 100,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;recovery_time&amp;quot;: 100,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;stay_active&amp;quot;: 75,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;training_frequency&amp;quot;: 100,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;training_volume&amp;quot;: 97&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       },&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;equivalent_walking_distance&amp;quot;: 3621,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;high_activity_met_minutes&amp;quot;: 0,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;high_activity_time&amp;quot;: 0,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;inactivity_alerts&amp;quot;: 0,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;low_activity_met_minutes&amp;quot;: 119,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;low_activity_time&amp;quot;: 10860,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;medium_activity_met_minutes&amp;quot;: 37,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;medium_activity_time&amp;quot;: 600,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;met&amp;quot;: {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;interval&amp;quot;: 60.0,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;items&amp;quot;: [&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#           1.1,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#           0.9,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   長すぎ端折る&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#           0.9,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#           0.9&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         ],&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#         &amp;quot;timestamp&amp;quot;: &amp;quot;2022-12-25T04:00:00+09:00&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       },&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;meters_to_target&amp;quot;: 8000,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;non_wear_time&amp;quot;: 0,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;resting_time&amp;quot;: 15900,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;sedentary_met_minutes&amp;quot;: 5,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;sedentary_time&amp;quot;: 14340,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;steps&amp;quot;: 3898,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;target_calories&amp;quot;: 550,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;target_meters&amp;quot;: 12000,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;total_calories&amp;quot;: 1940,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;day&amp;quot;: &amp;quot;2022-12-25&amp;quot;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#       &amp;quot;timestamp&amp;quot;: &amp;quot;2022-12-25T04:00:00+09:00&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   ],&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#   &amp;quot;next_token&amp;quot;: null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Readiness, Sleep は 2 日分、 Activity は 1 日分取れた。日時で実行してデータストアに蓄積するような使い方なら、パラメータを指定する必要もなさそう。基本はデータストアに溜め込むようなことしないだろうし、期間指定してページネーションして利用してねってところか。&lt;/p&gt;
&lt;p&gt;スコアはアプリ表示そのままだが、一部の小数位を含む数値はアプリで表示する精度以上に持っている様子。
また Activity は結構色々データを持っていて面白そう。 METs で 1 分刻みのデータ持ってるのかーとか、 &lt;code&gt;class_5_min&lt;/code&gt; に 5 分刻みのサマリを持ってんのかとか。この強烈なデータ表現はアプリ用なんかな？&lt;/p&gt;
&lt;p&gt;単純にデータを見てもまだピンとこないので、更なる探索はアプリの利用も熟れてきてからが良いかも知れない。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;おわりに&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;自分の体調を可視化できるのすごく良い。踊らされやすい人種なだけかも知れんがこうも行動を変容させられると、可能性を感じざるを得ない。実際にその変わった行動が健康に寄与してるかは健康診断とかの結果見なわからんけど。&lt;/p&gt;
&lt;p&gt;アプリの継続に関しては、仮に自分ダッシュボードを作り上げれたら案外要らないのか？まだ装着期間が短いこともあり出ないレポートもあるみたいなので、その辺を拝ませてもらってからメンバーシップなしにするとかの判断もありか。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 25 Dec 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-12-18-writing-cmdlet-in-fsharp-pt10.html</guid><link>https://krymtkts.github.io/posts/2022-12-18-writing-cmdlet-in-fsharp-pt10.html</link><title>F#でコマンドレットを書いてる pt.10</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;少しだけ pocof のプロパティ指定検索対応を進めた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PSCmdlet.ProcessRecord&lt;/code&gt; のときに &lt;code&gt;PSObject.Properties&lt;/code&gt; から &lt;code&gt;PSPropertyInfo.Name&lt;/code&gt; を取り出して &lt;code&gt;Set&amp;lt;string&amp;gt;&lt;/code&gt; の変数に格納する。
その変数を画面の描画のときに通知領域のところに出すまでを実装した。うまく出てるのを見てみようということだ。&lt;/p&gt;
&lt;p&gt;当然のごとく、常時プロパティの補完候補が出ているのはヘンなので、クエリの入力状況に応じた表示＆プロパティ候補表示 ON/OFF のオプションの追加が必要になる(のが見えてきた。行き当たりばったり)。&lt;/p&gt;
&lt;p&gt;ここで「クエリの入力状況」と書いたが、「プロパティ指定子」(&lt;code&gt;poco&lt;/code&gt; に倣い既定で &lt;code&gt;:&lt;/code&gt; を検討している)が入力されていて、かつカーソルがその「プロパティ指定子」に連続する文字列のポジションにある時が、「プロパティ入力」。つまり入力中のクエリとカーソル位置でモードを切り替える必要がある。&lt;/p&gt;
&lt;p&gt;これ結構めんどくて、クエリとか内部状態として持っているレコードにモードを足して、あとキー押下時やカーソル移動のそれぞれのアクションでモードの ON/OF をやらないといけない。&lt;/p&gt;
&lt;p&gt;もう他にも面倒なやつらしかないんやけど、今とりあえずプロパティ指定検索では以下を実装しようとしている。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;オプションにプロパティ候補 ON/OFF を追加する&lt;/li&gt;&lt;li&gt;内部状態に入力モード(通常・プロパティ)を追加する&lt;/li&gt;&lt;li&gt;「プロパティ入力モード」のときに&lt;ul&gt;
&lt;li&gt;プロパティのタブ補完できるようにする&lt;/li&gt;&lt;li&gt;プロパティ名入力に合わせてプロパティ表示を絞り込み&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;InputObject&lt;/code&gt; のプロパティ指定検索対応&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;途中 &lt;code&gt;PSPropertyInfo&lt;/code&gt; の型に合わせて入力の検査をしたら...とか思い始めたが、これ今やるのは違うわ今はいいわと思って虚無に帰した。やったら楽しそうなので、そのうち復活してくるかも。
他にも湧いては消え × N するアイデアはポツポツあるので、プロパティの対応が終わったらボチボチ真面目に検討できるようになるかなー。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;試しに実装してみて、使い勝手を検証して、更に実装していく。&lt;/p&gt;
&lt;p&gt;これまさにプロトタイピングなのだけど、それなら紙芝居でもいいのでは...という気はしなくもない。
が、紙芝居で作ったらすぐさま試用できるモノが手に入らないので、常に動くものを持てるこっちの方法が楽しい。仕事で気分任せに進めるとヤバい(終わりのないプロトタイピングで金食い潰すとかヤバい)けど趣味プロは誰にも邪魔されない。&lt;/p&gt;
&lt;p&gt;とは言えこのアプローチは継ぎ足し〃の九龍城砦になりがちなので、都度再構築されて然るべきなんだろうとひしと感じている。出発点が PowerShell から F# への写経だったのもあって、当初から微妙と感じるところがいくつかあるのと、 F# の腕が悪いのもあってかっこよくないところとか。来年に持ち越しかなー。これも楽しいのでやりたいけど、先にプロパティを始末したい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 18 Dec 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-12-11-writing-cmdlet-in-fsharp-pt9.html</guid><link>https://krymtkts.github.io/posts/2022-12-11-writing-cmdlet-in-fsharp-pt9.html</link><title>F#でコマンドレットを書いてる pt.9</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;師走は何かと忙しくて pocof のプロパティ指定検索対応に時間が割けていない。
あんまり手も動かせないので、プロパティ指定どうやったらいいかなーと思案している。
つまりこの記事は壁打ちだ。&lt;/p&gt;
&lt;p&gt;どー考えても一番楽なのは、 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.pscmdlet.invokecommand?view=powershellsdk-7.0.0&quot; title=&quot;&lt;code&gt;PSCmdlet.InvokeCommand&lt;/code&gt;&quot;&gt;&lt;code&gt;PSCmdlet.InvokeCommand&lt;/code&gt;&lt;/a&gt; にクエリ文字列から組み立てた &lt;code&gt;FilterScript&lt;/code&gt; を渡す方法。
でもこのやり方でやったとして自分の知見が広がるわけでもないし、楽しくない。&lt;/p&gt;
&lt;p&gt;ということでどうせなら F# の世界からどうにかしてやろうと思っている。
やはり正攻法なのは、&lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.management.automation.psobject.properties?view=powershellsdk-7.3.0&quot; title=&quot;&lt;code&gt;PSObject.Properties&lt;/code&gt;&quot;&gt;&lt;code&gt;PSObject.Properties&lt;/code&gt;&lt;/a&gt;にアクセスする方法だろう。&lt;/p&gt;
&lt;p&gt;難点は、 pocof の &lt;code&gt;InputObject&lt;/code&gt; を内部では &lt;code&gt;PSObject[]&lt;/code&gt; から &lt;code&gt;obj list&lt;/code&gt; に変えてしまってるので、それらを適宜補正してやる必要があるくらい(そもそもなんで &lt;code&gt;obj list&lt;/code&gt; にしたか覚えてない)。なんかできそうに思えてきた。&lt;/p&gt;
&lt;p&gt;フィルタの方は、 &lt;code&gt;PSObject.Properties&lt;/code&gt; にクエリ文字列をパースして抜き出したプロパティ名で値を取れば、クエリ式内で &lt;code&gt;where&lt;/code&gt; に使うのは造作もないことだろう。
&lt;code&gt;hashtable&lt;/code&gt; のときだけ特別サポートしているので、そこと折り合いつけれれば困ること無いのでは(油断している)。&lt;/p&gt;
&lt;p&gt;プロパティの入力候補出すやつは...どうかな。
パラメータ &lt;code&gt;InputObject&lt;/code&gt; に単一の型だけが含まれるのであれば、先頭の要素の &lt;code&gt;PSObject.Properties&lt;/code&gt; から候補を一覧するだけでいいのだけど、奇しくも pocof は複数の型も許容する包容力を持ってるから...&lt;/p&gt;
&lt;p&gt;まー単純に考えて、全走査しているタイミングは 2 つあるので、そこで型情報も一緒に控えておくのが良かろう。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;PSCmdlet.ProcessRecord&lt;/code&gt; で &lt;code&gt;list&lt;/code&gt; に詰めてるのでその時に &lt;code&gt;GetType&lt;/code&gt; する&lt;/li&gt;&lt;li&gt;&lt;code&gt;List.rev&lt;/code&gt; してるときか(&lt;code&gt;ProcessRecord&lt;/code&gt; で計算量減らすため逆に詰めているから)&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;フツーに &lt;code&gt;PSCmdlet.ProcessRecord&lt;/code&gt; いいな。型情報取るだけならなんかこれもできそうな気配してきたな。&lt;/p&gt;
&lt;p&gt;問題は取得したプロパティをどう表示するかやけど、スペース的に空いてるのは正規表現パターンのエラー表示するための行だけなので、そこに出そう。要素数が多い場合は水平方向のスクロール機能(！)を実装しないと使い物にならなさそう...全く実装イメージつかんなこれ。&lt;/p&gt;
&lt;p&gt;会社の期末が 2023-01 なので、なんか来年頭は忙しくなりそうやな～と思うし、この年末年始のお休み期間で如何に F# と戯れることができるかが重要な気がする。 pocof の至らぬ点諸々の棚卸しもやっておきたいし。
それに今年の振り返りもボチボチやり始めとかないと...&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 11 Dec 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-12-04-often-forgotten-in-pwsh-part-1.html</guid><link>https://krymtkts.github.io/posts/2022-12-04-often-forgotten-in-pwsh-part-1.html</link><title>PowerShell で忘れがちなこと pt.1</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;小ネタ。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hashtable&lt;/code&gt; は PowerFighter(勝手に作った PowerShell 使いの呼び名) なら誰しも使いまくるに違いない。&lt;/p&gt;
&lt;p&gt;リテラルが用意されており書きやすいから、ついつい適さない用途にふんだんに利用してしまい、たまにハマる(自分調べ)。
この度、仕事で使っている PowerShell で書いたスクリプトを久しぶりにメンテしたときハマったので、備忘のため記す。
ハマったのは次のような内容だ。&lt;/p&gt;
&lt;p&gt;「複数の数値から重複を取り除く術として &lt;code&gt;hashtable&lt;/code&gt; を使ったが、&lt;code&gt;hashtable&lt;/code&gt; に重複が残った」&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$hash&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Name                           Value&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                           &lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;                              True&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;                              True
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;なんだこりゃ。&lt;/p&gt;
&lt;p&gt;コレが起こった理由は簡単。 1 つ目と 2 つ目の型が異なるからだ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$hash&lt;/span&gt;.Keys | % GetType&lt;br /&gt;&lt;br /&gt;IsPublic IsSerial Name                                     BaseType&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;--------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                                     &lt;span class=&quot;hljs-literal&quot;&gt;--------&lt;/span&gt;&lt;br /&gt;True     True     String                                   System.Object&lt;br /&gt;True     True     Int32                                    System.ValueType
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;理由がわかれば簡単でまじでしょーもない内容だったが、本当にコレで小一時間ハマった。
異なる型が混在したのは単純に全ての分岐で同じ型になっていなかったバグなのだけど、REPL だと一見同じ値にしか見えないのでびっくりする。&lt;/p&gt;
&lt;p&gt;こんなことにならないように、重複を除く用途では型を厳密にできる &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.collections.generic?view=net-7.0&quot; title=&quot;System.Collections.Generic 名前空間&quot;&gt;System.Collections.Generic 名前空間&lt;/a&gt;のコレクションを使うべきだろう。
型属性がクソ長くなるけど。&lt;/p&gt;
&lt;p&gt;先述の、億劫して &lt;code&gt;hashtable&lt;/code&gt; を使った重複の除去は、 &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.collections.generic.hashset-1?view=net-7.0&quot; title=&quot;System.Collections.Generic.HashSet&lt;T&gt;&quot;&gt;System.Collections.Generic.HashSet&lt;T&gt;&lt;/a&gt; を使えば以下のように安全だ。&lt;/p&gt;
&lt;p&gt;ただ各メソッドに戻り値があるので PowerShell の戻り値と相性悪い。
そこが面倒なら &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=net-7.0&quot; title=&quot;System.Collections.Generic.Dictionary&amp;lt;TKey,TValue&amp;gt;&quot;&gt;System.Collections.Generic.Dictionary&amp;lt;TKey,TValue&amp;gt;&lt;/a&gt; かなあ...宣言がさらに長くなる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$h1&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{}&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$h1&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$h1&lt;/span&gt;[&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;1&amp;#x27;&lt;/span&gt;] = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$h1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Name                           Value&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                           &lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;                              &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;                              &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; [&lt;span class=&quot;hljs-type&quot;&gt;System.Collections.Generic.HashSet&lt;/span&gt;[&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]]&lt;span class=&quot;hljs-variable&quot;&gt;$h2&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{}&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$h2&lt;/span&gt;.add(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# 戻り値を無に帰すのがメンドイ&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$h2&lt;/span&gt;.add(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;1&amp;#x27;&lt;/span&gt;) | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# 同上&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$h2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Key Value&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; [&lt;span class=&quot;hljs-type&quot;&gt;System.Collections.Generic.Dictionary&lt;/span&gt;[&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;,&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]]&lt;span class=&quot;hljs-variable&quot;&gt;$h3&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{} &lt;span class=&quot;hljs-comment&quot;&gt;# 長いな...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$h3&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$h3&lt;/span&gt;[&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;1&amp;#x27;&lt;/span&gt;] = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$h3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Key Value&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;とはいえ、型属性の長さやメソッドの戻り値の取り回しにさえ目を瞑れれば、あとは提供される暗黙的変換ライフにより安全な生活が始まる。&lt;/p&gt;
&lt;p&gt;簡潔な構文糖は手に入らないけど、「こんなに長いのタイプできないにょ...」となるときは、代わりの術はあるから...それで以て茶を濁す。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Terminal でなら &lt;code&gt;[hashset&lt;/code&gt; とタイプして TAB を押下すれば、あ～ら不思議、完全名称が自動補完される(これは速くてまじですごい)&lt;/li&gt;&lt;li&gt;VS Code であれば &lt;code&gt;[hashset&lt;/code&gt; とタイプして補完候補から選ぶ。Terminal と比較すると若干もっさり感じる&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;雑多に書きたいときに Generic Type を使うのはちょっと大げさかなという気がしないでもないが、安心安全の PowerLife を送るにはこういうのも必要ということで。
↓ に引用した通り Generics のサポートも手厚くなってるわけだし。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_calling_generic_methods?view=powershell-7.3&quot; title=&quot;about Calling Generic Methods - PowerShell | Microsoft Learn&quot;&gt;about Calling Generic Methods - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Beginning with PowerShell 7.3, you can specify the types for a generic method.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;</description><pubDate>Sun, 04 Dec 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-11-27-writing-cmdlet-in-fsharp-pt8.html</guid><link>https://krymtkts.github.io/posts/2022-11-27-writing-cmdlet-in-fsharp-pt8.html</link><title>F#でコマンドレットを書いてる pt.8</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;前回書いた、 composite query の実装をした。 &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/9&quot; title=&quot;#9&quot;&gt;#9&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;デフォルトでは and で複数のクエリを合成するようにしてる。
一応理由がある。
最初から or だと絞り込む前の状態を覚えていて、追加でほしい候補のためにクエリを書くような使い方になる。
そういう使い方もできるが、ちょっと上級者感がするので、まずは見える範囲で徐々に候補を絞り込めるような and をデフォルトとすることにした。&lt;/p&gt;
&lt;p&gt;そのうちショートカット含めた初期値の変更にも対応したいと思ってたし、起動時から or にしたい場合はそこに盛り込めたらいい。&lt;/p&gt;
&lt;p&gt;ただこの and での合成は hashtable を絞り込むときに出来が悪くて、まだ思ったような絞り込みになっていない。現状 hashtable は or でのみ気持ちよく絞り込むのができなかった。&lt;/p&gt;
&lt;p&gt;これは、 &lt;code&gt;List.allPairs&lt;/code&gt; した複合クエリの List × エントリの List に and の場合は &lt;code&gt;List.forall&lt;/code&gt; or の場合は &lt;code&gt;List.exists&lt;/code&gt; してることで、 hashtable はエントリ Key-Value の二要素あるので and だと両方に共通の文字がないと釣れない...となっているため。
正しくは、 エントリ内の検索候補プロパティは or で、各エントリ毎は and / or のモードを適用できるようにするのが良いか。
プロパティ指定の絞り込みするときにこの問題対処するの必須。&lt;/p&gt;
&lt;p&gt;あと like matcher のときだけクエリが空の状態でもフィルタリングされて表示が 0 件になる挙動を直した。 &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/10&quot; title=&quot;#10&quot;&gt;#10&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;流石に初期表示が 0 件だとはじめ何で絞り込んだらいいんや...(wildcard 埋めたらいいだけやけど)と困惑するので、はじめは全件表示する。&lt;/p&gt;
&lt;p&gt;最後に、今回 PowerShell Gallery に公開する時手間取ったのが、 &lt;a href=&quot;https://github.com/PowerShell/platyPS&quot; title=&quot;platyPS&quot;&gt;platyPS&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2022-11-12-clean-up-pwsh-modules.html&quot; title=&quot;前にモジュールの掃除した&quot;&gt;前にモジュールの掃除した&lt;/a&gt;影響で &lt;a href=&quot;https://github.com/PowerShell/platyPS/tree/v2&quot; title=&quot;platyPS&quot;&gt;platyPS&lt;/a&gt; の version 2 preview より前のモジュールを消し去ってた。
コレにより &lt;code&gt;New-ExternalHelp&lt;/code&gt; Cmdlet がなくなっていて、 psake のリリーススクリプトがエラーするようになってた。
全く想定外。 v2 で消えるのかこの Cmdlet ？？て感じ。
まだ &lt;a href=&quot;https://github.com/PowerShell/platyPS/blob/8ca28935c376ae8dc36ac142e4960fc6d3b725e5/README.md&quot; title=&quot;README.md&quot;&gt;README.md&lt;/a&gt; に消えるような話書いてないし、対応待ってたらいだけなんかな ↓↓&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Create external help xml files (MAML) from platyPS Markdown.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;とりあえず preview でない platyPS を使うことで回避した。
pocof に v1 刻むときにはヘルプファイルもきれいにする必要があるし、その時までに platyPS が v2 でほんとに Cmdlet 失われるのかとかチェックする必要が出てきた。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 27 Nov 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-11-20-writing-cmdlet-in-fsharp-pt7.html</guid><link>https://krymtkts.github.io/posts/2022-11-20-writing-cmdlet-in-fsharp-pt7.html</link><title>F#でコマンドレットを書いてる pt.7</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。
プロパティ指定の検索に対応しようとしていて、今日のはその思考整理のようなもの。 &lt;a href=&quot;https://github.com/krymtkts/pocof/issues/2&quot; title=&quot;Add a property support. · Issue #2 · krymtkts/pocof&quot;&gt;Add a property support. · Issue #2 · krymtkts/pocof&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;実は？ &lt;a href=&quot;https://github.com/jasonmarcher/poco&quot; title=&quot;jasonmarcher/poco&quot;&gt;jasonmarcher/poco&lt;/a&gt; を使ってたときから今に至るまで、プロパティ指定の検索をあまりやってこなかった。
可能性は感じていて何なら使いたかったけど、プロパティをいちいち覚えて打つとかできなくて、使いこなせなかった。
なので pocof でそれを実装するからには、障壁を取り除いて簡単に使える機能にしたい。
そのため、まず pocof が機能に対応したと仮定してどんな風に使うか手を動かすイメージをして、そのあと今の pocof との差を表出させるようなことをしている。&lt;/p&gt;
&lt;p&gt;このアプローチだけでも色々足りないものが見えてきて面白い。
pocof の時から今の pocof に至るまでの自分の使い方が非常に限定的だったのがよく分かる。
今の自分のユースケースの殆どは、文字列化されたオブジェクトに対して正規表現でフィルタできたら、それで済んでしまうのがわかった。&lt;code&gt;Where-Object&lt;/code&gt; でフィルタするタイミングを、実行してデータがわかったその時まで遅延させる、そんな使い方しかしてない。
だから今の pocof はほんとにそれを満たすだけのミニマルさになってて、欲を言えばツールが使用者に違った視点を与えるとかのフィードバックするとか、そいういうモノがないんやなと改めて感じている。&lt;/p&gt;
&lt;p&gt;例えば、 poco の頃にあったスペース区切りで複数の and filter できる機能は pocof にはない。自分が使ってこなかったから作ってなかった。
でもプロパティ指定の検索をするとしたら、これは絶対に使いたい。 1 つのプロパティで絞り込んだとて満足な結果を得られることはないだろう。なんならこれらの複数のプロパティの絞り込みは and だけじゃなくて or でも結合させたい場面が出てくるだろう。
他にも、いま正規表現で &lt;code&gt;.+dir/*+.js&lt;/code&gt; とか書いてるのもスペース区切りで置き換えて &lt;code&gt;dir js&lt;/code&gt; でできたらタイプ数も減って楽でいいよなとか。(正規表現は正規表現で使ったらいいけどほとんどはもっと少ないルールに従ってフィルタできるであろうから)。
こんな感じで、ある 1 つの使い方から芋づる的に派生していく。
確信はないけど、こういった派生が自分の普段の使い方に変化をもたらす気配がしてる。&lt;/p&gt;
&lt;p&gt;とりあえずこの複数のフィルタは composite query と(若干中二病的に)名付けて Issue を起こした。&lt;a href=&quot;https://github.com/krymtkts/pocof/issues/9&quot; title=&quot;Support composite query · Issue #9 · krymtkts/pocof&quot;&gt;Support composite query · Issue #9 · krymtkts/pocof&lt;/a&gt;
やることのイメージが膨れ上がりそうやし、プロパティ指定の検索に必要な最低限を細かく刻んで機能を追加して、その後の成長はまた別に考えるのが良さそうかと考えている。&lt;/p&gt;
&lt;p&gt;はじめに述べたプロパティ指定の検索も、この「普段の使い方に変化をもたらす」気配がしてる。
例えば、わたしは仕事が AWS のリソースを探るのによく使う AWS Tools for PowerShell 。
Cmdlet の出力をフィルタするのやプロパティの確認なんかで、何度か結果を出力したり変数に格納したり、ステップを踏むことが多い。
でもこれが pocof のインタラクティブな検索で試行錯誤できるようになれば、何度もコマンドを実行しなくても粘土をこねるみたいに try &amp;amp; error しやすくなったりしないかな？とか。
選択したプロパティが列になって検索結果に表示されることでわかりやすさが向上しそうだな、とか。&lt;/p&gt;
&lt;p&gt;個人開発では主にゴミスクリプトしか書かないのもあって、改めて自分用のツールを育てる面白さがわかりだした。
個人的な嗜好として、あまり長く同じやり方を続けることを良しとしないのだけど、自分で自分のツールを開発するのってコレとめちゃくちゃ相性良いのでは？と最近思ったりしてる。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;全然関係ないけど .NET 7 出たし、 pocof もさっさと乗り換えてしまのが良さそう(今 .NET 6)。 prerelease なので気兼ねなくやれる。 .NET 7 対応した PowerShell 7.3 かなり速くなった気がするのよな(気だけ？)。その恩恵にあやかりたい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 20 Nov 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-11-12-clean-up-pwsh-modules.html</guid><link>https://krymtkts.github.io/posts/2022-11-12-clean-up-pwsh-modules.html</link><title>師走に向けて PowerShell モジュールの大掃除</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;PowerShell あるあるなのだけど、過去のモジュールが溜まってしまって自分で掃除しないといけない。
開発中でもない限りモジュールを切り戻することもないので、一気に消す。これが PowerFighter(勝手に作った PowerShell 使いの呼び名)の嗜み。&lt;/p&gt;
&lt;p&gt;ゆーてもこしらえてあるスクリプトを流すだけ。以下の通り。個人的に &lt;code&gt;-Scope AllUsers&lt;/code&gt; でモジュールを入れてるからそれに合わせた形となっている。
簡単のため改行を入れている。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# $PSGetPath.AllUsersModules をロードするために一度流す。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-InstalledModule&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Uninstall 対象の取り方。 AllUser 向けに入れてる場合。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ListAvailable&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Path &lt;span class=&quot;hljs-operator&quot;&gt;-Like&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$PSGetPath&lt;/span&gt;.AllUsersModules)*&amp;quot;&lt;/span&gt; `&lt;br /&gt;| &lt;span class=&quot;hljs-built_in&quot;&gt;Group-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Count &lt;span class=&quot;hljs-operator&quot;&gt;-GT&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; `&lt;br /&gt;| &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Group | &lt;span class=&quot;hljs-built_in&quot;&gt;Sort-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Descending&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Version | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Skip&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; } `&lt;br /&gt;| &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { [&lt;span class=&quot;hljs-type&quot;&gt;pscustomobject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        Name = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name;&lt;br /&gt;        RequiredVersion = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Version)&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(if (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.PrivateData.Values.PreRelease) {&amp;#x27;-&amp;#x27;+&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.PrivateData.Values.PreRelease} else {&amp;#x27;&amp;#x27;})&amp;quot;&lt;/span&gt;&lt;br /&gt;    } }&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 心配なときは以下の出力の最新バージョンが Hit してないことを目検する。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Get-Module -ListAvailable | ? -Property Path -like &amp;quot;$($PSGetPath.AllUsersModules)*&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# エグゼキューション。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# はじめは -WhatIf アリで流し、処理する時心配なら Confirm で一個ずつ確認する。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ListAvailable&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Path &lt;span class=&quot;hljs-operator&quot;&gt;-Like&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$PSGetPath&lt;/span&gt;.AllUsersModules)*&amp;quot;&lt;/span&gt; `&lt;br /&gt;| &lt;span class=&quot;hljs-built_in&quot;&gt;Group-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Count &lt;span class=&quot;hljs-operator&quot;&gt;-GT&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; `&lt;br /&gt;| &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Group | &lt;span class=&quot;hljs-built_in&quot;&gt;Sort-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Descending&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Version | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Skip&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; } `&lt;br /&gt;| &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { [&lt;span class=&quot;hljs-type&quot;&gt;pscustomobject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        Name = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name&lt;br /&gt;        RequiredVersion = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Version)&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(if (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.PrivateData.Values.PreRelease) {&amp;#x27;-&amp;#x27;+&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.PrivateData.Values.PreRelease} else {&amp;#x27;&amp;#x27;})&amp;quot;&lt;/span&gt;&lt;br /&gt;    } } | &lt;span class=&quot;hljs-built_in&quot;&gt;Uninstall-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AllowPrerelease&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;prerelease なモジュールの削除も一緒に含めるため、ごちゃごちゃしている。
&lt;code&gt;-Version&lt;/code&gt; の指定を楽にする場合は &lt;code&gt;Get-InstalledModule&lt;/code&gt; を使ったらいいけど、モジュールごとに実行すると遅いし...と思って使ってない。&lt;/p&gt;
&lt;p&gt;これで消しきれるかなと思ったけど、依存関係を忘れてたことでいくつかエラーをもらった。 2 周したらきれいになるかなと思いきや、以下のモジュールに関しては消しきれなかった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Configuration&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;Metadata&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;PackageManagement&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;PowerShellGet&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;これらは &lt;code&gt;AWS.Tools.Installer&lt;/code&gt; と &lt;code&gt;PowerShellGet&lt;/code&gt; が依存しており消せないとのこと。
先述のスクリプトでは最新版は確保するようになってあるし、壊れても入れ直したらいから、古いものに関してはやや強引に &lt;code&gt;-Force&lt;/code&gt; を付与して消し去る。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ListAvailable&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Path &lt;span class=&quot;hljs-operator&quot;&gt;-Like&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$PSGetPath&lt;/span&gt;.AllUsersModules)*&amp;quot;&lt;/span&gt; `&lt;br /&gt;| &lt;span class=&quot;hljs-built_in&quot;&gt;Group-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Count &lt;span class=&quot;hljs-operator&quot;&gt;-GT&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; `&lt;br /&gt;| &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Group | &lt;span class=&quot;hljs-built_in&quot;&gt;Sort-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Descending&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Version | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Skip&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; } `&lt;br /&gt;| &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { [&lt;span class=&quot;hljs-type&quot;&gt;pscustomobject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        Name = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name&lt;br /&gt;        RequiredVersion = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Version)&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(if (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.PrivateData.Values.PreRelease) {&amp;#x27;-&amp;#x27;+&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.PrivateData.Values.PreRelease} else {&amp;#x27;&amp;#x27;})&amp;quot;&lt;/span&gt;&lt;br /&gt;    } } | &lt;span class=&quot;hljs-built_in&quot;&gt;Uninstall-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AllowPrerelease&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この如何にも PowerFighter な近距離パワー型アプローチ、まさに PowerShell って感じ(いいたいだけ)。
穢れたモジュールフォルダを綺麗にできた。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 12 Nov 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-11-06-publish-psjobcanattendance.html</guid><link>https://krymtkts.github.io/posts/2022-11-06-publish-psjobcanattendance.html</link><title>PSJobCanAttendance の公開</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;自分が使う機能はおおよそできたので、 &lt;a href=&quot;https://github.com/krymtkts/PSJobCanAttendance&quot; title=&quot;krymtkts/PSJobCanAttendance&quot;&gt;krymtkts/PSJobCanAttendance&lt;/a&gt; を PowerShell Gallery に公開した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/PSJobCanAttendance/1.0.1&quot; title=&quot;PowerShell Gallery | PSJobCanAttendance 1.0.1&quot;&gt;PowerShell Gallery | PSJobCanAttendance 1.0.1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;デバッグプリント仕込んだまま publish してしまって速攻パッチが上がっている。これ過去に何度かやらかしたので防ぎたいけど防げてない。横着せずにログレベルちゃんと使ってやれよというところか...&lt;/p&gt;
&lt;p&gt;公開のために、&lt;a href=&quot;/posts/2022-10-30-prepare-to-publish-psjobcanattendance.html&quot; title=&quot;前回見つけた&quot;&gt;前回見つけた&lt;/a&gt; 勤怠の実績を一覧する機能のバグを修正した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;休暇があると日付と実績がずれる&lt;/li&gt;&lt;li&gt;最終日の実績が欠落する&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;休暇の実績を含めるようになったので、稼働していない日もひと目で分かる。&lt;/p&gt;
&lt;p&gt;動作確認を行うにあたり、指定した月の勤怠の実績を出力できる必要があったため、それも実装した。
ついでにパイプラインからパラメータを受けるようにしたことで、複数月の勤務実績を取得するのも容易だ。しかも期間が連続していない実績を引っこ抜くことができる。この挙動、画面ではできないはず(使い道が思い浮かばんけど)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 何故か 8 月を飛ばして 7,9 月の実績を一覧するムーブ&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt; | % {&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Month&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;Get-JobCanAttendance&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ただいまこれ書いてて、休日出勤の実績がある場合にちゃんと一覧できるかな？と思いついたので動作確認してみる必要がありそう。ダメそうなら Issue 行き。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;今後やること&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;勤怠管理サービスを CLI で処理できるようにするの、非公開のものも含めたらこれで 3 個目になった。
私的用途だと、大抵の勤怠管理で以下の機能を作ってきた。自動打刻は作れるが作らないのが良心。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;出退勤のリアルタイム打刻&lt;/li&gt;&lt;li&gt;事後の打刻(編集機能)&lt;/li&gt;&lt;li&gt;実績の一覧&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;今回のケースでいうと、あとコレができたらいいなーというのに以下がある。いずれもジョブカン勤怠管理ローカルな使い勝手を改善するものだ。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;グループが 1 つの場合に group_id の入力を省略できるようにする&lt;/li&gt;&lt;li&gt;実績の削除&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;まず 1 からできたらいい。 大抵の場合入力パラメータを減らせるから、楽さが増す。
2 は画面での編集が面倒でなければ普段作らないのだけど、今回のケースではほしいかなと思っている。理想はインタラクティブに削除対象を選べるようにしたいけど、まずは指定のパラメータで消すとこからやるか。&lt;/p&gt;
&lt;p&gt;あと krymtkts/PSJobCanAttendance 自体 &lt;a href=&quot;https://github.com/krymtkts/PSMFAttendance&quot; title=&quot;krymtkts/PSMFAttendance&quot;&gt;krymtkts/PSMFAttendance&lt;/a&gt; のコピペで作ったのもあって、今見るとなんか至らないイマイチな箇所がチラホラある。
それらを直したい気持ちもあるが、直したとて勤怠入力体験が良くなるわけでもないので、あんま動機づけにならない。&lt;/p&gt;
&lt;p&gt;個人的には、 &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の方をいじれてないから、さっさと勤怠スクリプトは終えてしまいたい。でも、やり始めたら気になって止めにくいのもあって止まらない状態が続いてる。要は惰性だ。
なのでリストアップしたものの、やる気がわかない場合はやらないかも...これぞ趣味プロの醍醐味(しらんけど)。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 06 Nov 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-10-30-prepare-to-publish-psjobcanattendance.html</guid><link>https://krymtkts.github.io/posts/2022-10-30-prepare-to-publish-psjobcanattendance.html</link><title>PSJobCanAttendance の公開準備</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSJobCanAttendance&quot; title=&quot;krymtkts/PSJobCanAttendance&quot;&gt;krymtkts/PSJobCanAttendance&lt;/a&gt; を PowerShell Gallery に公開する準備をしている。
一括編集機能に若干の改善をした。&lt;/p&gt;
&lt;p&gt;従来は、パイプラインを使った一括編集が可能だったが、出勤とか退勤とかの打刻イベント毎にパイプを分ける必要があった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 従来はこんなん&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;12&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;;&lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt;) | %{&lt;span class=&quot;hljs-built_in&quot;&gt;get-date&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;2022-09-&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;) 08:15:00+0900&amp;quot;&lt;/span&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;Edit-JobCanAttendance&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-TimeRecordEvent&lt;/span&gt; work_start &lt;span class=&quot;hljs-literal&quot;&gt;-AditGroupId&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;12&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;;&lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt;) | %{&lt;span class=&quot;hljs-built_in&quot;&gt;get-date&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;2022-09-&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;) 12:00:00+0900&amp;quot;&lt;/span&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;Edit-JobCanAttendance&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-TimeRecordEvent&lt;/span&gt; rest_start &lt;span class=&quot;hljs-literal&quot;&gt;-AditGroupId&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これ自分で使ってみて結構面倒に感じて、時刻と打刻イベントをパイプラインで渡せるように調整した。
この調整により、 1 ヶ月分の出勤・休憩の開始＆終了を一気に登録できる様になってしまった。怠惰が捗る(打刻を必要とする勤怠管理なのは触れてはならない)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 1 ~ 31 日の間で 7 日、 10 日、土日を除いた日に出勤と休憩開始・終了を一括登録する。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;31&lt;/span&gt; | ? {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-notin&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt; } | % {&lt;span class=&quot;hljs-built_in&quot;&gt;get-date&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Day&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;} | ? &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; DayOfWeek &lt;span class=&quot;hljs-operator&quot;&gt;-notin&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt; | % {&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        TimeRecordEvent=&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;work_start&amp;#x27;&lt;/span&gt;&lt;br /&gt;        RecordTime= &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Date&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Hour&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Minute&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Second&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        TimeRecordEvent=&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;rest_start&amp;#x27;&lt;/span&gt;&lt;br /&gt;        RecordTime= &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Date&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Hour&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Minute&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Second&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        TimeRecordEvent=&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;rest_end&amp;#x27;&lt;/span&gt;&lt;br /&gt;        RecordTime= &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Date&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Hour&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;13&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Minute&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Second&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;Edit-JobCanAttendance&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AditGroupId&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Verbose&lt;/span&gt;​
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これには &lt;a href=&quot;https://learn.microsoft.com/ja-jp/dotnet/api/system.management.automation.parameterattribute.valuefrompipelinebypropertyname?view=powershellsdk-1.1.0&quot; title=&quot;ValueFromPipelineByPropertyName&quot;&gt;ValueFromPipelineByPropertyName&lt;/a&gt; を使った。
Cmdlet のパラメータにパイプラインの入力オブジェクト(&lt;code&gt;hashtable&lt;/code&gt; は No)が持つ同名プロパティをマッピングできるので、複数のパラメータをバインドできる。
これ自分の書いた Cmdlet で使うことなかったので、いい勉強になった。&lt;/p&gt;
&lt;p&gt;その後 PSScriptAnalyzer の指摘を修正して、さて公開しよう、というところで登録済みの勤怠を一覧するところにバグが見つかった。
登録した日と勤怠の実績がずれるバグで、これは直したいな～というやつなので、公開はまた先送り・未遂に終わった。&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと別の文脈で、放置していた&lt;a href=&quot;https://github.com/krymtkts/PSMFAttendance&quot; title=&quot;krymtkts/PSMFAttendance&quot;&gt;krymtkts/PSMFAttendance&lt;/a&gt;にメンテの予定がないよとアナウンスを追記した。これで Archive する準備も整った(まだしてない)。&lt;/p&gt;
&lt;p&gt;これまた別の文脈で、現職では Slack に日報を投稿してから退勤するようにしてるので、そこから投稿時間を拾って退勤実績を作るようにしたいと考えている。
そのために Slack からメッセージの一覧を取得し、 PSJobCanAttendance での一括編集にもっていきたい。&lt;/p&gt;
&lt;p&gt;過去に似たようなことをしたとき、 &lt;a href=&quot;https://github.com/RamblingCookieMonster/PSSlack&quot; title=&quot;RamblingCookieMonster/PSSlack&quot;&gt;RamblingCookieMonster/PSSlack&lt;/a&gt; を使った。
しかし PSSlack は 2021 年頃の Slack API の変更に追いついてないので、使うには自力でパッチする必要がある。
(パッチは来てるが適用されていない &lt;a href=&quot;https://github.com/RamblingCookieMonster/PSSlack/pull/115&quot; title=&quot;Fix API deprecation 2021-02-24 by simonfagerholm · Pull Request #115 · RamblingCookieMonster/PSSlack&quot;&gt;Fix API deprecation 2021-02-24 by simonfagerholm · Pull Request #115 · RamblingCookieMonster/PSSlack&lt;/a&gt;)。&lt;/p&gt;
&lt;p&gt;以前使った時はそうしたが、面倒なので .NET の Slack のモジュールとか探してなんとかしたい。
でも、どのモジュールがいいんか...と調べるのも面倒なので、悩み中。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 30 Oct 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-10-23-cleaning-my-pwsh-profile.html</guid><link>https://krymtkts.github.io/posts/2022-10-23-cleaning-my-pwsh-profile.html</link><title>PowerShell の My Profile を掃除する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;PowerShell の profile を Gist で管理してるのだけど、この度掃除をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/krymtkts/f8af667c32b16fc28a815243b316c5be&quot; title=&quot;My PowerShell profile.&quot;&gt;My PowerShell profile.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;片手間にできる範囲しかやらなかったので、使ってないモジュールと関数の取り除きが主。あとは順番をちょっと入れ替えてみたり、把握してなかった全貌を眺めてみた。&lt;/p&gt;
&lt;p&gt;これらの取り除きついでに、供養がてら何のためにつかってたのかとか振り返ってみる。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;モジュール取り除き&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/mklement0/ClipboardText&quot; title=&quot;mklement0/ClipboardText: Universal clipboard text support for PowerShell, notably also in PowerShell Core (cross-platform) and Windows PowerShell v2-v4&quot;&gt;mklement0/ClipboardText: Universal clipboard text support for PowerShell, notably also in PowerShell Core (cross-platform) and Windows PowerShell v2-v4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/ClipboardText/0.1.8&quot; title=&quot;ClipboardText&quot;&gt;ClipboardText&lt;/a&gt; というモジュール。コレなんで使ってたのかすら忘れてしまったけど、結構使ってた記憶がある。
&lt;code&gt;Set-ClipboardText&lt;/code&gt; &lt;code&gt;Get-ClipboardText&lt;/code&gt; が使えるようになる。
PowerShell Core を使い始めた頃はクリップボード操作の Cmdlet がなくてできなかったとかそんな理由だったか？&lt;/p&gt;
&lt;p&gt;今やフツーに &lt;code&gt;Set-Clipboard&lt;/code&gt; &lt;code&gt;Get-Clipboard&lt;/code&gt; 使ってるので不要になったけどずっと消してなかった。今までありがとう、消した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/poco/1.1.0&quot; title=&quot;poco&quot;&gt;poco&lt;/a&gt;も残ってるかな？と思ったが、そうでもなかった。
(変え漏れを除けば)意外にも &lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.2.0-alpha&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; への変更は忘れてなかったらしい。&lt;/p&gt;
&lt;p&gt;あとモジュールは跡形もなかったが、昔 &lt;a href=&quot;https://www.powershellgallery.com/packages/GoogleCloud/1.0.1.10&quot; title=&quot;GoogleCloud&quot;&gt;GoogleCloud&lt;/a&gt; を使って勉強してたときの名残があったのでそれも消した。
このモジュールもう 4 年くらいメンテされてない様子、残念やけど多分重要でないんだろうな。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;関数取り除き&lt;/a&gt;&lt;/h4&gt;&lt;h5 &gt;&lt;a name=&quot;-VirtualBox-&quot; href=&quot;#-VirtualBox-&quot;&gt;明らかな消し忘れ。 VirtualBox 関連&lt;/a&gt;&lt;/h5&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Start-VBoxMachine&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    vboxmanage list vms | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Pocof&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-CaseSensitive&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-String&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Stream&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-String&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Pattern&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\{(.+)\}&amp;#x27;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { vboxmanage startvm (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Matches[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;].Groups[&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;1&amp;#x27;&lt;/span&gt;].Value) &lt;span class=&quot;hljs-literal&quot;&gt;--type&lt;/span&gt; headless }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Stop-VBoxMachine&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    vboxmanage list runningvms | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Pocof&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-CaseSensitive&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-String&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Stream&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-String&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Pattern&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\{(.+)\}&amp;#x27;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { vboxmanage controlvm (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Matches[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;].Groups[&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;1&amp;#x27;&lt;/span&gt;].Value) poweroff }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Get-RunningVBoxMachines&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    vboxmanage list runningvms&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こんなのがあった。VirtualBox の GUI を介さずに VM の起動・停止をするための奴らだったか確か。
前々職でコンテナ移行しきれてない秘伝の開発環境 VM がチラホラあって、それで使ってた記憶がある。あの VM ちゃん達は今も元気に VM してるのだろうか。
もはや使うこともないので消す。でも供養がてら Gist に残しておいた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/krymtkts/47f70697cbe006e81d7fd801e1e3b351&quot; title=&quot;krymtkts/scripts-for-virtualbox.ps1&quot;&gt;krymtkts/scripts-for-virtualbox.ps1&lt;/a&gt;&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-code-find-code-&quot; href=&quot;#-code-find-code-&quot;&gt;なんだコレ。 &lt;code&gt;find&lt;/code&gt; ぽい？やつ&lt;/a&gt;&lt;/h5&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;find&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;(&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;.&amp;#x27;&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$True&lt;/span&gt;,&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;ValueFromPipeline&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$True&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;[]]&lt;span class=&quot;hljs-variable&quot;&gt;$name&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;switch&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$delete&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;begin&lt;/span&gt; {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;process&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$n&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Name&lt;/span&gt;) {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$delete&lt;/span&gt;) {&lt;br /&gt;                &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name &lt;span class=&quot;hljs-operator&quot;&gt;-Like&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$n&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Remove-Item&lt;/span&gt;&lt;br /&gt;            }&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;                &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name &lt;span class=&quot;hljs-operator&quot;&gt;-Like&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$n&lt;/span&gt;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt; {&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;なんか薄っすらと、 &lt;code&gt;Makefile&lt;/code&gt; から &lt;code&gt;find&lt;/code&gt; 呼ぶときに何のシェルか考えるの面倒で PowerShell で &lt;code&gt;find&lt;/code&gt; 作ろうとしてた覚えがあるのだけど、それをいつやってたのかわからない。いま使ってもないのでなんでここにあるのか不明。
消す。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-profile-&quot; href=&quot;#-profile-&quot;&gt;何故 profile に足した？クソデカテキストファイルを作る関数&lt;/a&gt;&lt;/h5&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;New-TextFile&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Name&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;long&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Byte&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;Math&lt;/span&gt;]::Pow(&lt;span class=&quot;hljs-number&quot;&gt;1024&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;),&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Basis&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;Math&lt;/span&gt;]::Pow(&lt;span class=&quot;hljs-number&quot;&gt;1024&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)&lt;br /&gt;    )&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;begin&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Name&lt;/span&gt;) {&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Error&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;overrides currently not supported.&amp;#x27;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Remains&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$Byte&lt;/span&gt; % &lt;span class=&quot;hljs-variable&quot;&gt;$Basis&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Per&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$Byte&lt;/span&gt; / &lt;span class=&quot;hljs-variable&quot;&gt;$Basis&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;process&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hljs-variable&quot;&gt;$Per&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x&amp;#x27;&lt;/span&gt; * &lt;span class=&quot;hljs-variable&quot;&gt;$Basis&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Add-Content&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Name&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Encoding&lt;/span&gt; ascii &lt;span class=&quot;hljs-literal&quot;&gt;-NoNewline&lt;/span&gt; }&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$Remains&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x&amp;#x27;&lt;/span&gt; * &lt;span class=&quot;hljs-variable&quot;&gt;$Remains&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Add-Content&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Name&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Encoding&lt;/span&gt; ascii &lt;span class=&quot;hljs-literal&quot;&gt;-NoNewline&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;前に書いた &lt;a href=&quot;/posts/2022-03-13-create-huge-text-file-in-pwsh.html&quot; title=&quot;PowerShell でクソデカテキストファイルを作る&quot;&gt;PowerShell でクソデカテキストファイルを作る&lt;/a&gt; の関数版だと思われる。
わざわざ profile に入れておいたのはなんでだろう。スクリプトにするだけで良いのでは...過去の自分に問いたい。消した。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-code-psake-code-auto-completer-&quot; href=&quot;#-code-psake-code-auto-completer-&quot;&gt;&lt;code&gt;psake&lt;/code&gt; の auto completer 壊れてるで...&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;あと今回の掃除を通して &lt;code&gt;psake&lt;/code&gt; の auto completer 壊れてるやんと言うのに気づいたので、直した。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Invoke-psake&lt;/code&gt; の存在チェックをしてあったら &lt;code&gt;Register-ArgumentCompleter&lt;/code&gt; するようにしてた。
けど、どっかのタイミングから &lt;code&gt;invoke-psake&lt;/code&gt; が &lt;code&gt;invoke-cpsake&lt;/code&gt; になってて、 auto completer が登録されなくなってた。&lt;/p&gt;
&lt;p&gt;auto completer 周り、 &lt;code&gt;aws_completer&lt;/code&gt; で &lt;code&gt;Register-ArgumentCompleter&lt;/code&gt; 設定するとこも、 AWS CLI 1 の頃から使ってたのもあり AWS CLI 2 では要らなくなった部分がある(良くないけど PyPI からモジュール取ってたときの名残)。
今回は対応を先送りにした。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;おわり&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;そこまで消すものなかったな、というのが率直な感想だが、掃除してないな～という profile だった。&lt;/p&gt;
&lt;p&gt;コマンドの存在をチェックしてから関数とか auto completer 登録するみたいなの増えてるので、この辺共通化したいなあ。
でも共通化しだすとファイル分割もしたくなり、結局のところ今の Gist から取ってくるの終焉に向かうのでは...と思った。&lt;/p&gt;
&lt;p&gt;なんかより良い(楽な) PowerShell の Profile 管理手段ないかなー。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 23 Oct 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-10-16-writing-cmdlet-in-fsharp-pt6.html</guid><link>https://krymtkts.github.io/posts/2022-10-16-writing-cmdlet-in-fsharp-pt6.html</link><title>F#でコマンドレットを書いてる pt.6</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hashtable&lt;/code&gt; サポートした。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;やはり &lt;code&gt;IDictionary&lt;/code&gt; 実装用に特別処理みたいなのを書いてあげないといけないかなーという気が若干してる。コイツ以外にも色々出てきたら面倒なので気が向かないけど、特別扱いなのはたしかにそうなので。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;前回コメントしていた実装方針にした。先のことはわからないので、いま想定できない未来は未来の自分に託す。&lt;/p&gt;
&lt;p&gt;これによって &lt;code&gt;pocof&lt;/code&gt; は &lt;code&gt;hashtable&lt;/code&gt; のエントリをフィルタできるようになった。 クエリは &lt;code&gt;hashtable&lt;/code&gt; の &lt;code&gt;Key&lt;/code&gt; / &lt;code&gt;Value&lt;/code&gt; それぞれに適用される。こんな感じ ↓。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{a=&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;1&amp;#x27;&lt;/span&gt;;b=&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;2&amp;#x27;&lt;/span&gt;;c=&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;3&amp;#x27;&lt;/span&gt;;d=&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;a1&amp;#x27;&lt;/span&gt;;e=&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;b2&amp;#x27;&lt;/span&gt;} | pocof &lt;span class=&quot;hljs-literal&quot;&gt;-NonInteractive&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Query&lt;/span&gt; a&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name                           Value&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ----                           -----&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# a                              1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# d                              a1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ただしフィルタして得られる値は &lt;code&gt;hashtable&lt;/code&gt; ではなく、 &lt;code&gt;Object[]&lt;/code&gt; (中身は &lt;code&gt;System.Collections.DictionaryEntry&lt;/code&gt;) になる。
一瞬 &lt;code&gt;hashtable&lt;/code&gt; に戻したいかな～と思ったが、色々使い道を模索しているときに以下のようなおもしろ利用法あるとわかったので、そのケースで不都合ありそうでやめた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 十把一絡げ&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$misc&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt;; &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{a=&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;b=&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;;c=&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;}; (&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Sunday, 16 October, 2022 15:25:19&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Key   : c&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Value : 3&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name  : c&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Key   : b&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Value : 2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name  : b&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Key   : a&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Value : 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Name  : a&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 11&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 12&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 13&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 14&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 15&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$misc&lt;/span&gt; | pocof &lt;span class=&quot;hljs-literal&quot;&gt;-NonInteractive&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Query&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Sunday, 16 October, 2022 15:25:19&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;因みにこういったケースの活用方法はまだ見出していない。ただなんかこのファジーな検索あると面白そうなので残している。例えば、色んなものを array に詰め込んでおいて後でから見ようってアプローチとかになるんではないかと。
仕事の製品コードにこういうの見つけたら卒倒しそうやけど、自分が terminal でなんかデータを捏ねくり回すときにあったら、新たな世界が開けるのでは？的な。しらんけど。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/GraphicalTools&quot; title=&quot;&lt;code&gt;Out-ConsoleGridView&lt;/code&gt;&quot;&gt;&lt;code&gt;Out-ConsoleGridView&lt;/code&gt;&lt;/a&gt; はこういう事できなくて、同じ型が揃ってないとエラーになる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$misc&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-ConsoleGridView&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Out-ConsoleGridView: Object reference not set to an instance of an object.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/where-object?view=powershell-7.2&quot; title=&quot;&lt;code&gt;Where-Object&lt;/code&gt;&quot;&gt;&lt;code&gt;Where-Object&lt;/code&gt;&lt;/a&gt; は流石懐が深くて、 &lt;code&gt;-FilterScript&lt;/code&gt; を使えば同様のことができる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$misc&lt;/span&gt; | ? {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ひとまず &lt;code&gt;hashtable&lt;/code&gt; サポートも終えたので、 プロパティ指定でフィルタする機能を実装する気持ちが高まってきてる。
だけど、このファジーなフィルタの発見によって、フィルタ対象の array に登場する型をチェックしてプロパティを得て...みたいなことが必要になり、面倒さが増した。&lt;/p&gt;
&lt;p&gt;率直に言ってコレだるいｗのだけど、こういう楽しみって趣味プロならではの醍醐味じゃないかな。第一ユーザが自分なので、自分が納得できないモノは許容し難いのよな。&lt;/p&gt;
&lt;p&gt;まだまだゆるく長く楽しめそうな気配がしていて、良い。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 16 Oct 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-10-09-replace-battery-of-razer-stealth.html</guid><link>https://krymtkts.github.io/posts/2022-10-09-replace-battery-of-razer-stealth.html</link><title>Razer Blade Stealth 13 (2017)のバッテリーを換装する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;My Laptop は Razer Blade Stealth 13 2017 モデルなのだが、流石に経年劣化が目立つようになってきた。
バッテリーの膨張だ。&lt;/p&gt;
&lt;p&gt;Razer Blade Stealth 13 は美しいアルミ削り出しボティなのだけど、ここ 1 年くらいは底面が何か弧を描いてんな～と感じていたものの、実用上支障がなかったので放置していた。
ところが、夏を過ぎた頃になって蓋を締めたときにピッチリ閉まらなくなってきて「あ、これはヤバイな」と感じた。
早急に交換が必要だと(あんま放置すると筐体の歪みが戻らなくなる)。&lt;/p&gt;
&lt;p&gt;もう 4,5 年ものなので CPU の遅さや RAM の少なさ(16GB)も目立つといえば目立つのだけど、 PC のスタートアップやソフトウェアのアップデートに時間がかかる以外ではまだ開発したりゲームする上で対して不満はない状態(仕事だとイライラしそうだが)なので、&lt;del&gt;円安世界で不要な出費を抑えるためにも&lt;/del&gt;バッテリーを交換して長く使おうと考えた。&lt;/p&gt;
&lt;p&gt;参考にした記事 →&lt;a href=&quot;https://neareal.com/3353/&quot; title=&quot;RazerBlade のバッテリーを換装する – NEAREAL&quot;&gt;RazerBlade のバッテリーを換装する – NEAREAL&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ホントのところは iFixit のリペアキット込み込みバッテリが欲しかったのだけど、おま国で購入できなかった(結果無駄にアカウントだけ作ってしまった)。&lt;/p&gt;
&lt;p&gt;なもんで Razer Blade Stealth 13 2017 モデルの型番を Amazon.co.jp で調べて、交換バッテリーをサクッと見つけた。何個もあったので一番安いのを選ぶ。
&lt;a href=&quot;https://www.amazon.co.jp/gp/product/B0B6139PBJ&quot; title=&quot;購入したバッテリ&quot;&gt;購入したバッテリ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この判断が良くなかったのか、発送から到着まで 1 ヶ月以上かかった。「コロナ禍の影響で香港で物流が滞っている」と聞いたけど果たして...&lt;/p&gt;
&lt;p&gt;正規バッテリじゃないみたいなので心配といえば心配だったけど、届いた品を見たら &lt;strong&gt;デル(株)&lt;/strong&gt; て書いてたし、 PSE マークもあった。でも &lt;code&gt;㈱&lt;/code&gt; の印字がみょーにずれてる。やっぱ模造品かな。&lt;/p&gt;
&lt;p&gt;このバッテリ到着までの長い待ち時間の間にもどんどん膨らみ続け(最近特に酷かった)、タッチパッドのところが一目でわかるくらいに弧を描くようになった。もう限界や...というところで先日バッテリが届いたのでようやく換装に着手できた。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;換装する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;換装で触った範囲、バックパネルとバッテリの固定には 3 種類のネジが使われており、それぞれに対応するドライバが必要だった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;バックパネル&lt;ul&gt;
&lt;li&gt;トルクス T6 x 8 箇所&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;バッテリ&lt;ul&gt;
&lt;li&gt;プラス #1 x 6 箇所&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;バッテリコネクタの蓋&lt;ul&gt;
&lt;li&gt;プラス #0 x 2 箇所&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;バックパネルのネジを外すと自然とバックパネルが浮き上がった。かなりのエネルギーが抑圧されていたらしい。恐ろしすぎる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2022-10-09-laptop/floating-back-panel.jpg&quot; title=&quot;自動的に浮かび上がるバックパネル&quot; alt=&quot;自動的に浮かび上がるバックパネル&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;先程 &lt;strong&gt;バッテリコネクタの蓋&lt;/strong&gt;と書いたけど、バッテリのコネクタを覆うようにプラ板がついてた。恐らく外れないようにするための固定器具だが、コイツが後で困る。&lt;/p&gt;
&lt;p&gt;バッテリはめてみたら 1 箇所だけ 0.3 mm ほどネジ穴とずれてしまってバッチリはまらなかった。仕方ないのでその一箇所だけ無理やりネジ込んだ。&lt;/p&gt;
&lt;p&gt;そしてバッテリのコネクタ、フラットケーブルが長過ぎる...折りたたまないと接続できない。ここで先程のバッテリコネクタの蓋が組み合わさり、うまくはめるためにピンセットで絶妙な畳み込みをする必要があった。&lt;/p&gt;
&lt;p&gt;以下の写真で波打つフラットケーブルとビミョーにずれた &lt;code&gt;㈱&lt;/code&gt; が確認できる。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2022-10-09-laptop/waving-flat-cable.jpg&quot; title=&quot;長過ぎて接続すると波打つフラットケーブル&quot; alt=&quot;長過ぎて接続すると波打つフラットケーブル&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;バッテリコネクタの蓋の隙間に畳み込まれたフラットケーブル。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2022-10-09-laptop/convoluted-flat-cable.jpg&quot; title=&quot;バッテリコネクタの蓋の隙間にねじ込まれるフラットケーブル&quot; alt=&quot;バッテリコネクタの蓋の隙間にねじ込まれるフラットケーブル&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;バッテリの新旧を見比べてみる。古い方(下)からははち切れんばかりのエネルギーを感じる。ほんまに危なっかしいな。爆発する前に新バッテリが届いてほんと良かった。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2022-10-09-laptop/before-after.jpg&quot; title=&quot;スマートな新バッテリ(上)とダイナマイトな旧バッテリ(下)&quot; alt=&quot;スマートな新バッテリ(上)とダイナマイトな旧バッテリ(下)&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;換装後&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;換装前後で明らかに差を感じられる。異様に熱くならなくなってファンが回らなくなった。&lt;/p&gt;
&lt;p&gt;ただ &lt;code&gt;powercfg.exe /BATTERYREPORT&lt;/code&gt; でバッテリ容量が取れない。 これってどうやったら解消されるんだろう？バッテリ残容量も 100% を指しててホンマか？というお気持ち。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;powercfg.exe /ENERGY&lt;/code&gt; したらバッテリの容量が取れないというエラーになった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Battery:Battery Capacity Unknown&lt;br /&gt;The battery capacity could not be determined. This may indicate a firmware (BIOS) problem.&lt;br /&gt;Battery ID&amp;emsp;RazerRazer Blade Stealth
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;バッテリ容量わからないと残容量もわからないのでは？再起動したら認識されるときもあって、その時は 41% だった。Razer Blade Stealth はバッテリ容量が少ないと赤いランプが灯るのだが、そこも真っ赤っ赤。試しに置きっぱなしにしてたら電力不足でシャットダウンしてた。&lt;/p&gt;
&lt;p&gt;どうしたもんかと調査してみたところ、バッテリ交換後は使い切る → フル充電を数回繰り返すと良い、というような情報があったので参考にして 12,3 時間充電してみた。&lt;/p&gt;
&lt;p&gt;よく見たら Amazon のバッテリのページにも同じようなことが書いてた。不自然な日本語でわからなかった。無理に日本語にせず英語にでもしたらいいのに。充電の部分がすっぱり抜けてて当初わからなかった。以下引用&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#39;&amp;#39;&amp;#39; 1.新しいバッテリを正常に使用する前に、容量を 10%程度に放電してからサイクルを 3 ～ 4 回満たしてください。0%まで放電しないように注意してください。そうすると、バッテリが壊れやすくなります。
&amp;#39;&amp;#39;&amp;#39;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;充電後、今朝改めて &lt;code&gt;powercfg.exe /BATTERYREPORT&lt;/code&gt; してみたところ、 98% 48,949 mWh まで表示されるようになった。規格は 53.6Wh なのでまだまだ上まで充電されるのかな。
&lt;code&gt;powercfg.exe /ENERGY&lt;/code&gt; のバッテリ容量のエラーも解消された。
あと何度か繰り返してみて状況見てみるつもり。&lt;/p&gt;
&lt;p&gt;正直なところ筐体が歪んでしまったかもな～と思っていたが、換装後はバッチリ元の平坦さを取り戻せた。たとえ模造品であろうと今のところは満足度が高い。
放電充電繰り返して規格 MAX まで充電されるまでちょっと様子見。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 09 Oct 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-10-02-writing-cmdlet-in-fsharp-pt5.html</guid><link>https://krymtkts.github.io/posts/2022-10-02-writing-cmdlet-in-fsharp-pt5.html</link><title>F#でコマンドレットを書いてる pt.5</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。ほぼ実装におけるメモ、壁打ち。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/GraphicalTools&quot; title=&quot;Out-ConsoleGridView&quot;&gt;Out-ConsoleGridView&lt;/a&gt;を見て &lt;code&gt;hashtable&lt;/code&gt; をフィルタできるのいいな～と思ったので、 &lt;code&gt;hashtable&lt;/code&gt; サポートを始めている。誰得な機能ではあれど、これがあると自分にとって利用の幅が広がる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ProcessRecord&lt;/code&gt; メソッドにおいて、 &lt;code&gt;IDictionary&lt;/code&gt; 実装の場合のみ展開した要素を内部で保持するようにしてみた。一見して煩雑なので、なんかマシにしたい。 &lt;code&gt;list&lt;/code&gt; にして &lt;code&gt;list&lt;/code&gt; 外すあたりがどーにも。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;     override __.ProcessRecord() =&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        input &amp;lt;- List.append input &amp;lt;| List.ofArray __.InputObject&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        let entries: list&amp;lt;obj&amp;gt; =&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            List.ofArray __.InputObject&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            |&amp;gt; List.collect (fun (o: PSObject) -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                match o.BaseObject with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                | :? IDictionary as dct -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    Seq.cast&amp;lt;DictionaryEntry&amp;gt; dct&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    |&amp;gt; Seq.cast&amp;lt;obj&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    |&amp;gt; Seq.toList&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                | _ as o -&amp;gt; [ o ])&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        input &amp;lt;- List.append input entries&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;破壊的な操作ならすぐマシなのが思いつくが、ちょっと寝かせる。とはいえそっちでスッキリするならそっちがいいかな。
いや待て、ここまで書いて &lt;code&gt;fold&lt;/code&gt; の方がスッキリする気が...してきたので後でやってみる。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-2022-10-03-&quot; href=&quot;#-2022-10-03-&quot;&gt;追記(2022-10-03)&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;要らんコードも取り除いてこうした。幾分マシかなあ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;     override __.ProcessRecord() =&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        input &amp;lt;- List.append input &amp;lt;| List.ofArray __.InputObject&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        input &amp;lt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            List.ofArray __.InputObject&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+            |&amp;gt; List.fold&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                (fun acc o -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    match o.BaseObject with&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    | :? IDictionary as dct -&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                        Seq.cast&amp;lt;obj&amp;gt; dct&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                        |&amp;gt; Seq.fold (fun a d -&amp;gt; d :: a) acc&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                    | _ as o -&amp;gt; o :: acc)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+                input&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     override __.EndProcessing() =&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        input &amp;lt;- List.rev input&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;p&gt;この変更を加えることで &lt;code&gt;hashtable&lt;/code&gt; の各要素を扱えるようになるけど、依然フィルタした結果は得られない。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pocof&lt;/code&gt; はいま内部的に各要素の &lt;code&gt;ToString&lt;/code&gt; メソッドの結果に対して LINQ のクエリをかけてる。
そのため &lt;code&gt;DictionaryEntry&lt;/code&gt; のような &lt;code&gt;ToString&lt;/code&gt; の結果が自身のクラスを示す文字列 &lt;code&gt;System.Collections.DictionaryEntry&lt;/code&gt; を返す場合、使い物にならない。&lt;/p&gt;
&lt;p&gt;未実装のプロパティ指定可能にする機能があればまあ使えるので先にやるべきと考えるが、プロパティ未指定時の挙動が定義できてないといけない。
常時プロパティ指定なんてしないので、 &lt;code&gt;ToString&lt;/code&gt; に値が反映されないタイプのオブジェクトの場合に、デフォルトでフィルタ可能な挙動を定義する必要がある。あーこっちのが大事やわ。
やはり &lt;code&gt;IDictionary&lt;/code&gt; 実装用に特別処理みたいなのを書いてあげないといけないかなーという気が若干してる。コイツ以外にも色々出てきたら面倒なので気が向かないけど、特別扱いなのはたしかにそうなので。&lt;/p&gt;
&lt;p&gt;つづく&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 02 Oct 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-09-24-psjobcanattendance.html</guid><link>https://krymtkts.github.io/posts/2022-09-24-psjobcanattendance.html</link><title>PowerShell でジョブカン勤怠管理を操作する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;現職について半年が経とうとしている。幸運なことに毎日忙しく過ごしており打刻もままならん(&lt;del&gt;単にいつも忘れてるだけ&lt;/del&gt;)。
なので、またアレを作った。打刻スクリプトだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSJobCanAttendance&quot; title=&quot;krymtkts/PSJobCanAttendance&quot;&gt;krymtkts/PSJobCanAttendance&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;現職は&lt;a href=&quot;https://jobcan.ne.jp/&quot; title=&quot;ジョブカン勤怠管理&quot;&gt;ジョブカン勤怠管理&lt;/a&gt;を使ってるので、また新しく作る必要があった。
とはいえ&lt;a href=&quot;https://github.com/krymtkts/PSMFAttendance&quot; title=&quot;krymtkts/PSMFAttendance&quot;&gt;krymtkts/PSMFAttendance&lt;/a&gt;をベースに開発(コピペ)しているので、構造的には同じ。
異なるのはスクレイピングの部分だけといって過言ない。&lt;/p&gt;
&lt;p&gt;個人的に考える目玉機能は以下の 2 つ。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;OTP 対応&lt;/li&gt;&lt;li&gt;一括編集&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;1 については、認証時に OTP を取得する &lt;code&gt;ScriptBlock&lt;/code&gt; 差し込めるようにしてある。現職では都合が良いことに 1Password を使わせえてもらえてるので、 &lt;a href=&quot;https://developer.1password.com/docs/cli/get-started/&quot; title=&quot;op&quot;&gt;op&lt;/a&gt; を使って取得した OTP が渡せるのだ。
&lt;code&gt;ScriptBlock&lt;/code&gt; がない場合は入力を求めるプロンプトになる。&lt;/p&gt;
&lt;p&gt;2 については、自分の現職における勤務実績の入れ方を考えると、絶対必要だったものだ。
現職はフレックスでかなりゆるいのでほぼ勤怠管理無いに等しいが、打刻は求められている。ただ自身が怠惰なせいもあり、3 週間くらい打刻を忘れていて〆前に急いで入力するなんてことが多発している。これを楽にこなすためにも、今回は絶対に一括編集機能を作りたかった。休憩時間が自動入力の設定じゃないようなので、打刻漏れしたときの作業の重さは尚更だ。&lt;/p&gt;
&lt;p&gt;以下のようにパイプを使った一括編集ができる。端的に言って、楽過ぎてヤバい(打刻しろ)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;12&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;;&lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt;) | %{&lt;span class=&quot;hljs-built_in&quot;&gt;get-date&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;2022-09-&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;) 08:15:00+0900&amp;quot;&lt;/span&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;Edit-JobCanAttendances&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-TimeRecordEvent&lt;/span&gt; work_start &lt;span class=&quot;hljs-literal&quot;&gt;-AditGroupId&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上記の様な感じで試しに 3 週ほどの実績をドバドバと書き込んでみたが、リクエストが拒否されることもなく使えて一安心だった。
今回の打刻スクリプトを作るにあたり、毎度のごとく利用規約はチェック済みだ。&lt;a href=&quot;https://jobcan.ne.jp/aup&quot; title=&quot;利用規約｜ジョブカン勤怠管理&quot;&gt;利用規約｜ジョブカン勤怠管理&lt;/a&gt;を確認したが、こういうスクリプトを作ることに関し問題なさそうだった。&lt;/p&gt;
&lt;p&gt;本当は 2022 年夏頃には一通り作ってたのだけど、その後 2 ヶ月位使わずに来てたので、この週末でまとめ上げた。来週から実際に使ってみて、熟れてきたら PowerShell Gallery に公開しようと考えている。&lt;/p&gt;
&lt;p&gt;今回作ってみて気づいたこと。&lt;a href=&quot;https://github.com/krymtkts/PSMFAttendance&quot; title=&quot;krymtkts/PSMFAttendance&quot;&gt;krymtkts/PSMFAttendance&lt;/a&gt; を作ったときは、同サービスの前例が 1 つくらいしかなかったのに、今回は前例を探せば結構ヒットした。
「No.1 勤怠管理」の名は伊達じゃないな！と思わせるものがあった(何様)。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2021-11-27-psmfattendance.html&quot; title=&quot;前に作った Money Forward クラウド勤怠のやつ&quot;&gt;前に作った Money Forward クラウド勤怠のやつ&lt;/a&gt;は、前職を離れて実行環境がないからもうメンテもできないし、そろそろ Archive してもイイ気がする。
バグ残ったママだけど直して動作確認できないからしゃーない。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 24 Sep 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-09-18-data-ide-data-station-build-notes.html</guid><link>https://krymtkts.github.io/posts/2022-09-18-data-ide-data-station-build-notes.html</link><title>データ IDE DataStation のビルド関連メモ</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;ちょっと前に &lt;a href=&quot;https://datastation.multiprocess.io/&quot; title=&quot;DataStation&quot;&gt;DataStation&lt;/a&gt; という OSS の IDE を知った。
GitHub の repo はこちら。&lt;a href=&quot;https://github.com/multiprocessio/datastation&quot; title=&quot;multiprocessio/datastation: App to easily query, script, and visualize data from every database, file, and API.&quot;&gt;multiprocessio/datastation: App to easily query, script, and visualize data from every database, file, and API.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;データベース・ファイル・HTTP リクエストまで多様なデータソースへの接続をサポートしてたり、簡単にグラフ化、コードで加工したり、とにかく良い。 Notebook みたいといえばそんな感じ。&lt;/p&gt;
&lt;p&gt;ちょっとコントリしたいネタがあり、その動作確認のためにビルドして実行する必要があった。その時の手順・つまづきポイントを備忘のために雑メモで記しておく。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;DataStation のアーキテクチャについてはこちらのメモにある。そんなに詳しくないので自力で色々読んだり試したりした方がイイか。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/multiprocessio/datastation/blob/66b77f0cfe41040c49fe1e42e6f267b59f45b5bf/ARCHITECTURE.md&quot; title=&quot;datastation/ARCHITECTURE.md at main · multiprocessio/datastation&quot;&gt;datastation/ARCHITECTURE.md at main · multiprocessio/datastation&lt;/a&gt;&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;デスクトップアプリのビルドと実行&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/multiprocessio/datastation/blob/66b77f0cfe41040c49fe1e42e6f267b59f45b5bf/HACKING.md&quot; title=&quot;datastation/HACKING.md at main · multiprocessio/datastation&quot;&gt;datastation/HACKING.md at main · multiprocessio/datastation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;手順はこれを参照した。でも試してる途中でよくわからなくなってくるので、&lt;a href=&quot;https://github.com/multiprocessio/datastation/blob/66b77f0cfe41040c49fe1e42e6f267b59f45b5bf/package.json&quot; title=&quot;&lt;code&gt;package.json&lt;/code&gt;&quot;&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/a&gt; を読んで各スクリプトが何者かは読んだ方がイイかも(実際そうした)。&lt;/p&gt;
&lt;p&gt;ビルドと実行には WSL2 を使う。 手順に記載のある通り Windows でもできるっぽい(&lt;a href=&quot;https://jmeubank.github.io/tdm-gcc/&quot; title=&quot;tdm-gcc&quot;&gt;tdm-gcc&lt;/a&gt;というのを使う)けど、なんか面倒な気配がしたので Linux で楽をする。いつかチャレンジしてもよいが今ではないと判断した。
GCC は Go の SQLite3 モジュールをビルドするので必要っぽい。&lt;/p&gt;
&lt;p&gt;ビルドの事前準備には依存関係のインストールスクリプトが用意されてる(CI 用だけど)。それを使って楽をする。
&lt;a href=&quot;https://github.com/multiprocessio/datastation/blob/66b77f0cfe41040c49fe1e42e6f267b59f45b5bf/scripts/ci/prepare_linux.sh&quot; title=&quot;datastation/prepare_linux.sh&quot;&gt;datastation/prepare_linux.sh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;DataStation のデスクトップアプリは Electron アプリの様子。
以下のビルド実行時に権限が必要だったのと、それによって &lt;code&gt;--no-sandbox&lt;/code&gt; が必要になった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; yarn build-desktop --no-sandbox
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このビルド実行でライブラリが不足しているのがわかり、以下を参考にパッケージをインストールした。なんのエラーが出たかはメモを失念したが、 lib* が足りない系。
足りない依存関係は皆 Electron のビルドに必要なものばかりだった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://akinov.hatenablog.com/entry/2021/04/04/151851&quot; title=&quot;Puppeteer でライブラリ不足 libraries: libatk-1.0.so.0 - ノンカフェインであなたにやさしい&quot;&gt;Puppeteer でライブラリ不足 libraries: libatk-1.0.so.0 - ノンカフェインであなたにやさしい&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/electron/electron-quick-start/issues/486#issuecomment-1153535808&quot; title=&quot;Missing shared libraries · Issue #486 · electron/electron-quick-start&quot;&gt;Missing shared libraries · Issue #486 · electron/electron-quick-start&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;この依存関係のインストール後にビルドが成功するようになったが、実行すると SQLite3 のエラーになった。
内容は SQLite3 が古いと言われるものだった(メモ失念)。エラーログを見る限りこれの解消には Electron の再ビルドが必要なようだった(これあとから見てもピンとくるのかわからん。エラーログをメモらなかったことが悔やまれる)。&lt;/p&gt;
&lt;p&gt;↓ の記事を参考にした覚えあり。
&lt;a href=&quot;https://stackoverflow.com/questions/46384591/node-was-compiled-against-a-different-node-js-version-using-node-module-versio&quot; title=&quot;npm - Node - was compiled against a different Node.js version using NODE_MODULE_VERSION 51 - Stack Overflow&quot;&gt;npm - Node - was compiled against a different Node.js version using NODE_MODULE_VERSION 51 - Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;./node_modules/.bin/electron-rebuild
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ここまでやって初めて ↓ のコマンドで Electron アプリを動かして動作確認できるようになった(理解のために結局 &lt;code&gt;package.json&lt;/code&gt; に書かれたスクリプトを直で叩くようになる)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;yarn electron --trace-warning --unhandled-rejection=warn build/desktop.js --no-sandbox
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;runner-UT&quot; href=&quot;#runner-UT&quot;&gt;runner の UT&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;DataStation のデスクトップアプリはいわばフロントエンドで、データソースとの接続やデータ読み取りは Go で書かれた &lt;a href=&quot;https://github.com/multiprocessio/datastation/tree/main/runner&quot; title=&quot;datastation/runner&quot;&gt;datastation/runner&lt;/a&gt; で行われてるようだった。&lt;/p&gt;
&lt;p&gt;なので UT の実行に関しては先述のディレクトリで &lt;code&gt;go test&lt;/code&gt; するだけで OK だった。とはいえ前の節で先述した通り、 GCC に依存したモジュールのビルドがあるので WSL2 でやるのが良かろう。&lt;/p&gt;
&lt;p&gt;終。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 18 Sep 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-09-10-writing-cmdlet-in-fsharp-pt4.html</guid><link>https://krymtkts.github.io/posts/2022-09-10-writing-cmdlet-in-fsharp-pt4.html</link><title>F#でコマンドレットを書いてる pt.4</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;めちゃめちゃ放置してたのだけど、 8 月末くらいから触れるようになってきたので、気になる部分ですぐ変えられる部分を書き換えて、 PowerShell Gallery に公開した。 &lt;a href=&quot;/posts/2022-05-07-start-to-write-cmdlet-by-fsharp.html&quot; title=&quot;はじめたころ&quot;&gt;はじめたころ&lt;/a&gt;から 4 ヶ月くらい経ったのか。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/pocof/0.1.0-alpha&quot; title=&quot;PowerShell Gallery | pocof 0.1.0-alpha&quot;&gt;PowerShell Gallery | pocof 0.1.0-alpha&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;現時点に公開する動機としては、自分の普段遣いでは未だ &lt;code&gt;poco&lt;/code&gt; を使ってるというのもあって、折角なのでそれを &lt;code&gt;pocof&lt;/code&gt; に変えようと考えた次第だ。
一部機能に関しては未実装なので、オプションはコメントアウトして隠した形で公開している。&lt;/p&gt;
&lt;p&gt;大きい変更としては、PowerShell オブジェクトを作成せずに &lt;code&gt;PSCmdlet&lt;/code&gt; のサブクラスの中で PowerShell の Cmdlet を呼び出す方法がわかったので、その辺を書き換えた。
これが非常に参考になった →&lt;a href=&quot;https://github.com/PowerShell/PowerShell/issues/12137&quot; title=&quot;InvokeCommand.InvokeScript not returning Output · Issue #12137 · PowerShell/PowerShell&quot;&gt;InvokeCommand.InvokeScript not returning Output · Issue #12137 · PowerShell/PowerShell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;DLL の モジュールを公開するのは初めてだったので、これまた躓きつつも先達の知恵を借りて乗り越えられた。
これ → &lt;a href=&quot;https://webcoder.info/fspsmodule.html&quot; title=&quot;Writing a PowerShell Core Module With F#, A Complete Guide | Brianary&quot;&gt;Writing a PowerShell Core Module With F#, A Complete Guide | Brianary&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;結局始めた頃はフォルダ指定の公開でええんちゃうかと思ってたが、 &lt;code&gt;Import-Module&lt;/code&gt; してから公開する方がめっちゃ楽なので、参照元に従いそう変えちゃった(こだわり無し)。
そもそもこの記事がなかったら &lt;code&gt;pocof&lt;/code&gt; はサクッと始めてなかったので、感謝しかない。&lt;/p&gt;
&lt;p&gt;それと特に意図があった訳ではないが、 &lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/scripting/developer/module/how-to-write-a-powershell-module-manifest?view=powershell-7.2&quot; title=&quot;PowerShell Module Manifest&quot;&gt;PowerShell Module Manifest&lt;/a&gt; で使ったことがなかった &lt;code&gt;PreRelease&lt;/code&gt; を使ってみたりもした。&lt;/p&gt;
&lt;p&gt;公開にあたっての目玉機能は何もない。何なら &lt;code&gt;poco&lt;/code&gt; の機能で未だ実装してないものもある。
ただいくつか自分が &lt;code&gt;poco&lt;/code&gt; を使っていて困ってたことは、これで解消される。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正規表現パターンの記述中にエラーで落ちない&lt;/li&gt;&lt;li&gt;クエリ記述中に左右カーソル移動ができる(buggy な疑いアリ)&lt;/li&gt;&lt;li&gt;(あとテスト用の非対話モード ← 普段利用ではまじで意味ないけどテストが楽)&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;今後欲しい機能としては、とりあえず自分の使い方だと、プロパティ周り。
プロパティ指定のフィルタとプロパティ入力の補完ができたら相当楽になる。表示するプロパティが選べたりしたら最高。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pocof&lt;/code&gt; で印字されたアイコングリフが &lt;code&gt;??&lt;/code&gt; になってたり他にも色々未実装・直さないといけない点あれど、自分が普段使うツールを自分の手でコントロールできる(しかも学習まで兼ねて)というのは、イイことやなと改めて思った。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 10 Sep 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-09-03-the-cui-ver-of-out-grid-view.html</guid><link>https://krymtkts.github.io/posts/2022-09-03-the-cui-ver-of-out-grid-view.html</link><title>Out-GridView の CUI 版 Out-ConsoleGridView</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;最近知ったのだけど、 &lt;code&gt;Out-GridView&lt;/code&gt; の PowerShell Team 謹製 CUI 版 &lt;code&gt;Out-ConsoleGridView&lt;/code&gt; があったらしい。これが使えるヤツだったら &lt;code&gt;poco&lt;/code&gt; も今作ってる &lt;code&gt;pocof&lt;/code&gt; も要らんやん、と思った。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/GraphicalTools&quot; title=&quot;PowerShell/GraphicalTools: Modules that mix PowerShell and GUIs/CUIs! - built on Avalonia and gui.cs&quot;&gt;PowerShell/GraphicalTools: Modules that mix PowerShell and GUIs/CUIs! - built on Avalonia and gui.cs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;元々 CUI 使ってるのに &lt;code&gt;Out-GridView&lt;/code&gt; で GUI 表示しないとインタラクティブな絞り込みできないのがイヤで &lt;a href=&quot;https://github.com/peco/peco&quot; title=&quot;peco&quot;&gt;peco&lt;/a&gt; を使ってたってのがある。
&lt;code&gt;peco&lt;/code&gt; は PowerShell に最適化されてないから、その後オブジェクトのまま取り扱える &lt;a href=&quot;https://github.com/jasonmarcher/poco&quot; title=&quot;jasonmarcher/poco&quot;&gt;jasonmarcher/poco&lt;/a&gt; にたどり着いた。
その後 &lt;code&gt;poco&lt;/code&gt; の独自実装を自分で始めたのが &lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;&lt;code&gt;pocof&lt;/code&gt;&quot;&gt;&lt;code&gt;pocof&lt;/code&gt;&lt;/a&gt;(F# の練習がてら)。&lt;/p&gt;
&lt;p&gt;なもんで、 &lt;code&gt;Out-GridView&lt;/code&gt; の CUI 版があってもしイイ感じに使えるのなら、この長年の変遷に終止符を打つんちゃうかな的な。&lt;/p&gt;
&lt;p&gt;以下 &lt;code&gt;README.md&lt;/code&gt; に従い試す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Install-Module&lt;/span&gt; Microsoft.PowerShell.ConsoleGuiTools &lt;span class=&quot;hljs-literal&quot;&gt;-AllowPrerelease&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Scope&lt;/span&gt; AllUsers
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-ConsoleGridView&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;/img/2022-09-03-capture/capture.png&quot; title=&quot;水色の背景に印字される `ls` の結果&quot; alt=&quot;水色の背景に印字される `ls` の結果&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;space&lt;/code&gt; キーでオブジェクトを選択するか &lt;code&gt;Ctrl+A&lt;/code&gt; で全選択して、 &lt;code&gt;Enter&lt;/code&gt; で選択した結果を出力する。
&lt;code&gt;-Filter&lt;/code&gt; オプションに渡した値で初期表示がフィルタリングされた形になる。そのままタイプしてもフィルタ入力できない。&lt;code&gt;Tab&lt;/code&gt; キーを押してフィルタのテキストにフォーカスできる。
フィルタは正規表現のみみたい。不正なパターンを入れたらちゃんとエラー表示されてエライ。
必ず結果を洗濯した状態で&lt;code&gt;Enter&lt;/code&gt; 押さないと結果が得られないのはちょっとメンドイ。
わたしは使わないけどマウスコントロール(クリックどころかスクロールまで)できるのもすごいな。
背景変わるの好きになれないので、今後色とかキーとかのオプション充実したりするかなあ。
インクリメンタルサーチじゃないのも微妙に好みじゃない操作性だ。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;poco&lt;/code&gt;、 &lt;code&gt;pocof&lt;/code&gt; 共にバッファを元に戻すとレイアウトの崩れが起きるのだけど、 &lt;code&gt;Out-ConsoleGridView&lt;/code&gt; は崩れない。素晴らしい。
表示域にないスクロール可能な部分は吹っ飛んでしまうけど、崩れない方法は真似させてもらいたい(MIT ライセンスなので)。けど、コード読んだ感じどこかわからなかった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Out-ConsoleGridView&lt;/code&gt; は CmdLet の出力に &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.formatviewdefinition?view=powershellsdk-7.0.0&quot; title=&quot;FormatViewDefinition Class (System.Management.Automation) | Microsoft Docs&quot;&gt;FormatViewDefinition Class (System.Management.Automation) | Microsoft Docs&lt;/a&gt;を自前で作ってるみたい。
なので PowerShell で表示される内容とちょっと違う。
それ故か、例えば &lt;code&gt;Get-InstalledModule&lt;/code&gt; のような情報量の多い結果を表示するとちょっと悲しい感じになってしまった。 &lt;code&gt;format.ps1xml&lt;/code&gt; が利用されないせいかな。しかしこのクラス使い方がわからなかったので勉強になるわ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-InstalledModule&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-ConsoleGridView&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;/img/2022-09-03-capture/jam-packed-capture.png&quot; title=&quot;すし詰めに印字される `Get-InstalledModule` の結果&quot; alt=&quot;すし詰めに印字される `Get-InstalledModule` の結果&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pocof&lt;/code&gt; でやりたいことと方向性が違うなあという感じなので、作ってるものを今すぐブン投げ捨てる必要はなかったようだ。こちらの開発は趣味プロで続けようと思った。しかしコード参考にできるものが増えたのでとても助かるなぁ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 03 Sep 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-08-27-bump-bootstrap.html</guid><link>https://krymtkts.github.io/posts/2022-08-27-bump-bootstrap.html</link><title>Bootstrap のバージョンを上げる</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;先週の記事を書いたあとで、何の気なしに &lt;a href=&quot;https://web.dev/measure/&quot; title=&quot;Measure page quality - web.dev&quot;&gt;Measure page quality - web.dev&lt;/a&gt; で当ブログの測定をした。
そこで既知の脆弱性があるライブラリ (&lt;code&gt;Bootstrap@3.3.0&lt;/code&gt; と &lt;code&gt;jQuery@1.11.0&lt;/code&gt;)使うなよ！みたいなレポートがでたので、 Bootstrap の更新を思い立った。&lt;/p&gt;
&lt;p&gt;変更した内容 → &lt;a href=&quot;https://github.com/krymtkts/krymtkts.github.io/commit/c4adeacb06fe759b787646bba5fb698c1f688c94&quot; title=&quot;Upgrade bootstrap from 3 to 5. · krymtkts/krymtkts.github.io@c4adeac&quot;&gt;Upgrade bootstrap from 3 to 5. · krymtkts/krymtkts.github.io@c4adeac&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ブログ作成当時の記事(&lt;a href=&quot;/posts/2019-01-10-make-blog-with-clojure.html&quot; title=&quot;Clojure でブログを作った&quot;&gt;Clojure でブログを作った&lt;/a&gt;)を見ると、このブログのテーマは Cryogen 備え付けのテーマである &lt;code&gt;blue_centered&lt;/code&gt; をコピって作ったものだった。
そのままずっと使ってるので、当然の如くテンプレで利用しているライブラリも古いままだったという訳だ。&lt;/p&gt;
&lt;p&gt;さて、 Bootstrap のマイグレーションは当然ドキュメントがあるわけだが、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://getbootstrap.com/docs/4.0/migration/&quot; title=&quot;Migrating to v4 · Bootstrap&quot;&gt;Migrating to v4 · Bootstrap&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://getbootstrap.com/docs/5.0/migration/&quot; title=&quot;Migrating to v5 · Bootstrap v5.0&quot;&gt;Migrating to v5 · Bootstrap v5.0&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;今回は&lt;del&gt;手抜きによる&lt;/del&gt; v3 → v5 という飛び級であるし、わたし自身は Bootstrap に慣れてないので、とりあえずマイグレーションで対応するのは目で見て影響がある範囲のみとした。マイグレーションとしては正攻法な感じじゃなくて、割りと雑な感じだ。&lt;/p&gt;
&lt;p&gt;それらの変更は例えば CSS のセレクタの変更だったり、 &lt;code&gt;class&lt;/code&gt; 属性の変更だったりだ。一応レスポンシブなデザインなので PC とモバイル(ブラウザのエミュレータだけど)も見ている。ちょいちょい以前と違うデザインにした・或いは意図せず変わった箇所もある。&lt;/p&gt;
&lt;p&gt;途中コンテンツを空で更新したままデプロイしてしまうしょーもないミスがあったが、再度コンテンツを生成して事なきを得た。
これ Cryogen の差分ビルドの影響でちょいちょいやらかすのだけど、普段は人間力でカバーしていたところを今回はできず、デプロイしてしまった次第。この記事の投稿時点で設定を見直した。&lt;/p&gt;
&lt;p&gt;今回の VerUp により Best Practices は 92 -&amp;gt; 100 に、 あと Performance も 93 -&amp;gt; 94 と意図せず微妙な好影響があった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;before&lt;ul&gt;
&lt;li&gt;&lt;img src=&quot;/img/2022-08-27-capture/before.png&quot; title=&quot;変更前は Performance 93 Accessibility 97 Best Practices 92 SEO 92&quot; alt=&quot;変更前は Performance 93 Accessibility 97 Best Practices 92 SEO 92&quot; loading=&quot;lazy&quot; /&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;after&lt;ul&gt;
&lt;li&gt;&lt;img src=&quot;/img/2022-08-27-capture/after.png&quot; title=&quot;変更後は Performance 94 Accessibility 97 Best Practices 100 SEO 92&quot; alt=&quot;変更後は Performance 94 Accessibility 97 Best Practices 100 SEO 92&quot; loading=&quot;lazy&quot; /&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Bootstrap 5 では CSS カスタムプロパティでフォントサイズとか色とか変えられるみたいなので、このブログ用に再定義してるスタイルのいくつかは不要になるんじゃないかな。
これを機にちょっと見直すのもありかも知れない。あるいは別の静的サイトジェネレータに乗り換えるとか。他にやることなくなったらそれも一興か。&lt;/p&gt;
&lt;p&gt;終。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 27 Aug 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-08-20-osc-133-in-win-term.html</guid><link>https://krymtkts.github.io/posts/2022-08-20-osc-133-in-win-term.html</link><title>Windows Terminal で OSC133 する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;先週は盆の関係で時間が取れず書くのをサボった。まあその前の日曜に余分に書いてたし相殺したことにしておく。&lt;/p&gt;
&lt;p&gt;きょうは Windows Terminal でもシェル統合みたいなのができるらしいと気づいたので、それを試す。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;ちょっと古い Windows Terminal Preview のリリースノートを見てて気づいた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/microsoft/terminal/releases/tag/v1.15.1862.0&quot; title=&quot;Release Windows Terminal Preview v1.15.186 · microsoft/terminal&quot;&gt;Release Windows Terminal Preview v1.15.186 · microsoft/terminal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Get-GitHubRelease -OwnerName microsoft -RepositoryName terminal -Tag v1.15.1862.0 | select -ExpandProperty body | % {$_ -split &amp;quot;`n&amp;quot;} | sls -Pattern &amp;#39;\[Experimental\]&amp;#39; -Context 0,10&lt;/code&gt; で雑に抽出。&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;[Experimental] We now support scrollbar marks! (#12948) (#13163) (#13291) (#13414)&lt;ul&gt;
&lt;li&gt;Use the &lt;code&gt;addMark&lt;/code&gt; action to add a scrollbar mark&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;color&lt;/code&gt; optional parameter can be used to specify a color&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;Use the &lt;code&gt;scrollToMark&lt;/code&gt; action with a specified &lt;code&gt;direction&lt;/code&gt; parameter to scroll between the marks&lt;/li&gt;&lt;li&gt;Use the &lt;code&gt;clearMark&lt;/code&gt; action to remove a selected mark&lt;/li&gt;&lt;li&gt;Use the &lt;code&gt;clearAllMarks&lt;/code&gt; action to remove all scrollbar marks&lt;/li&gt;&lt;li&gt;The &lt;code&gt;experimental.autoMarkPrompts&lt;/code&gt; profile setting can be set to &lt;code&gt;true&lt;/code&gt; to automatically mark each prompt&lt;ul&gt;
&lt;li&gt;NOTE: This uses the FTCS_PROMPT sequence from FinalTerm, &lt;code&gt;OSC 133 ; A&lt;/code&gt;, which we now support! (#13163)&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;The &lt;code&gt;experimental.showMarksOnScrollbar&lt;/code&gt; profile setting can also be set to &lt;code&gt;true&lt;/code&gt; to display the marks on your scrollbar&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;ほう？
プロンプトに自動でマーカーを付けられる様になったらしい。&lt;/p&gt;
&lt;p&gt;この機能使いたかったが、端末乗り換えて profile にシーケンス足して...みたいなのが必要っぽかったのでメンドイなーと思ってけど、端末だけで対応できるのなら非常に楽。&lt;/p&gt;
&lt;p&gt;これはやりたい。試してみる。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;Windows-Terminal-&quot; href=&quot;#Windows-Terminal-&quot;&gt;Windows Terminal の設定&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;利用している Windows Terminal Preview のバージョンは Version: 1.15.2282.0 だった。&lt;/p&gt;
&lt;p&gt;以下のような感じの設定で試す。実際の &lt;code&gt;settings.json&lt;/code&gt; は他の設定でゴチャついているので、要所だけ切り抜いた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;$help&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://aka.ms/terminal-documentation&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;$schema&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://raw.githubusercontent.com/microsoft/terminal/main/doc/cascadia/profiles.schema.json&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;actions&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;command&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;action&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;addMark&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;color&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#CB4B16&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;keys&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ctrl+m&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;command&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;action&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;scrollToMark&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;direction&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;previous&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;keys&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ctrl+up&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;command&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;action&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;scrollToMark&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;direction&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;next&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;keys&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ctrl+down&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;command&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;clearAllMarks&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;keys&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ctrl+d&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;profiles&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;defaults&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;experimental.autoMarkPrompts&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;experimental.showMarksOnScrollbar&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;JSON Schema については、&lt;code&gt;https://aka.ms/terminal-profiles-schema&lt;/code&gt; の方はバージョンが古いので Preview 使ってると色々不都合がある。ので repo 直で見る。&lt;/p&gt;
&lt;p&gt;試してみて、とりあえずすべて期待通りに動くのがわかった。&lt;/p&gt;
&lt;p&gt;はじめスクロールバーに色がつかなくて、はて？だったけど、これは &lt;code&gt;settings.json&lt;/code&gt; の記述が間違ってたからだった。
&lt;code&gt;experimental.autoMarkPrompts&lt;/code&gt;, &lt;code&gt;experimental.showMarksOnScrollbar&lt;/code&gt; は &lt;code&gt;profiles&lt;/code&gt; 直下じゃない。
&lt;code&gt;profiles.defaults&lt;/code&gt; に書かないとダメ。&lt;/p&gt;
&lt;p&gt;これに気づいたのは &lt;a href=&quot;https://github.com/microsoft/terminal/blob/c12987af415c5e0911d7a0a81b8494fbe6307328/doc/cascadia/profiles.schema.json#L2177-L2181&quot; title=&quot;&lt;code&gt;settings.json&lt;/code&gt; の JSON Schema のここ&quot;&gt;&lt;code&gt;settings.json&lt;/code&gt; の JSON Schema のここ&lt;/a&gt;見たら、 &lt;code&gt;Profile&lt;/code&gt; 毎の property であることがわかったから。&lt;/p&gt;
&lt;p&gt;ドキュメントにもこの機能出てた。あとから気づいたわ。
&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/terminal/customize-settings/profile-advanced#scroll-marks-preview&quot; title=&quot;Scroll marks (Preview)- Windows Terminal Advanced Profile Settings | Microsoft Docs&quot;&gt;Scroll marks (Preview)- Windows Terminal Advanced Profile Settings | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ドキュメントの方は、タイトルも「Advanced profile settings in Windows Terminal」 やし、こっちならパっと見で気づけたかな...まあよし。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;今回この件を調べてから、 &lt;a href=&quot;https://github.com/microsoft/terminal/issues/11000&quot; title=&quot;megathread: Scrollbar Marks · Issue #11000 · microsoft/terminal&quot;&gt;megathread: Scrollbar Marks · Issue #11000 · microsoft/terminal&lt;/a&gt; という巨大な Issue を見つけた。
きょう試した experimental な feature もここ由来のもの。&lt;/p&gt;
&lt;p&gt;まだ VS Code のそれに比べると相当しょぼい。
またコマンドの成功・失敗に対応してマーカーの色分けがつくとかもない。
けど、この Issue 見るにそれらはそのうちやるっぽい(&lt;code&gt;category&lt;/code&gt; というやつかな)。なので、 subscribe しておいて新しいのが来たら是非試したい。&lt;/p&gt;
&lt;p&gt;普段仕事で使う標準出力が長い &lt;code&gt;cdk&lt;/code&gt; とか AWS Tools for PowerShell とかの実行結果を飛び回るのに、こんなに有効な機能が来たことは喜ばしい。
来週の仕事から早速使う。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;余談&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ついでに &lt;code&gt;useAcrylic = true&lt;/code&gt; じゃないとき、 &lt;code&gt;opacity&lt;/code&gt; だけで古き良き透過にできるのにも気づいた。
Windows 11 で ver1.12 から使えたらしい...気づくのに時間がかかったけど、これもやりたかったことのひとつなので、良い。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/terminal/customize-settings/profile-appearance#transparency&quot; title=&quot;Opacity - Windows Terminal Appearance Profile Settings | Microsoft Docs&quot;&gt;Opacity - Windows Terminal Appearance Profile Settings | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 20 Aug 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-08-07-git-says-the-local-repo-is-not-yours.html</guid><link>https://krymtkts.github.io/posts/2022-08-07-git-says-the-local-repo-is-not-yours.html</link><title>git で local repo が自分のものじゃないとなったやつ</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今日はブログ書くつもり無かったけど、これまた起こったらなんかハマりそうやなーと思ったので、したためた。&lt;/p&gt;
&lt;p&gt;何があったかわからんが、 git に local repo の所有権が自分にないと言われてエラーになった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; git status&lt;br /&gt;fatal: detected dubious ownership &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; repository at &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;C:/Users/takatoshi/dev/github.com/krymtkts/Get-GzipContent&amp;#x27;&lt;/span&gt;&lt;br /&gt;To add an exception &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; this directory, call:&lt;br /&gt;&lt;br /&gt;        git config &lt;span class=&quot;hljs-literal&quot;&gt;--global&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--add&lt;/span&gt; safe.directory C:\Users\takatoshi\dev\github.com\krymtkts\&lt;span class=&quot;hljs-built_in&quot;&gt;Get-GzipContent&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set&lt;/span&gt; the environment variable GIT_TEST_DEBUG_UNSAFE_DIRECTORIES=true and run&lt;br /&gt;again &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; more information.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;safe.directory&lt;/code&gt; が設定されているパスなのだけど。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; git config &lt;span class=&quot;hljs-literal&quot;&gt;--list&lt;/span&gt; | ? {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-like&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;safe*&amp;#x27;&lt;/span&gt;}&lt;br /&gt;safe.directory=C:/Users/takatoshi/dev/*
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;GIT_TEST_DEBUG_UNSAFE_DIRECTORIES&lt;/code&gt; でデバッグメッセージを有効化できるそうなのでしてみたところ、以下の様なのが出た。
最近使ってた local repo では出なくて、&lt;del&gt;放置してた&lt;/del&gt; 最近ご無沙汰だった repo で出ている。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$env:GIT_TEST_DEBUG_UNSAFE_DIRECTORIES&lt;/span&gt;=&lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; git status&lt;br /&gt;warning: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;C:/Users/takatoshi/dev/github.com/krymtkts/Get-GzipContent/.git&amp;#x27;&lt;/span&gt; is owned by:&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;S-1-5-32-544&amp;#x27;&lt;/span&gt;&lt;br /&gt;but the current user is:&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;S-1-5-21-3808303910-2770483448-703627078-1001&amp;#x27;&lt;/span&gt;&lt;br /&gt;fatal: detected dubious ownership &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; repository at &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;C:/Users/takatoshi/dev/github.com/krymtkts/Get-GzipContent&amp;#x27;&lt;/span&gt;&lt;br /&gt;To add an exception &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; this directory, call:&lt;br /&gt;&lt;br /&gt;        git config &lt;span class=&quot;hljs-literal&quot;&gt;--global&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--add&lt;/span&gt; safe.directory C:/Users/takatoshi/dev/github.com/krymtkts/&lt;span class=&quot;hljs-built_in&quot;&gt;Get-GzipContent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;owner が違う...なんで owner 変わってしまってたんだろう。ユーザー 1 人しかいないのに。
あーハイハイ、と想像がついたので試したところ、管理者権限でならエラーが出ない。&lt;/p&gt;
&lt;p&gt;どうも過去に管理者権限で作成した local repo の所有者が Administrator になってた模様。それが最近の Git for Windows の更新で検知されるようになったんだ。&lt;/p&gt;
&lt;p&gt;Windows で所有者を変更する方法を調べてみて、それっぽい手順があったのでそれに倣う。
Windows のこの辺の昨日全然知らないので、どっかのタイミングで調べないといけないな。
&lt;a href=&quot;https://theitbros.com/using-takeown-exe-command-to-take-ownership-of-file-or-folder/#:~:text=You%20can%20change%20the%20owner,%3E%20Advanced%20%3E%20Owner%20%3E%20Change.&quot; title=&quot;Using Takeown.exe Command to Take Ownership of a File or Folder – TheITBros&quot;&gt;Using Takeown.exe Command to Take Ownership of a File or Folder – TheITBros&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;takeown /F C:\Users\takatoshi\dev\github.com\krymtkts\&lt;span class=&quot;hljs-built_in&quot;&gt;Get-GzipContent&lt;/span&gt; /&lt;span class=&quot;hljs-built_in&quot;&gt;R&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# SUCCESS: The file (or folder):  ....&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# えげつない量の印字...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; git status&lt;br /&gt;On branch master&lt;br /&gt;Your branch is up to date with &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;origin/master&amp;#x27;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;nothing to commit, working tree clean
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;イイね。直せた。
他のディレクトリも所有者を変えた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;takeown.exe /f . /&lt;span class=&quot;hljs-built_in&quot;&gt;r&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# えげつない量の印字を無に帰す...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;終。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 07 Aug 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-08-06-usecase-of-get-gzipcontent.html</guid><link>https://krymtkts.github.io/posts/2022-08-06-usecase-of-get-gzipcontent.html</link><title>Get-GzipContent のユースケース</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;以前 &lt;a href=&quot;https://github.com/krymtkts/Get-GzipContent&quot; title=&quot;krymtkts/Get-GzipContent: Get-Content for gzip files.&quot;&gt;krymtkts/Get-GzipContent: Get-Content for gzip files.&lt;/a&gt; というのを作って &lt;a href=&quot;https://www.powershellgallery.com/packages/Get-GzipContent/0.1.2&quot; title=&quot;PowerShell Gallery&quot;&gt;PowerShell Gallery&lt;/a&gt; に公開した。&lt;/p&gt;
&lt;p&gt;当時 gzip された JSON を扱う機会が多かった。
その時の職場は bash 文化だったのだけど、自分のローカルでは PowerShell を使うし...ということで、モジュールが欲しかった。
この PowerShell で gzip を展開するコード自体よく知られてるパターンらしかったけど、登録されてるモジュールがなかったので、自分で作った。ちゃんと探したら似たモジュールはあったのだろうけど、周辺モジュールもドカッと入るのは期待するところでないので、単機能のモジュールを作ったんだ確か。&lt;/p&gt;
&lt;p&gt;最近になってまた gzip されたファイルを扱う機会が増えたので、改めて使う機会が来たのだけど...これちょっとイマイチやなーと思っている。&lt;/p&gt;
&lt;p&gt;CloudFront のアクセスログで&lt;a href=&quot;https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html#LogFileFormat&quot; title=&quot;標準ログ&quot;&gt;標準ログ&lt;/a&gt;というのがあるのだけど、こいつは gzip された TSV で、これを PowerShell で取り扱うのに以下の関数を作った。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ConvertFrom-CloudFrontAccessLog&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;,&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;Position&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;ValueFromPipeline&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;,&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;ValueFromPipelineByPropertyName&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;,&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;HelpMessage&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Path to one or more locations.&amp;#x27;&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Alias&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSPath&amp;#x27;&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;ValidateNotNullOrEmpty&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;[]]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Path&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;begin&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$header&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;date&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;time&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x-edge-location&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;sc-bytes&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;c-ip&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cs-method&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cs(Host)&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cs-uri-stem&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;sc-status&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cs(Referer)&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cs(User-Agent)&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cs-uri-query&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cs(Cookie)&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x-edge-result-type&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x-edge-request-id&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x-host-header&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cs-protocol&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cs-bytes&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;time-taken&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x-forwarded-for&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ssl-protocol&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ssl-cipher&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x-edge-response-result-type&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cs-protocol-version&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;fle-status&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;fle-encrypted-fields&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;c-port&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;time-to-first-byte&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x-edge-detailed-result-type&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;sc-content-type&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;sc-content-len&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;sc-range-start&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;sc-range-end&amp;#x27;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;process&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Path&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { (zcat &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;-split&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n&amp;quot;&lt;/span&gt; } | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-Csv&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Delimiter&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`t&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Header&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$header&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;ForEach-Object { (zcat $_) -split &amp;quot;`n&amp;quot; }&lt;/code&gt; ここがイケてない。まじで使いにくい。
改行コードずつ &lt;code&gt;Write-Object&lt;/code&gt; するようにしてないから、自分で分割しないといけなくなってしまっている。当時は改行なし JSON ばかり取り扱ってたので、全く気づかなかったのかなと思っている(しらん)。&lt;/p&gt;
&lt;p&gt;↓ こうできたらすごくイイ気がする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$Path&lt;/span&gt; | zcat | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-Csv&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Delimiter&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`t&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Header&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$header&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;breaking change なのもあるしバージョン 1 にするかーとか思っている。後方互換のスイッチ要るかな？とか分割単位を指定できるのが良いのかな？とか考え出すと、やる気が...
ま、 &lt;code&gt;Get-Content&lt;/code&gt; と似た動きにしたいってのがあるので、 &lt;code&gt;-Delimiter&lt;/code&gt; かなー。&lt;/p&gt;
&lt;p&gt;でも、とりあえず数年後し？のセルフ使用レビューを経てツールを改善しよ...という気になったので、自分のために書いたモジュールでもあるし自分が必要な範囲で直そ。使ってる人がおこになったらちょっと考える。&lt;/p&gt;
&lt;p&gt;さっさと直したらいいのだけど、動機づけとしてこの記事をしたためた。
あとはやるだけ... &lt;a href=&quot;https://github.com/krymtkts/Get-GzipContent/issues/3&quot; title=&quot;Add the &lt;code&gt;-Delimiter&lt;/code&gt; option like &lt;code&gt;Get-Content&lt;/code&gt;. · Issue #3 · krymtkts/Get-GzipContent&quot;&gt;Add the &lt;code&gt;-Delimiter&lt;/code&gt; option like &lt;code&gt;Get-Content&lt;/code&gt;. · Issue #3 · krymtkts/Get-GzipContent&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 06 Aug 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-07-30-practice-build-aws-tools-for-powrshell.html</guid><link>https://krymtkts.github.io/posts/2022-07-30-practice-build-aws-tools-for-powrshell.html</link><title>AWS Tools for PowerShell のビルド素振り</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今年は積極的に？ AWS Tools for PowerShell を使ってることもあって、また Issue 書くことあるかなー、なんなら PR 書いて貢献した方がいいよなと考えるに至り、 &lt;a href=&quot;https://github.com/aws/aws-tools-for-powershell&quot; title=&quot;aws/aws-tools-for-powershell&quot;&gt;aws/aws-tools-for-powershell&lt;/a&gt; のビルドを素振りしてみた。
残念ながら、 contribution 関連でビルドの方法がレクチュアされてる文書とかなかったので、手探りでやってる。&lt;/p&gt;
&lt;p&gt;まず、サービス毎の膨大なプロジェクトがあるし、試しに単体のプロジェクトをビルドしたかったのだけど、関連付く DLL が無くてビルドできなかった。 &lt;code&gt;Amazon.Runtime&lt;/code&gt; とかいうやつ？ この repo 内のどれかのプロジェクトでビルドされるんだろうけど。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;buildtools/&lt;/code&gt; 配下を見ると、どうも CI が CodeBuild らしい(当然のごとく)。この &lt;code&gt;buildtools/ci.buildspec.yml&lt;/code&gt; の中に記載されている全体のビルドで使ってるプロジェクトなら上手くいきそうな雰囲気がしたので、これでフルビルドを試した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet &lt;span class=&quot;hljs-literal&quot;&gt;--version&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 6.0.302&lt;/span&gt;&lt;br /&gt;dotnet build .\buildtools\build.proj&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# めちゃくちゃ大量のビルドログが出力される...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ところがこのフルビルドしだしたらクッソ重い...ビルドが終わらない。
わたしの Razer blade stealth 2017 モデルだと CPU 使用率が天井に貼り付いて、過去にない位にヒートアップしてて心配な気持ちにさせてくれた。&lt;/p&gt;
&lt;p&gt;結果、 41 分かかってなんとかビルドに成功した。&lt;/p&gt;
&lt;p&gt;で、出力結果を見たら改行コードが変わってしまったみたいでエグい差分が発生してしまった。
元コードは全部 &lt;code&gt;LF&lt;/code&gt; なのだけど、 Windows でのビルドによって &lt;code&gt;CRLF&lt;/code&gt; になってしまったみたい。CodeBuild では .NET Core 3.1 でビルドしてるから .NET の関連ツールを使ってても &lt;code&gt;LF&lt;/code&gt; になるんやろが、こちとら Windows 。
どこで変わったか調査して再発を防ぎたいけど、別の機会にする。&lt;/p&gt;
&lt;p&gt;これで基盤的な DLL は生成されたであろうし、サービス個別のプロジェクトのビルドを試すと、うまくいった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;dotnet build .\modules\AWSPowerShell\Cmdlets\Lambda\AWS.Tools.Lambda.csproj&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ...中略...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Build succeeded.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     0 Warning(s)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     0 Error(s)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Time Elapsed 00:00:01.81&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;テストは PowerShell で Cmdlet に対して行う Pester のやつがあるのみで、かつこれらの内容を見てると当然のごとく AWS リソースがある前提。なので、多分個人では金がかかってできないやつ。デプロイ用の CFn とかもないし。
PR のワークフローで対処してんのかなー。&lt;/p&gt;
&lt;p&gt;想定以上に時間がかかったけど、とりあえずなんか修正したいときに手元でビルドするための知識は貯まった。
フルビルドで改行コードが書き換わってしまう、サービス単体のビルドに必要な最小限の依存関係を理解する、辺りが宿題かな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 30 Jul 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-07-23-glue-tagging-cmdlet-not-used-by-anyone-in-the-world.html</guid><link>https://krymtkts.github.io/posts/2022-07-23-glue-tagging-cmdlet-not-used-by-anyone-in-the-world.html</link><title>世界中の誰にも使われていない？ Glue のタグ付け Cmdlet</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;現職にて AWS のコストを可視化すべく、既存の AWS リソースにひたすらコスト配分タグを付与していく作業をしている(勝手に)。
Cost Explorer を眺めてコストのかかり具合を見るのは、 AWS の醍醐味というか楽しみだと思ってるのだけど、あんまり共感を得られたことがない。&lt;/p&gt;
&lt;p&gt;タグ付けには&lt;a href=&quot;https://docs.aws.amazon.com/ARG/latest/userguide/tag-editor.html&quot; title=&quot;タグエディタ&quot;&gt;タグエディタ&lt;/a&gt;を使ってしまっても良いのだけど、折角なので、何を実行したかを形に残せしたい。
そこで &lt;a href=&quot;https://aws.amazon.com/powershell/&quot; title=&quot;AWS Tools for PowerShell&quot;&gt;AWS Tools for PowerShell&lt;/a&gt; でやってる&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;のだけど、とあるサービスだけなんか他のサービスのタグ付け Cmdlet は作法が違ってた。&lt;/p&gt;
&lt;p&gt;Glue 君のことね。 &lt;a href=&quot;https://docs.aws.amazon.com/powershell/latest/reference/items/Add-GLUEResourceTag.html&quot; title=&quot;Glue: Add-GLUEResourceTag Cmdlet | AWS Tools for PowerShell&quot;&gt;Glue: Add-GLUEResourceTag Cmdlet | AWS Tools for PowerShell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この御方なんか知らんけど &lt;code&gt;Tag[]&lt;/code&gt; じゃなくて &lt;code&gt;hashtable&lt;/code&gt; を受けつける。コレまた当然のごとく Reference にはサンプルコード載ってないので、念のためググるかーと思いググったところ...&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2022-07-23-capture/aws-tools-for-pwsh.png&quot; title=&quot;9 件しかヒットしない Add-GLUEResourceTag&quot; alt=&quot;9 件しかヒットしない Add-GLUEResourceTag&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;9 件しかヒットしなかった(2022-07-22 時点)。マジで？
世界中で誰も使ってないのか、はたまたショボ過ぎて誰も記事にしないのか。&lt;/p&gt;
&lt;p&gt;因みに使い方には困ることもなく、実行した結果も期待通り、ちゃんとタグが付いてた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$AccountId&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-STSCallerIdentity&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; Account&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$Region&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-DefaultAWSRegion&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; Region&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$Tag&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;service&amp;#x27;&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;my-service&amp;#x27;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;stage&amp;#x27;&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;dev&amp;#x27;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cost&amp;#x27;&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;my-service-dev&amp;#x27;&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-GLUECrawlerList&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# Glue Crawler の ARN が `Get-GLUECrawler` から持ってこれなくて、みすぼらしく手で組んでる。&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Add-GLUEResourceTag&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ResourceArn&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;arn:aws:glue:&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{Region}:&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{AccountId}:crawler/&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name)&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-TagsToAdd&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Tag&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/jp/about-aws/whats-new/2019/03/aws-glue-now-supports-resource-tagging/&quot; title=&quot;AWS Glue でリソースタグがサポートされて 3 年ばかり経ってる&quot;&gt;AWS Glue でリソースタグがサポートされて 3 年ばかり経ってる&lt;/a&gt;けどみんな使ってないのかなーとか、他にも使われてない Cmdlet があるんやろなーと、思いを馳せた。&lt;/p&gt;
&lt;p&gt;AWS CLI の方はというと &lt;code&gt;&amp;quot;aws glue tag-resource&amp;quot;&lt;/code&gt; で 3 件しかヒットしなかった。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2022-07-23-capture/aws-cli.png&quot; title=&quot;3 件しかヒットしない &quot;aws glue tag-resource&quot;&quot; alt=&quot;3 件しかヒットしない &quot;aws glue tag-resource&quot;&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;しかしながらヒットした記事は実行例が分かるものになってて、こう...なんか AWS Tools for PowerShell の人気の無さが際立つなーと感じた。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;他を見る&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;雑だが、 AWS Tools for PowerShell のリソースタグ関連の Cmdlet で、タグのパラメータの型が何か調べるスクリプトを書いた。 CRUD 全部の Cmdlet が含まれるのであまり正確ではない。&lt;/p&gt;
&lt;p&gt;わたしは AWS Tools for PowerShell の特定のモジュールしか入れてないから全体はわからんけど、傾向は見られる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# AWS.Tools.* modules must be imported first to get all property information.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; *AWS* | &lt;span class=&quot;hljs-built_in&quot;&gt;Import-Module&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Command&lt;/span&gt; *Tag* | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Source &lt;span class=&quot;hljs-operator&quot;&gt;-Like&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;*aws*&amp;#x27;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;pscustomobject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        Name = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name&lt;br /&gt;        TagParameterType = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Parameters.Values | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Name &lt;span class=&quot;hljs-operator&quot;&gt;-Like&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;*tag*&amp;#x27;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; ParameterType&lt;br /&gt;    }&lt;br /&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; TagParameterType &lt;span class=&quot;hljs-operator&quot;&gt;-NE&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Null&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Group-Object&lt;/span&gt; TagParameterType&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Count Name&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ----- ----&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#    31 System.String[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     8 Amazon.IdentityManagement.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     4 System.Collections.Hashtable&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     3 {System.String[], System.String[]}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     3 Amazon.CodeDeploy.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     3 System.String&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     2 Amazon.OpenSearchService.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     2 Amazon.AutoScaling.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     2 Amazon.EC2.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     2 Amazon.S3.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     2 Amazon.Redshift.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     2 Amazon.CertificateManager.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.ECS.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.CloudWatch.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.SimpleNotificationService.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.StepFunctions.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.SecretsManager.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.ECR.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.RDS.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.KeyManagementService.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.KinesisFirehose.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.DynamoDBv2.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.ECR.ImageTagMutability&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.ElasticLoadBalancingV2.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.ElastiCache.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.QuickSight.Model.Tag[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#     1 Amazon.EventBridge.Model.Tag[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;*.Tag[]&lt;/code&gt; が多数派かなーと。 &lt;code&gt;31 System.String[]&lt;/code&gt; これは多分削除とか取得かな。
ただしこいつら &lt;code&gt;*.Tag[]&lt;/code&gt; グループの中でも、 プロパティが &lt;code&gt;Key&lt;/code&gt; だったり &lt;code&gt;TagKey&lt;/code&gt; だったりの派閥があるので、ほんま「みんな違ってみんないい」的状態。&lt;/p&gt;
&lt;p&gt;おわり。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;既存リソースは IaC じゃないので、コマンドでタグ付けするため。 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sat, 23 Jul 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-07-16-aws-cdk-with-fsharp-pt2.html</guid><link>https://krymtkts.github.io/posts/2022-07-16-aws-cdk-with-fsharp-pt2.html</link><title>F# の AWS CDK で EventPattern の記述を無理やり通す</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2022-07-03-aws-cdk-with-fsharp.html&quot; title=&quot;前&quot;&gt;前&lt;/a&gt;に書いた、 F# の AWS CDK で EventRule のパターンが正しいのにエラーとなるやつ。&lt;/p&gt;
&lt;p&gt;こういうのをしたいところ、&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;EventPattern:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;source:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;aws.s3&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;detail-type:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Created&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;detail:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;bucket:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Ref:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;バケツ&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;object:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;prefix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;test/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以下の記述だとエラーになる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;EventPattern &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    EventPattern(&lt;br /&gt;        Source &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;aws.s3&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;],&lt;br /&gt;        DetailType &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Object Created&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;],&lt;br /&gt;        Detail &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;bucket&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;, [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; bucket.BucketName &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;]) ])&lt;br /&gt;                    (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;object&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;key&amp;quot;&lt;/span&gt;, [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;prefix&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;test/&amp;quot;&lt;/span&gt;) ] &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;]) ]) ]&lt;br /&gt;    )
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Unhandled exception. System.ArgumentException: Could not infer JSII type for .NET type &amp;#x27;IDictionary`2&amp;#x27; (Parameter &amp;#x27;type&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この Issue っぽい。
&lt;a href=&quot;https://github.com/aws/jsii/issues/1044&quot; title=&quot;DotNet: Unable to pass interface instance through in a Dictionary&amp;lt;string, object&amp;gt; · Issue #1044 · aws/jsii&quot;&gt;DotNet: Unable to pass interface instance through in a Dictionary&amp;lt;string, object&amp;gt; · Issue #1044 · aws/jsii&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;けど、 &lt;code&gt;IDictionary&amp;lt;string,obj&amp;gt;&lt;/code&gt; は使えてる部分もあって微妙に違うしなー。
より詳細な型がここ(&lt;code&gt;EventPattern&lt;/code&gt;)にはないし、どないすりゃいいんじゃ。&lt;/p&gt;
&lt;p&gt;色々とこねくり回した末に、 CFn のリソースを直接上書きすることで回避できるのがわかった。
&lt;a href=&quot;https://docs.aws.amazon.com/cdk/v2/guide/cfn_layer.html#cfn_layer_raw&quot; title=&quot;Escape hatches - AWS Cloud Development Kit (CDK) v2&quot;&gt;Escape hatches - AWS Cloud Development Kit (CDK) v2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/aws-cdk-fsharp-trial&quot; title=&quot;krymtkts/aws-cdk-fsharp-trial&quot;&gt;krymtkts/aws-cdk-fsharp-trial&lt;/a&gt; からコードを抜粋する。&lt;/p&gt;
&lt;p&gt;配列内に &lt;code&gt;IDictionary&amp;lt;string,obj&amp;gt;&lt;/code&gt; がいると型が解決できなようだったので、空の配列で定義しておき、後でから &lt;code&gt;IDictionary&amp;lt;string,obj&amp;gt;&lt;/code&gt; 要素を差し込む！野蛮過ぎる...&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; rule &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        Rule(&lt;br /&gt;            this,&lt;br /&gt;            &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;bucket-event&amp;quot;&lt;/span&gt;,&lt;br /&gt;            RuleProps(&lt;br /&gt;                RuleName &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;buckt-event&amp;quot;&lt;/span&gt;,&lt;br /&gt;                Description &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;bucket event.&amp;quot;&lt;/span&gt;,&lt;br /&gt;                EventPattern &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                    EventPattern(&lt;br /&gt;                        Source &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;aws.s3&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;],&lt;br /&gt;                        DetailType &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Object Created&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;],&lt;br /&gt;                        &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; cannot write like below because JSII is unable to use `IDictionary&amp;lt;string, object&amp;gt;` inside the array.&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-comment&quot;&gt;// Detail =&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-comment&quot;&gt;//     dict [ (&amp;quot;bucket&amp;quot;, dict [ (&amp;quot;name&amp;quot;, [| bucket.BucketName |]) ])&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;hljs-comment&quot;&gt;//            (&amp;quot;object&amp;quot;, dict [ (&amp;quot;key&amp;quot;, [| dict [ (&amp;quot;prefix&amp;quot;, &amp;quot;test/&amp;quot;) ] |]) ]) ]&lt;/span&gt;&lt;br /&gt;                        Detail &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                            &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;bucket&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;, [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; bucket.BucketName &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;]) ])&lt;br /&gt;                                   (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;object&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;key&amp;quot;&lt;/span&gt;, [&lt;span class=&quot;hljs-operator&quot;&gt;||&lt;/span&gt;]) ]) ]&lt;br /&gt;                    )&lt;br /&gt;            )&lt;br /&gt;        )&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// &lt;span class=&quot;hljs-doctag&quot;&gt;NOTE:&lt;/span&gt; the escape hatch for IDictionary&amp;lt;string, object&amp;gt;` inside the array is raw overrides.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; rule.Node.DefaultChild &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;:?&lt;/span&gt; CfnRule &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; ep &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; ep.AddPropertyOverride(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;EventPattern.detail.object.key.0&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;prefix&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;test/&amp;quot;&lt;/span&gt; ])&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;hljs-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;failwith&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;You passed a wrong variable that is not of type CfnRule!&amp;quot;&lt;/span&gt;&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;cdk synth&lt;/code&gt; でエラーせずに、以下の出力が得られるようになった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;bucketeventF2FCD38A:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;AWS::Events::Rule&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Properties:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;Description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;bucket&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;event.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;EventPattern:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;detail:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;bucket:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Ref:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sourcebucketE323AAE3&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;object:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;prefix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;test/&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;detail-type:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Created&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;source:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;aws.s3&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;Name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;buckt-event&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;State:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ENABLED&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;Targets:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Arn:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Fn::GetAtt:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;samplefunctionAA39FD5B&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Arn&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Id:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Target0&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Metadata:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;aws:cdk:path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;AwsCdkFsharpStack/bucket-event/Resource&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;宣言的に書きたいのにこんなツギハギが要るとか、めちゃくちゃ不便極まりない。&lt;/p&gt;
&lt;p&gt;これは F# のせいじゃないけど、この .NET の不便な側面を許容してまで F# で CDK したいかというと、まずないな...と思った。これに関連して AWS CDK の Issue をちょいちょい調べたが、 .NET や Java で CDK するの辛そうやな..とうっすら思えた。茨の道を突き進むなりの良さがあるのだろうか。&lt;/p&gt;
&lt;p&gt;改めて、仕事は素直に TypeScript を採用して良かったと実感した。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 16 Jul 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-07-09-tips-for-sending-http-requests-pwsh.html</guid><link>https://krymtkts.github.io/posts/2022-07-09-tips-for-sending-http-requests-pwsh.html</link><title>PowerShell で大量の HTTP リクエストを送る場合の Tips</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;大量のアクセスログがほしい事情で、テスト環境に大量のリクエストを送りつける必要があった。&lt;/p&gt;
&lt;p&gt;JMeter とか Gatling 使えば済む話なのだけど、すぐに使い回せるものがなかったし、パパっとやってしまいたかったので PowerShell を使ってみたら、エラーになった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$requests&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;aaa=10&amp;amp;bbb=20&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;aaa=11&amp;amp;bbb=21&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;aaa=12&amp;amp;bbb=22&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$requests&lt;/span&gt; * &lt;span class=&quot;hljs-number&quot;&gt;100000&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parallel&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Method&lt;/span&gt; Get &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://&lt;span class=&quot;hljs-variable&quot;&gt;$using:testDomaain&lt;/span&gt;?&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$jitter&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Random&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Minimum&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Maximum&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;23&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Start-Sleep&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Milliseconds&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;95&lt;/span&gt; + &lt;span class=&quot;hljs-variable&quot;&gt;$jitter&lt;/span&gt;) &lt;span class=&quot;hljs-comment&quot;&gt;# 待ち&lt;/span&gt;&lt;br /&gt;} &lt;span class=&quot;hljs-literal&quot;&gt;-ThrottleLimit&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-Json&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; ./responses.json
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こういうのでタコ殴りにすると...&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Only one usage of each socket address (protocol/network address/port) is normally permitted&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;15000 件を超えた辺りでこうなった。なんだ？ググる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://social.msdn.microsoft.com/Forums/aspnet/en-US/ab5e4f6d-e96a-4bef-bba2-870eda412ea3/systemnetsocketssocketexception-only-one-usage-of-each-socket-address-protocolnetwork?forum=AzureFunctions&quot; title=&quot;System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted&quot;&gt;System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;ポートが枯渇するんだと。 PowerShell の実装を見た訳じゃないけど、 大量に実行された &lt;code&gt;Invoke-WebRequest&lt;/code&gt; で &lt;code&gt;HttpClient&lt;/code&gt; を大量作成したのであろうことは、想像するに易い。&lt;/p&gt;
&lt;p&gt;同じ &lt;code&gt;HttpClient&lt;/code&gt; を使い回せば良いらしいので、そうした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$requests&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;aaa=10&amp;amp;bbb=20&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;aaa=11&amp;amp;bbb=21&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;aaa=12&amp;amp;bbb=22&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$h&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;New-Object&lt;/span&gt; System.Net.Http.HttpClient&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$requests&lt;/span&gt; * &lt;span class=&quot;hljs-number&quot;&gt;100000&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parallel&lt;/span&gt; {&lt;br /&gt;    (&lt;span class=&quot;hljs-variable&quot;&gt;$using:h&lt;/span&gt;).GetAsync(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://&lt;span class=&quot;hljs-variable&quot;&gt;$using:testDomaain&lt;/span&gt;?&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&amp;quot;&lt;/span&gt;).GetAwaiter()&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$jitter&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Random&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Minimum&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Maximum&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;23&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Start-Sleep&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Milliseconds&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;95&lt;/span&gt; + &lt;span class=&quot;hljs-variable&quot;&gt;$jitter&lt;/span&gt;) &lt;span class=&quot;hljs-comment&quot;&gt;# 待ち&lt;/span&gt;&lt;br /&gt;} &lt;span class=&quot;hljs-literal&quot;&gt;-ThrottleLimit&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.GetResult()} | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertTo-Json&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; ./responses.json
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;そんだけ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参照&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Azure/azure-functions-host/issues/1806&quot; title=&quot;Need Official Guidance On using HttpClient in Functions · Issue #1806 · Azure/azure-functions-host&quot;&gt;Need Official Guidance On using HttpClient in Functions · Issue #1806 · Azure/azure-functions-host&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.ironmansoftware.com/powershell-async-method/&quot; title=&quot;Calling Async .NET Methods from PowerShell&quot;&gt;Calling Async .NET Methods from PowerShell&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;</description><pubDate>Sat, 09 Jul 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-07-03-aws-cdk-with-fsharp.html</guid><link>https://krymtkts.github.io/posts/2022-07-03-aws-cdk-with-fsharp.html</link><title>F# で AWS CDK して躓いてる</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;最近仕事で AWS CDK を使ってみたが、非常に良い感触だった。
仕事では TypeScript を採用したが、テンプレートが提供されている言語を見るとなんと F# がいるではないか。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; cdk init &lt;span class=&quot;hljs-literal&quot;&gt;--list&lt;/span&gt;&lt;br /&gt;Available templates:&lt;br /&gt;* app: Template &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; a CDK Application&lt;br /&gt;   └─ cdk init app &lt;span class=&quot;hljs-literal&quot;&gt;--language&lt;/span&gt;=[&lt;span class=&quot;hljs-type&quot;&gt;csharp&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;fsharp&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;go&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;java&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;javascript&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;python&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;typescript&lt;/span&gt;]&lt;br /&gt;* lib: Template &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; a CDK Construct Library&lt;br /&gt;   └─ cdk init lib &lt;span class=&quot;hljs-literal&quot;&gt;--language&lt;/span&gt;=typescript&lt;br /&gt;* sample&lt;span class=&quot;hljs-literal&quot;&gt;-app&lt;/span&gt;: Example CDK Application with some constructs&lt;br /&gt;   └─ cdk init sample&lt;span class=&quot;hljs-literal&quot;&gt;-app&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--language&lt;/span&gt;=[&lt;span class=&quot;hljs-type&quot;&gt;csharp&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;fsharp&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;go&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;java&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;javascript&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;python&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;typescript&lt;/span&gt;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;単に「C# のクラス用意したから継承して使ってや～」的なもので F# 向けに調整されてないだろうが、コレ誰が使うねんという気がしたので、試してみた。&lt;/p&gt;
&lt;p&gt;参考にした前例たち。非常に参考にさせてもらった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://awsmaniac.com/functional-programming-with-aws-cdk/&quot; title=&quot;Functional Programming with AWS CDK | AWS Maniac&quot;&gt;Functional Programming with AWS CDK | AWS Maniac&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://cloudgnosis.org/fsharp/fsharp-for-the-cloud-worker/part5.html&quot; title=&quot;Part 5 - AWS Cloud Development Kit (CDK) — Cloudgnosis collection 0.1 documentation&quot;&gt;Part 5 - AWS Cloud Development Kit (CDK) — Cloudgnosis collection 0.1 documentation&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;まずテンプレからプロジェクトを生成した素の状態で CFn を作成してみる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;cdk init sample&lt;span class=&quot;hljs-literal&quot;&gt;-app&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--language&lt;/span&gt;=fsharp&lt;br /&gt;cdk synth
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ちゃんと CFn をビルドできた。 どんなコードが出るか知りたかったので &lt;code&gt;sample-app&lt;/code&gt; を使ったが、ここで &lt;code&gt;app&lt;/code&gt; テンプレを使うと、利用されない &lt;code&gt;this&lt;/code&gt; が残ってるので警告が出る。でも勿論 CFn をビルドできる。&lt;/p&gt;
&lt;p&gt;記述に関しては TypeScript など他の言語と大差なさそう。ただ予想通り C# との相互運用は前提になってる。
宣言的に記述する箇所については &lt;code&gt;let&lt;/code&gt; バインディングして、 リソースに手続き的に何かすると &lt;code&gt;do&lt;/code&gt; バインディングみたい。&lt;/p&gt;
&lt;p&gt;試しに S3 と Lambda を EventBridge で繋いでみたい。&lt;/p&gt;
&lt;p&gt;F# の CDK では &lt;code&gt;Amazon.CDK&lt;/code&gt; に必要な Construct が全部入りしてるみたい。なので &lt;code&gt;Amazon.CDK.xxx&lt;/code&gt; みたいな感じでポチポチ &lt;code&gt;.&lt;/code&gt; を刻んでいけば、ドキュメントがなくてもそれなりに探せる。&lt;/p&gt;
&lt;p&gt;F# は言語固有モジュールが無いので、ここに例えば Lambda を足すとすると、個別にビルドする感じになる。あれめちゃくちゃ楽で好きなんやけど、 .Net 向けにはない。
プロジェクトを別途足す方向で作るらしい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# テンプレなかったので探してインストール&lt;/span&gt;&lt;br /&gt;dotnet new lambda.Empty&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt; --&lt;span class=&quot;hljs-title&quot;&gt;search&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;dotnet new &lt;span class=&quot;hljs-literal&quot;&gt;--install&lt;/span&gt; Amazon.Lambda.Templates&lt;br /&gt;&lt;br /&gt;dotnet new lambda.S3 &lt;span class=&quot;hljs-literal&quot;&gt;--output&lt;/span&gt; . &lt;span class=&quot;hljs-literal&quot;&gt;--name&lt;/span&gt; api &lt;span class=&quot;hljs-literal&quot;&gt;--language&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;F#&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; src&lt;br /&gt;dotnet sln add api
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;p&gt;stack をザーッと書いてみたが、めちゃくちゃつまづきどころがある。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;open System.Collections&lt;/code&gt; したら &lt;code&gt;Stack&lt;/code&gt; が競合するので注意&lt;/li&gt;&lt;li&gt;&lt;code&gt;MemorySize&lt;/code&gt;に&lt;code&gt;128&lt;/code&gt; を渡してたら Ionide や &lt;code&gt;dotnet build&lt;/code&gt; ではエラー検知できなかったが、 &lt;code&gt;cdk synth&lt;/code&gt; でエラー(めんどくせ)&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MemorySize&lt;/code&gt;を&lt;code&gt;128&lt;/code&gt;から&lt;code&gt;(Some 128.0 |&amp;gt; Option.toNullable)&lt;/code&gt;に&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;必須プロパティがビルドまでわからないのつらい&lt;/li&gt;&lt;li&gt;&lt;code&gt;EventPattern&lt;/code&gt; の &lt;code&gt;IDictionary&amp;lt;string,obj&amp;gt;&lt;/code&gt;を一息で書くのかなりキツイ(まじでめんどい)&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Value&lt;/code&gt; の型が揃わないところは個別に &lt;code&gt;let&lt;/code&gt; してあとで組み合わせたり&lt;/li&gt;&lt;li&gt;&lt;code&gt;dict&lt;/code&gt; に食わせる &lt;code&gt;tuple&lt;/code&gt; はきっちりカッコで囲むと先述の &lt;code&gt;let&lt;/code&gt; が不要になった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;EventPattern&lt;/code&gt; の &lt;code&gt;Detail&lt;/code&gt; が &lt;code&gt;cdk synth&lt;/code&gt; でエラーになる&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Prefix のパターンをやりたいのだけど、 &lt;a href=&quot;https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-prefix-matching&quot; title=&quot;Content filtering in Amazon EventBridge event patterns - Amazon EventBridge&quot;&gt;Content filtering in Amazon EventBridge event patterns - Amazon EventBridge&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;EventPattern:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;source:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;aws.s3&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;detail-type:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Created&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;detail:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;bucket:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Ref:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;バケツ&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;object:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;prefix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;test/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以下の記述だとエラーになる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;EventPattern &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    EventPattern(&lt;br /&gt;        Source &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;aws.s3&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;],&lt;br /&gt;        DetailType &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Object Created&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;],&lt;br /&gt;        Detail &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;bucket&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;, [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; bucket.BucketName &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;]) ])&lt;br /&gt;                    (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;object&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;key&amp;quot;&lt;/span&gt;, [&lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt; [ (&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;prefix&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;test/&amp;quot;&lt;/span&gt;) ] &lt;span class=&quot;hljs-operator&quot;&gt;|&lt;/span&gt;]) ]) ]&lt;br /&gt;    )
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Unhandled exception. System.ArgumentException: Could not infer JSII type for .NET type &amp;#x27;IDictionary`2&amp;#x27; (Parameter &amp;#x27;type&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;dict [ (&amp;quot;prefix&amp;quot;, &amp;quot;test/&amp;quot;) ]&lt;/code&gt; の代わりに文字列を渡してると問題なくなるけど、それってスキーマ違反なんですけど。
この辺 TypeScript は困った記憶ないので、参ったなという感じ。&lt;/p&gt;
&lt;p&gt;この辺の回答が出たら割りと参考になるかもなーと思って見ている。&lt;a href=&quot;https://github.com/aws/aws-cdk/discussions/20894&quot; title=&quot;How to set detail on an eventpattern in java · Discussion #20894 · aws/aws-cdk&quot;&gt;How to set detail on an eventpattern in java · Discussion #20894 · aws/aws-cdk&lt;/a&gt;
単純に F# 力の低さに起因して記述できないだけだといいけど。&lt;/p&gt;
&lt;p&gt;もうちょっと深掘したいが今週はここまで。
とりあえず repo は作った。 &lt;a href=&quot;https://github.com/krymtkts/aws-cdk-fsharp-trial&quot; title=&quot;krymtkts/aws-cdk-fsharp-trial&quot;&gt;krymtkts/aws-cdk-fsharp-trial&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 03 Jul 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-06-26-writing-cmdlet-in-fsharp-pt3.html</guid><link>https://krymtkts.github.io/posts/2022-06-26-writing-cmdlet-in-fsharp-pt3.html</link><title>F#でコマンドレットを書いてる pt.3</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.powershell?view=powershellsdk-7.0.0&quot; title=&quot;PowerShell Class&quot;&gt;PowerShell Class&lt;/a&gt; を使って、現在の runspace を引き継がせるとかはちょっとわかりまして、 (F# というか .NET)の世界で PowerShell の表示文字列を取り回すには PowerShell Class を使い最後に &lt;code&gt;Out-String&lt;/code&gt; した結果を取り回すのが典型っぽいのはわかった。&lt;/p&gt;
&lt;p&gt;ただやっぱり PowerShell の力を借りない方法を諦めきれずにいた。
また今後プロパティ指定での検索を実装していったときに、指定したプロパティはなんか色付けするとかしようとしたらこっちの方が絶対やりやすいだろうというのを感じてたので、&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting&quot; title=&quot;Composite formatting&quot;&gt;Composite formatting&lt;/a&gt; を使ってどうにかできないものか考えていた。&lt;/p&gt;
&lt;p&gt;が、結論としては PowerShell の力を借りるのが良いのでは～...というところまできた。&lt;/p&gt;
&lt;p&gt;結局のところ &lt;code&gt;format.ps1xml&lt;/code&gt; に従って PowerShell で表示が制御されるので、 F# の中で &lt;code&gt;PSObject.Properties&lt;/code&gt; を見たとてどいつを優先表示したらいいかわからん。またこの &lt;code&gt;Properties&lt;/code&gt; から表示するテーブルを作るのは &lt;code&gt;hashtable&lt;/code&gt; や &lt;code&gt;array&lt;/code&gt; が引数の場合には適応したくないし、となると型でパターンマッチして～となる。
考えるとここにこだわるのはもっとプロパティでの絞り込みとかの他の機能を実装したあとでいいかなーという気になってきた。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;format.ps1xml&lt;/code&gt; もそうだけど PowerShell 内部実装に対する基礎知識(&lt;code&gt;PSPropertyInfo&lt;/code&gt;とかまじで情報ない)がやっぱ圧倒的に不足してるから、蓄積されるまでは黙って PowerShell に従うが良いかと考えを改めた。
であれば、もう PowerShell Class を使う方向に倒して、検索中のプロパティを &lt;code&gt;Format-Table&lt;/code&gt; の &lt;code&gt;-Properties&lt;/code&gt; で表示するようにしようかな、という選択肢もありかなと。&lt;/p&gt;
&lt;p&gt;いったんこの形で検索中の表示を進めれば、他に組み込んでおきたい機能、例えばプロパティ指定の検索とかに取りかかれる。
週末の 1,2 時間が主な開発時間なので、亀な進捗の中でも実装を進められる判断が必要かなー。それもまた一興。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 26 Jun 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-06-19-belatedly-parallel-foreach-object.html</guid><link>https://krymtkts.github.io/posts/2022-06-19-belatedly-parallel-foreach-object.html</link><title>今更 ForEach-Object -Parallel</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今更だが、直列だと長時間かかる処理を分散させるために &lt;code&gt;ForEach-Object -Parallel&lt;/code&gt; を使う必要があった。
困ったというほどでもないけど、真面目に使ったことなかったので、今回学んだ気をつけポイントをまとめる。
(毎度の如く PowerShell でそれをやる必要は全くなかったが、ぱっと手を動かしたくてついやってしまった)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参照&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/powershell/powershell-foreach-object-parallel-feature/&quot; title=&quot;PowerShell ForEach-Object Parallel Feature - PowerShell Team&quot;&gt;PowerShell ForEach-Object Parallel Feature - PowerShell Team&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/psworkflow/about/about_foreach-parallel?view=powershell-5.1&quot; title=&quot;about Foreach-Parallel - PowerShell | Microsoft Docs&quot;&gt;about Foreach-Parallel - PowerShell | Microsoft Docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/61273189/how-to-pass-a-custom-function-inside-a-foreach-object-parallel/61273544#61273544&quot; title=&quot;powershell - How to pass a custom function inside a ForEach-Object -Parallel - Stack Overflow&quot;&gt;powershell - How to pass a custom function inside a ForEach-Object -Parallel - Stack Overflow&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;並列数の制御&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;-Parallel&lt;/code&gt; はとにかく遅い。異なる runspace が作成されそこで実行されるからだ。
なのでとにかく計算時間がかかるんやというような処理だけ渡すようにした方がいい。&lt;/p&gt;
&lt;p&gt;今回は、あらかじめ &lt;code&gt;ThrottleLimit&lt;/code&gt; と同じ数の &lt;code&gt;InputObject&lt;/code&gt; に調整して重いコマンドを打つ方針を使った。
消えては立ち上がり x2 するような書き方をした方ではやはり runspace 作成のオーバーヘッドが、処理時間という形で顕著に見られた。
スクリプトブロックが消えては立ち上がり x2 しないように、スクリプトブロック内で重い 1 処理を実行する方が良かった(AWS のリソースを一括操作するやつだからできたことだけど)。&lt;/p&gt;
&lt;p&gt;1 ヵ月分のデータを加工する必要があって、対象日毎に 1 処理にすることができたので、それを約 30 並列でやった。
イメージ ↓&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$begin&lt;/span&gt; = (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Day&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Hour&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Minute&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Second&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Millisecond&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$end&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$begin&lt;/span&gt;.AddMonths(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;).AddDays(&lt;span class=&quot;hljs-literal&quot;&gt;-1&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$dateRange&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;()&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$begin&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-le&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$end&lt;/span&gt;) {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$dateRange&lt;/span&gt; += &lt;span class=&quot;hljs-variable&quot;&gt;$begin&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$begin&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$begin&lt;/span&gt;.AddDays(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$dateRange&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ThrottleLimit&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$dateRange&lt;/span&gt;.Length &lt;span class=&quot;hljs-literal&quot;&gt;-Parallel&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# 長時間かかる処理.&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;スクリプトブロック外のリソース参照&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;$using:&lt;/code&gt; 修飾子をつけたら変数を参照できる。
ただしスクリプトブロックや関数には使えない。&lt;/p&gt;
&lt;p&gt;関数をどうしても使いまわしたいときは、文字列に変換した上で取り込む技もある。 &lt;a href=&quot;https://stackoverflow.com/questions/61273189/how-to-pass-a-custom-function-inside-a-foreach-object-parallel/61273544#61273544&quot; title=&quot;powershell - How to pass a custom function inside a ForEach-Object -Parallel - Stack Overflow&quot;&gt;powershell - How to pass a custom function inside a ForEach-Object -Parallel - Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;が、スクリプトブロック内でしか使わないのであればその中に関数を定義してしまったほうが楽か。
&lt;a href=&quot;https://devblogs.microsoft.com/powershell/powershell-foreach-object-parallel-feature/#comment-171&quot; title=&quot;最もクリーンな方法でオススメらしいし&quot;&gt;最もクリーンな方法でオススメらしいし&lt;/a&gt;、実際にそうした。&lt;/p&gt;
&lt;p&gt;(&lt;code&gt;Import-Module&lt;/code&gt; すればいいのだけどいちいちモジュールを作らないこともあろう)&lt;/p&gt;
&lt;p&gt;技を使うとこうなる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Get-Identity&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;,&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;Position&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;ValueFromPipeline&lt;/span&gt;&lt;br /&gt;        )]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;PSObject&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Value&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;process&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Value&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$funcDef&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{function:&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Identity&lt;/span&gt;}.ToString()&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Test-UsingFuncInParallel&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; ()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parallel&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;{function:&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Identity&lt;/span&gt;} = &lt;span class=&quot;hljs-variable&quot;&gt;$using:funcDef&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Identity&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt;&lt;br /&gt;    } &lt;span class=&quot;hljs-literal&quot;&gt;-ThrottleLimit&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;技を使わない版。当然ながらスクリプトブロックは間延びする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Test-UsingFuncInParallel&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; ()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parallel&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Get-Identity&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;                [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;,&lt;br /&gt;                    &lt;span class=&quot;hljs-type&quot;&gt;Position&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,&lt;br /&gt;                    &lt;span class=&quot;hljs-type&quot;&gt;ValueFromPipeline&lt;/span&gt;&lt;br /&gt;                )]&lt;br /&gt;                [&lt;span class=&quot;hljs-type&quot;&gt;PSObject&lt;/span&gt;]&lt;br /&gt;                &lt;span class=&quot;hljs-variable&quot;&gt;$Value&lt;/span&gt;&lt;br /&gt;            )&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;process&lt;/span&gt; {&lt;br /&gt;                &lt;span class=&quot;hljs-variable&quot;&gt;$Value&lt;/span&gt;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Identity&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt;&lt;br /&gt;    } &lt;span class=&quot;hljs-literal&quot;&gt;-ThrottleLimit&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使う関数が多いとスクリプトブロックも伸びがちなので、使い分けを検討した方が良かろう。
用途次第だが、わたしの場合は先述の通り並列数 MAX ピッタリに調整した &lt;code&gt;InputObject&lt;/code&gt; を使て長時間の処理を流すだろうから、 runspace の作成のコストはそれほど気にならない。スクリプトブロックの中がごちゃごちゃしないことのメリットがあるかも知れん。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;あと微妙にハマったのが &lt;code&gt;$PSCmdlet&lt;/code&gt; の参照。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$using:&lt;/code&gt; つけ忘れてると単に &lt;code&gt;$null&lt;/code&gt; なだけなのでエラーメッセージ見てもピンときにくい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Line |&lt;br /&gt;   2 |          if ($PSCmdlet.ShouldProcess($_, &amp;#x27;Write-Host&amp;#x27;)) {&lt;br /&gt;     |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;     | You cannot call a method on a null-valued expression.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;さらに関数の呼び出し時はカッコで囲む必要がある。カッコがないと Parse Error。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt; function Test-ShouldProcessInParallel {&lt;br /&gt;     [CmdletBinding(SupportsShouldProcess)]&lt;br /&gt;     param ()&lt;br /&gt;&lt;br /&gt;     1..30 | ForEach-Object -Parallel {&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        if ($using:PSCmdlet.ShouldProcess($_, &amp;#x27;Write-Host&amp;#x27;)) {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        if (($using:PSCmdlet).ShouldProcess($_, &amp;#x27;Write-Host&amp;#x27;)) {&lt;/span&gt;&lt;br /&gt;             $_ | Write-Host&lt;br /&gt;         }&lt;br /&gt;     } -ThrottleLimit 30&lt;br /&gt; }
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;ParserError:&lt;br /&gt;Line |&lt;br /&gt;   6 |          if ($using:PSCmdlet.ShouldProcess($_, &amp;#x27;Write-Host&amp;#x27;)) {&lt;br /&gt;     |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;     | Expression is not allowed in a Using expression.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あとなんか見慣れぬエラーになる時があったが忘れた。再現できたら追記したい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 19 Jun 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-06-12-writing-cmdlet-in-fsharp-pt2.html</guid><link>https://krymtkts.github.io/posts/2022-06-12-writing-cmdlet-in-fsharp-pt2.html</link><title>F#でコマンドレットを書いてる pt.2</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt; の話。&lt;/p&gt;
&lt;p&gt;平日仕事の方ばっかりやってるので亀な進捗だ。
ひとまず&lt;a href=&quot;/posts/2022-06-05-whitespace-comparison-in-pwsh.html&quot; title=&quot;&lt;code&gt;System.Management.Automation.WildcardPattern&lt;/code&gt; の使い方がわかった&quot;&gt;&lt;code&gt;System.Management.Automation.WildcardPattern&lt;/code&gt; の使い方がわかった&lt;/a&gt; のを皮切りに、 &lt;code&gt;-like&lt;/code&gt;,&lt;code&gt;-match&lt;/code&gt;,&lt;code&gt;-eq&lt;/code&gt; あたりのフィルタを実装した。&lt;/p&gt;
&lt;p&gt;あとプロパティを指定しての絞り込みとかを実装してないが、これは &lt;code&gt;PSObject&lt;/code&gt; から目当てのプロパティを拾ってマッチするだけなので、多分むずくないだろう。&lt;/p&gt;
&lt;p&gt;いま一番頭を悩ませている課題は、絞り込みを確定するまでの間印字する内容についてだ。
やはり PowerShell でインタラクティブなフィルタリングをするのであれば、印字する内容も PowerShell の &lt;code&gt;Format-Table&lt;/code&gt; ライクな印字をしたい。
例えば &lt;a href=&quot;https://github.com/devblackops/Terminal-Icons&quot; title=&quot;Terminal-Icons&quot;&gt;Terminal-Icons&lt;/a&gt; を使っていたら、カラフルな &lt;code&gt;Get-ChildItem&lt;/code&gt; の結果のママ絞り込みしたい。ただそのやり方がさっぱり分からない。&lt;/p&gt;
&lt;p&gt;全くわからんなりに、とりあえず F# 内から PowerShell を実行する練習として、 &lt;code&gt;PowerShell.Create&lt;/code&gt; でコマンドレットを動かしてみただけというコードは動かしてみた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;Cmdlet(VerbsDiagnostic.Test, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Pocof&amp;quot;&lt;/span&gt;)&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;[&amp;lt;OutputType(typeof&amp;lt;PSObject&amp;gt;)&amp;gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;TestPocofCommand&lt;/span&gt;() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;inherit&lt;/span&gt; PSCmdlet()&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; __.EndProcessing() &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        __.WriteObject&lt;br /&gt;        &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;|&lt;/span&gt; PowerShell&lt;br /&gt;            .Create()&lt;br /&gt;            .AddCommand(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Get-ChildItem&amp;quot;&lt;/span&gt;)&lt;br /&gt;            .AddCommand(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Format-Table&amp;quot;&lt;/span&gt;)&lt;br /&gt;            .Invoke() &lt;span class=&quot;hljs-comment&quot;&gt;// まじで意味ない&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このへんまだ調査不足のため、以下に記すのはメモ書きレベル。つか &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.powershell?view=powershellsdk-7.0.0&quot; title=&quot;PowerShell Class&quot;&gt;PowerShell Class&lt;/a&gt; だけでなく PowerShell SDK のドキュメントむずくない？
全体的に読んでてもよくわからん(愚痴)。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;これをやろうとしたら &lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_format.ps1xml?view=powershell-7.2&quot; title=&quot;Format.ps1xml&quot;&gt;Format.ps1xml&lt;/a&gt; が反映された状態の文字列を F# 内で作らないといけないが、 F# 内で &lt;code&gt;PowerShell.Create&lt;/code&gt; したとてセッションの引き継ぎができるのかがわからん&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.powershell.create?view=powershellsdk-7.0.0#system-management-automation-powershell-create(system-management-automation-runspacemode)&quot; title=&quot;PowerShell.Create&quot;&gt;PowerShell.Create&lt;/a&gt; あたりでどうにかなりそうに見えるけど試せてない&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;PowerShell SDK の中には &lt;code&gt;FormatTableCommand&lt;/code&gt; という名のまさに &lt;code&gt;Format-Table&lt;/code&gt; そのものがあるが、こいつの Input に &lt;code&gt;SelectPocofCommand&lt;/code&gt; からデータを食わす方法がわからん&lt;ul&gt;
&lt;li&gt;これも多分実行時に引数で渡せるようにみえるけど(略) &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.powershell.invoke?view=powershellsdk-7.0.0#system-management-automation-powershell-invoke-1(system-collections-ienumerable)&quot; title=&quot;PowerShell.Invoke Method&quot;&gt;PowerShell.Invoke Method&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;これらが想定通りで期待の Output が得られたとて、正直な気持ちは F# 内で PowerShell の実行エンジン作ってまでやりたくないなー(なんか重そう)、もっと簡単に &lt;code&gt;Format-Table&lt;/code&gt; の出力を得る方法はないんかいな、というお気持ち&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;System.Management.Automation.WildcardPattern&lt;/code&gt; みたいな外部から見える場所に PowerShell 内部で使ってる機能がいい感じに提供されてたらいいのだけど、そんな感じではなさそう。&lt;/p&gt;
&lt;p&gt;見た目に動きのある機能実装ができたときの嬉しさはやっぱひとしおなので、取り組みたい、けどまだ情報＆能力的に不足してるなーというところ。何やるにしても手を動かせるまでに異様に時間がかかる。
ひとまずは調査継続しつつ他の課題潰していくか。&lt;/p&gt;
&lt;p&gt;ほんま仕事とは一切接点無くて趣味プロとして最高のテーマになってる。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 12 Jun 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-06-05-whitespace-comparison-in-pwsh.html</guid><link>https://krymtkts.github.io/posts/2022-06-05-whitespace-comparison-in-pwsh.html</link><title>PoweShell で半角スペース(U+0020) -eq 全角スペース(U+3000) が True となる</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;転職して 3 ヶ月目を迎えた。
入社以降は何の因果か CRM の導入をやることになり、既存データ(スプレッドシート)の以降のために PowerShell を駆使している。&lt;/p&gt;
&lt;p&gt;そんな中で今まで知らなかった PowerShell の表情をいくつも知ることができ(例えばコレとか)、なんやかんやで楽しんでいる。&lt;/p&gt;
&lt;p&gt;その中で度肝を抜かれたのが、今日のテーマ。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#39; &amp;#39;&lt;/code&gt;(U+0020) &lt;code&gt;-eq&lt;/code&gt; &lt;code&gt;&amp;#39; &amp;#39;&lt;/code&gt;(U+3000) が &lt;code&gt;True&lt;/code&gt; となる。&lt;/p&gt;
&lt;p&gt;PowerShell 7 と Windows PowerShell 5.1 で試した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Name                           Value&lt;br /&gt;----                           -----&lt;br /&gt;PSVersion                      7.2.4&lt;br /&gt;PSEdition                      Core&lt;br /&gt;GitCommitId                    7.2.4&lt;br /&gt;OS                             Microsoft Windows 10.0.22000&lt;br /&gt;Platform                       Win32NT&lt;br /&gt;PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}&lt;br /&gt;PSRemotingProtocolVersion      2.3&lt;br /&gt;SerializationVersion           1.1.0.1&lt;br /&gt;WSManStackVersion              3.0
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Name                           Value&lt;br /&gt;----                           -----&lt;br /&gt;PSVersion                      5.1.22000.653&lt;br /&gt;PSEdition                      Desktop&lt;br /&gt;PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}&lt;br /&gt;BuildVersion                   10.0.22000.653&lt;br /&gt;CLRVersion                     4.0.30319.42000&lt;br /&gt;WSManStackVersion              3.0&lt;br /&gt;PSRemotingProtocolVersion      2.3&lt;br /&gt;SerializationVersion           1.1.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;7 だと &lt;code&gt;True&lt;/code&gt; 、 5.1 だと &lt;code&gt;False&lt;/code&gt; だ。
&lt;code&gt;-ceq&lt;/code&gt; だと 7 でも &lt;code&gt;False&lt;/code&gt; を返すので &lt;code&gt;-ieq&lt;/code&gt; の判定が違うのだけど、 PowerShell Core からこうなんだろうか？
PowerShell の実装を追ってみたが、追いきれなかった。 めちゃくちゃ&lt;a href=&quot;https://github.com/PowerShell/PowerShell/blob/87f621eb1fa94f1d114b0cc4a5fb7aab5d3133c9/src/System.Management.Automation/engine/parser/Compiler.cs#L5804%E3%83%BCL5806&quot; title=&quot;ココ&quot;&gt;ココ&lt;/a&gt;っぽいのだけど、 LINQ に由来するクラス &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.linq.expressions.dynamicexpression.dynamic?view=net-6.0#system-linq-expressions-dynamicexpression-dynamic(system-runtime-compilerservices-callsitebinder-system-type-system-linq-expressions-expression-system-linq-expressions-expression)&quot; title=&quot;DynamicExpression&quot;&gt;DynamicExpression&lt;/a&gt; とかの知識がないのでまだ調査中。&lt;/p&gt;
&lt;p&gt;どう説明したらいいか悩むのが、いくつか試してみていてわかってきたのは、 &lt;code&gt;String&lt;/code&gt; の &lt;code&gt;-ieq&lt;/code&gt; でこの事象が見られること。 &lt;code&gt;Char&lt;/code&gt; だと起こらない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27; &amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-ieq&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;　&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# True&lt;/span&gt;&lt;br /&gt;([&lt;span class=&quot;hljs-built_in&quot;&gt;char&lt;/span&gt;][&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x20&amp;#x27;&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;-ieq&lt;/span&gt; ([&lt;span class=&quot;hljs-built_in&quot;&gt;char&lt;/span&gt;][&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x3000&amp;#x27;&lt;/span&gt;)  &lt;span class=&quot;hljs-comment&quot;&gt;# Char だと False&lt;/span&gt;&lt;br /&gt;([&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;][&lt;span class=&quot;hljs-built_in&quot;&gt;char&lt;/span&gt;][&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x20&amp;#x27;&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;-ieq&lt;/span&gt; ([&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;][&lt;span class=&quot;hljs-built_in&quot;&gt;char&lt;/span&gt;][&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x3000&amp;#x27;&lt;/span&gt;) &lt;span class=&quot;hljs-comment&quot;&gt;# String だと True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;そしてもう 1 つ、 Unicode で General category が Separator, space と定義されているものが等値と判定されること。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Whitespace_character#Unicode&quot; title=&quot;Whitespace character - Wikipedia&quot;&gt;Whitespace character - Wikipedia&lt;/a&gt; の表が非常にわかりやすい。ここから以下のテストコードを作成し、先述の事実を導いた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x0009&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x000A&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x000B&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x000C&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x000D&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x0020&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x0085&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x00A0&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x1680&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2000&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2001&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2002&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2003&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2004&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2005&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2006&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2007&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2008&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2009&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x200A&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2028&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2029&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x202F&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x205F&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x3000&amp;#x27;&lt;/span&gt; | % { [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;    CodePoint = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;br /&gt;    isEquals = ([&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;][&lt;span class=&quot;hljs-built_in&quot;&gt;char&lt;/span&gt;][&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27; &amp;#x27;&lt;/span&gt;&lt;br /&gt;}}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;CodePoint isEquals&lt;br /&gt;--------- --------&lt;br /&gt;0x0009       False&lt;br /&gt;0x000A       False&lt;br /&gt;0x000B       False&lt;br /&gt;0x000C       False&lt;br /&gt;0x000D       False&lt;br /&gt;0x0020        True&lt;br /&gt;0x0085       False&lt;br /&gt;0x00A0        True&lt;br /&gt;0x1680        True&lt;br /&gt;0x2000        True&lt;br /&gt;0x2001        True&lt;br /&gt;0x2002        True&lt;br /&gt;0x2003        True&lt;br /&gt;0x2004        True&lt;br /&gt;0x2005        True&lt;br /&gt;0x2006        True&lt;br /&gt;0x2007        True&lt;br /&gt;0x2008        True&lt;br /&gt;0x2009        True&lt;br /&gt;0x200A        True&lt;br /&gt;0x2028       False&lt;br /&gt;0x2029       False&lt;br /&gt;0x202F        True&lt;br /&gt;0x205F        True&lt;br /&gt;0x3000        True
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あーココまで来ると、意図的な挙動 ≒ 仕様というのに当たりがつく。
なので .NET の String クラスの挙動を見てみると...&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27; &amp;#x27;&lt;/span&gt;.Equals(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;　&amp;#x27;&lt;/span&gt;, [&lt;span class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;Comparison&lt;/span&gt;]::CurrentCultureIgnoreCase) &lt;span class=&quot;hljs-comment&quot;&gt;# True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x0009&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x000A&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x000B&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x000C&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x000D&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x0020&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x0085&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x00A0&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x1680&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2000&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2001&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2002&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2003&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2004&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2005&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2006&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2007&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2008&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2009&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x200A&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2028&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x2029&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x202F&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x205F&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0x3000&amp;#x27;&lt;/span&gt; | % { [&lt;span class=&quot;hljs-type&quot;&gt;PSCustomObject&lt;/span&gt;]&lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;&amp;gt;     CodePoint = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;&lt;br /&gt;&amp;gt;     isEquals = ([&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;][&lt;span class=&quot;hljs-built_in&quot;&gt;char&lt;/span&gt;][&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;).Equals(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27; &amp;#x27;&lt;/span&gt;, [&lt;span class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;Comparison&lt;/span&gt;]::CurrentCultureIgnoreCase)&lt;br /&gt;&amp;gt; }}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;CodePoint isEquals&lt;br /&gt;--------- --------&lt;br /&gt;0x0009       False&lt;br /&gt;0x000A       False&lt;br /&gt;0x000B       False&lt;br /&gt;0x000C       False&lt;br /&gt;0x000D       False&lt;br /&gt;0x0020        True&lt;br /&gt;0x0085       False&lt;br /&gt;0x00A0        True&lt;br /&gt;0x1680        True&lt;br /&gt;0x2000        True&lt;br /&gt;0x2001        True&lt;br /&gt;0x2002        True&lt;br /&gt;0x2003        True&lt;br /&gt;0x2004        True&lt;br /&gt;0x2005        True&lt;br /&gt;0x2006        True&lt;br /&gt;0x2007        True&lt;br /&gt;0x2008        True&lt;br /&gt;0x2009        True&lt;br /&gt;0x200A        True&lt;br /&gt;0x2028       False&lt;br /&gt;0x2029       False&lt;br /&gt;0x202F        True&lt;br /&gt;0x205F        True&lt;br /&gt;0x3000        True
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;StringComparison.InvariantCultureIgnoreCase&lt;/code&gt; は同じ結果。 &lt;code&gt;StringComparison.OrdinalIgnoreCase&lt;/code&gt; は違う結果となった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.stringcomparison?view=net-6.0&quot; title=&quot;StringComparison Enum (System) | Microsoft Docs&quot;&gt;StringComparison Enum (System) | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;全然知らんかった...また世の中に恥を晒してしまったと共に、1 つ学んだわ。
まだ確かな情報源を得たわけじゃないけど、きっと世の中のﾄﾞｯﾄﾈｯﾀｰにとっては常識なんやろなあ。
手始めに ↓ コレちゃんと読むようにしよう...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings&quot; title=&quot;Best Practices for Comparing Strings in .NET | Microsoft Docs&quot;&gt;Best Practices for Comparing Strings in .NET | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;ちなみにこの調査において、 &lt;code&gt;-like&lt;/code&gt; には &lt;code&gt;System.Management.Automation.WildcardPattern&lt;/code&gt; が使われていて、しかも公開されてるクラスというのがわかった。こんなのがあるの知らなかったわ。&lt;/p&gt;
&lt;p&gt;そのまま &lt;a href=&quot;https://github.com/krymtkts/pocof#readme&quot; title=&quot;pocof&quot;&gt;pocof&lt;/a&gt; のワイルドカード検索で利用することにした。↓ こういう使い方。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;([&lt;span class=&quot;hljs-type&quot;&gt;System.Management.Automation.WildcardPattern&lt;/span&gt;]&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;*ui*&amp;quot;&lt;/span&gt;).IsMatch(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;kouiuno&amp;#x27;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description><pubDate>Sun, 05 Jun 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-05-28-writing-cmdlet-in-fsharp.html</guid><link>https://krymtkts.github.io/posts/2022-05-28-writing-cmdlet-in-fsharp.html</link><title>F#でコマンドレットを書いてる</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2022-05-07-start-to-write-cmdlet-by-fsharp.html&quot; title=&quot;以前 F# で PowerShell コマンドレットを書き始めた&quot;&gt;以前 F# で PowerShell コマンドレットを書き始めた&lt;/a&gt;と書いた。&lt;/p&gt;
&lt;p&gt;ひと月くらいかけて主に休みの日にちょいちょい書き進めてきて、最近最低限動くようになったので public repo にした。
&lt;a href=&quot;https://github.com/krymtkts/pocof&quot; title=&quot;krymtkts/pocof&quot;&gt;krymtkts/pocof&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;まだ激ショボな機能しかない。
プロパティを指定してフィルタリングするとか、フィルタリングした見た目をこれまたテーブルフォーマットにするとか、 PowerShell ならではの良さをまだ全然作り込めてない。&lt;/p&gt;
&lt;p&gt;さっぱり作り方がわからん &lt;code&gt;Format-Table&lt;/code&gt; とか &lt;code&gt;-like&lt;/code&gt; とか PowerShell のクラスをそのまま使いたい気分。無理やったら組むねんけど。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ls | pocof&lt;/code&gt; したら Terminal-Icons で鮮やかになったままフィルタリングされてほしいのよなー。
この辺が組み込めたら、 PowerShell Gallery で公開したい。&lt;/p&gt;
&lt;p&gt;現状正規表現でのフィルタリングくらいしかまともに使えるものがなく亀速な進捗だけど、Cmdlet を書いたり F# で書いたのも初めてだったから、楽しく取り組めた。&lt;/p&gt;
&lt;p&gt;前にも書いた通り、これは poco の多言語フォークなんやけど、その動機としては poco の未実装だったり使いにくいところが起因してツール自体をあまり使いこなせてなかったところがある。
自分自身あまりツールの使い込みは得意じゃなくて、なんなら自分流にアレンジできるタイプのツールしか使いこなせない。&lt;/p&gt;
&lt;p&gt;DIY キーボードとかまさにその典型例なんやけど、キーバインディングが自分の制御下に置かれた途端ブラインドタッチができるようになったりしたので、何かと自分用に手を加えないといけないんだろう。&lt;/p&gt;
&lt;p&gt;でもこれで poco というか pocof は自分の制御下に置いたのでなんか色々試してみたいお気持ち。&lt;/p&gt;
&lt;p&gt;F# の書き心地に関しては、まだ慣れない点もあれど結構気に入ってる。 &lt;code&gt;else&lt;/code&gt; は矯正してほしいところやけど。&lt;/p&gt;
&lt;p&gt;着手前は試しにコンピュート式書いてみたいなーとか考えてたが、いまんとこ使おうと思えば使えるけど敢えて使うほどでもない感じで、使い所ない。
大したことやってないからパターンマッチや高階関数使ってるだけでもサクサクできる。
.NET 自体かなり久しぶりなこと(PowerShell つかってるけど全然 .NET に踏み込んでない...)と、 .NET と F# の世界の境界がまだ自分の中で曖昧で、そのへんは書きながら学んでいきたいなーという感じ。&lt;/p&gt;
&lt;p&gt;何にせよ趣味プロのちょうどいいネタを見つけた。当分はこれで遊ぶ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 28 May 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-05-22-customize-my-worn-out-705.html</guid><link>https://krymtkts.github.io/posts/2022-05-22-customize-my-worn-out-705.html</link><title>使い古しの Logicool M 705 をカスタマイズする</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;もう 15 年くらい使っている Logicool の M705 がある。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-M705-&quot; href=&quot;#-M705-&quot;&gt;この M705 について&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;この M705 は、昔ロジクールに勤めていた友人からもらったものだ。
現行モデルは多分これ → &lt;a href=&quot;https://www.logicool.co.jp/ja-jp/products/mice/m705m-wireless-mouse.910-005303.html&quot; title=&quot;3 年の電池寿命を提供するロジクール M705m マラソン ワイヤレスマウス&quot;&gt;3 年の電池寿命を提供するロジクール M705m マラソン ワイヤレスマウス&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;もらってから数年の間はそんなに使ってなかったが、尋常でない電池寿命とハードデューティさに気づき、以降メインとして使っている。&lt;/p&gt;
&lt;p&gt;わたしはマウスを「つまみ持ち」する。この M705 はわたしの持ち方に、クリックの押し込みの深さとか、軽く指を曲げた状態での親指と小指の間隔がバッチリハマっていて、同じマウスをずっと使っている。&lt;/p&gt;
&lt;p&gt;トラッキングの位置が他のマウスとは結構違っていて、若干操作に癖を感じていたが、そこは慣れだったような記憶がある。&lt;/p&gt;
&lt;p&gt;一時期左クリックがチャタリングを起こしたことがあって、数週間別のマウスに乗り換えて使わない時期があったのだが、放置中に直って以降はチャタリングも起こらなくなった(何故)。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;異変&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;この M705 だが、グリップ力強化かなんかの理由で、マウスの両サイドがラバーというかやわらかい合成樹脂でできている。
これが利用から 10 年も経った頃から異変を感じるようになった。ボコボコしてきたり擦れるだけでラバーが削れたり。&lt;/p&gt;
&lt;p&gt;最近知ったが、これは合成樹脂のブリーディングとかブリードアウトという現象のようだ。合成樹脂の成分自体が分離しだしてるから、拭き取ったりしてどうにかなるものでないということだった。&lt;/p&gt;
&lt;p&gt;ここ数年は症状の進行も激しく、指で押すだけで指紋がつくくらいにラバーが劣化していた。&lt;/p&gt;
&lt;p&gt;マウスを買い替えることも検討したが、まだメカニカルな部分は動くし、新しいマウスを選ぶのも結構労力がかかるよなーというのが悩みだった。
そこで思い切って、このベタベタボロボロラバーを取り除こうと考えた。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;カスタマイズする&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;M705 のベタベタボロボロラバーを取り除き、手元にあった黒のテーピングを重ねて貼ることにした。テーピングならラバー部分の形状に合わせることも簡単だし、親指＆小指の接触部分が汚れたとしてもまた貼り直せばいいだけなので、我ながら良いアイデアだ。&lt;/p&gt;
&lt;p&gt;ベタボロラバーを取り除くのには、大型刃のカッターナイフと、細かい部分にはデザインナイフを利用した。いずれもオルファだ。&lt;/p&gt;
&lt;p&gt;分解してみてわかったが、ラバーのボコボコしていた部分には溶け出した液状の謎成分が溜まっており、中々グロテスクだった。
このマウスはプラスチックの骨格みたいなところにラバーをはめ込み＆貼り付けしてるような構造をしていて、プラスチック部分を極力傷つけないようにした。&lt;/p&gt;
&lt;p&gt;小指側のラバーを取り除くのは非常に簡単だった。単にプラウチック部分の弧に合わせてカッターをすべらせるだけでスイスイ剥がせた。&lt;/p&gt;
&lt;p&gt;親指側は形状的に窪んでいるので結構難しく、デザインナイフを使ってできるだけ細やかに処理した。特に親指部分のスイッチ(旧モデルにのみあるやつ。進む・戻るボタンじゃなく親指の位置にある)は可動部のラバーを取り除くと空洞になる。配線にカッターのはが届くので慎重に作業する必要があった。&lt;/p&gt;
&lt;p&gt;分解を進めると、樹脂の劣化の進行具合が、指に触れる箇所とそうでない箇所で大きく異なるのが見て取れた。
劣化が進んだ箇所はグズグズで、刃を滑らせるのも簡単だったが、親指側の指が触れない部分等は結構元のママの硬度のようで、ちょっと力が必要だった。&lt;/p&gt;
&lt;p&gt;ベタボロラバーを取り除いたあとにはテーピングを施す。&lt;/p&gt;
&lt;p&gt;曲面へ一枚で貼り付けるのは面倒なので、いくつかの面でテーピングを区切りそれを組み合わせて貼り付けた。
やはり強度面で元のベタボロラバーに大きく劣るので、少なくても二重、親指ん可動部は三重にテーピングすることで強度を持たせてみた。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;感想&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;アイデアができてからは、作業に対した時間もかからなかったし、中々やってみてよかった。&lt;/p&gt;
&lt;p&gt;結構長い期間をベタボロラバーの状態で触ってきたので、テーピングのサラサラした手触りになって中々新鮮味がある。&lt;/p&gt;
&lt;p&gt;まだ使ってみて一週間程度なので、この後どの程度テーピング部分に汚れが蓄積していくかは見えていないが、まあ半年とかのスパンで交換できれば良いか。&lt;/p&gt;
&lt;p&gt;お気に入りのマウスをより良い状態に改善し、継続して使い続ける術を新たに身に着けた。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 22 May 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-05-14-think-about-alignment-of-full-width-chars.html</guid><link>https://krymtkts.github.io/posts/2022-05-14-think-about-alignment-of-full-width-chars.html</link><title>East Asian な全角文字をキーに使った場合のアラインメントについて考える</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;掲題のとおりである。
ここでいうアラインメントはメモリの話じゃなくて、字面上の整列のことを指す。&lt;/p&gt;
&lt;p&gt;自分の中でもどうあるべきかまだ結論が出せてないので、考えをまとめるために書く。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;問題&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;いま、 &lt;a href=&quot;https://github.com/PowerShell/PSScriptAnalyzer&quot; title=&quot;PSScriptAnalyzer&quot;&gt;PSScriptAnalyzer&lt;/a&gt; で全角文字をキーに持つ hashtable を整形したとき期待どおりにならなのだけど、どう解決するのがいいのだろう？と悩んでる。&lt;/p&gt;
&lt;p&gt;一応弁解しておくと、わたしの気持ちとしては「そんなところに全角文字使うとか危なげなことやめようや」だ。&lt;/p&gt;
&lt;p&gt;ところが、今やってる仕事でスプレッドシートのデータをシステムに取り込むにあたり、それらをいくつかの CSV に分解・再構築する必要があって、その中でこのテーマに直面した。 PSCustomObject を CSV に変換する形でスクリプトを作ってるので、全角文字が識別子になるのだ。&lt;/p&gt;
&lt;p&gt;普通に自分が書く範囲だとこんなの書かないので、最近まで気づかなかった。&lt;/p&gt;
&lt;p&gt;VS Code で PowerShell を書くと、自動整形には &lt;a href=&quot;https://github.com/PowerShell/PSScriptAnalyzer&quot; title=&quot;PSScriptAnalyzer&quot;&gt;PSScriptAnalyzer&lt;/a&gt; の &lt;code&gt;Invoke-Formatter&lt;/code&gt; が使われる。この戻り値が整形後のコードになるのだけど、ここで今回のテーマに直面する。&lt;/p&gt;
&lt;p&gt;問題は以下のコードで再現できる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$settings&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;    IncludeRules = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSAlignAssignmentStatement&amp;#x27;&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;    Rules = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        PSAlignAssignmentStatement = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;            Enable = &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;# PSAlignAssignmentStatement.CheckHashtable が真だと、&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;# hashtable の要素の並びを整形してくれる。&lt;/span&gt;&lt;br /&gt;            CheckHashtable = &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$script&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;@&amp;#x27;&lt;br /&gt;$test = @{&lt;br /&gt;    A = 0&lt;br /&gt;    ABC = 0&lt;br /&gt;    ABCDE = 0&lt;br /&gt;    Ａ = 0&lt;br /&gt;    ＡＢＣ = 0&lt;br /&gt;    ＡＢＣＤＥ = 0&lt;br /&gt;}&lt;br /&gt;&amp;#x27;@&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-Formatter&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ScriptDefinition&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$script&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Settings&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$settings&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;出力はこうなる。これは期待のとおりではない。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$test&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;    A     = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ABC   = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ABCDE = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    Ａ     = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ＡＢＣ   = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ＡＢＣＤＥ = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;わたしはこうなってほしいと考える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$test&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;    A          = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ABC        = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ABCDE      = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    Ａ         = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ＡＢＣ     = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ＡＢＣＤＥ = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;PSScriptAnalyzer のコードを調べて、 PSScriptAnalyzer 的には PowerShell のパーサが返した列番号(&lt;code&gt;EndColumnNumber&lt;/code&gt;)の通りに整形してるのがわかった。
&lt;a href=&quot;https://github.com/PowerShell/PSScriptAnalyzer/blob/58c44234d44dfd0db35bb532906963e08fde8621/Rules/AlignAssignmentStatement.cs#L194&quot; title=&quot;PSScriptAnalyzer/AlignAssignmentStatement.cs GetHashtableCorrections の L194&quot;&gt;PSScriptAnalyzer/AlignAssignmentStatement.cs GetHashtableCorrections の L194&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;次に PowerShell のパーサを直接調べる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$script&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;@&amp;#x27;&lt;br /&gt;$test = @{&lt;br /&gt;    A = 0&lt;br /&gt;    ABC = 0&lt;br /&gt;    ABCDE = 0&lt;br /&gt;    Ａ = 0&lt;br /&gt;    ＡＢＣ = 0&lt;br /&gt;    ＡＢＣＤＥ = 0&lt;br /&gt;}&lt;br /&gt;&amp;#x27;@&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;getColumnNumberString&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$Extent&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;start &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$Extent&lt;/span&gt;.StartColumnNumber.ToString().PadLeft(2)) end &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$Extent&lt;/span&gt;.EndColumnNumber.ToString().PadLeft(2))&amp;quot;&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ast&lt;/span&gt; = [&lt;span class=&quot;hljs-type&quot;&gt;System.Management.Automation.Language.Parser&lt;/span&gt;]::ParseInput(&lt;span class=&quot;hljs-variable&quot;&gt;$script&lt;/span&gt;, [&lt;span class=&quot;hljs-type&quot;&gt;ref&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt;, [&lt;span class=&quot;hljs-type&quot;&gt;ref&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$null&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$hashAst&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$ast&lt;/span&gt;.FindAll({ &lt;span class=&quot;hljs-variable&quot;&gt;$args&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] &lt;span class=&quot;hljs-operator&quot;&gt;-is&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;System.Management.Automation.Language.HashtableAst&lt;/span&gt;] }, &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$hashAst&lt;/span&gt;.KeyValuePairs | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# Item1 がキーの情報、 Item2 は &amp;#x27;=&amp;#x27; の情報&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$e1&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$e2&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Item1.Extent, &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Item2.Extent&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;key &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(getColumnNumberString(&lt;span class=&quot;hljs-variable&quot;&gt;$e1&lt;/span&gt;)) | &amp;#x27;=&amp;#x27; &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(getColumnNumberString(&lt;span class=&quot;hljs-variable&quot;&gt;$e2&lt;/span&gt;))&amp;quot;&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;出力はこうなって、全角文字の表示幅は考慮されてないのがわかる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;key start  5 end  6 | &amp;#x27;=&amp;#x27; start  9 end 10&lt;br /&gt;key start  5 end  8 | &amp;#x27;=&amp;#x27; start 11 end 12&lt;br /&gt;key start  5 end 10 | &amp;#x27;=&amp;#x27; start 13 end 14&lt;br /&gt;key start  5 end  6 | &amp;#x27;=&amp;#x27; start  9 end 10&lt;br /&gt;key start  5 end  8 | &amp;#x27;=&amp;#x27; start 11 end 12&lt;br /&gt;key start  5 end 10 | &amp;#x27;=&amp;#x27; start 13 end 14
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;じゃあこれは PowerShell のバグなのか？とまで考えを至らせると、いやパーサは表示する文字の幅を意識する必要あるか？と思えるので、これは誰が解決する問題なんや...と思っているのが、今の状況。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;他の言語を調べる&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;他の事例を調べて、全角文字を含むキーや識別子をアラインメントするとどうなるか比べてみる。&lt;/p&gt;
&lt;p&gt;とはいえ、他の言語でアラインメントするようなフォーマットかける言語何があったっけ？
少なくとも Python は違ったし、思いついたのは Go だけ。
Go 以外にも思いついたら追加したい。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;Go&quot; href=&quot;#Go&quot;&gt;Go&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;こんな中身の &lt;code&gt;test.go&lt;/code&gt; があるとする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; main&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; person &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {&lt;br /&gt;&amp;emsp;A &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;&amp;emsp;ABC &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;&amp;emsp;ABCDE &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;&amp;emsp;Ａ &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;&amp;emsp;ＡＢＣ &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;&amp;emsp;ＡＢＣＤＥ &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これに &lt;code&gt;gofmt ./test.go&lt;/code&gt; すると次の通り。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; main&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; person &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {&lt;br /&gt;        A     &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;        ABC   &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;        ABCDE &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;        Ａ     &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;        ＡＢＣ   &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;        ＡＢＣＤＥ &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;やっぱり！ PowerShell の結果と同じ。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;現時点の理解&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;現実的には、パーサやフォーマッタがフォントの文字幅を考慮しないし、アラインメントしないのが妥当な落とし所なのかな。
気持ちとしては、全角文字を含んだとしても綺麗にアラインメントしてほしいが、それもエッジケースなのでそんなに困ることがない。&lt;/p&gt;
&lt;p&gt;とはいえ Unicode 文字の演算子とかポツポツあるし、幅の規定が厳格であればフォーマッタあたりで解消したいテーマではある気がする。&lt;/p&gt;
&lt;p&gt;なんか締まらない締めになった。&lt;/p&gt;
&lt;p&gt;とりあえず自分用の覚書としては、 PSScriptAnalyzer は &lt;code&gt;PSAlignAssignmentStatement.CheckHashtable=$false&lt;/code&gt; で利用すればこの問題に悩まされることもないので、オススメする。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 14 May 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-05-07-start-to-write-cmdlet-by-fsharp.html</guid><link>https://krymtkts.github.io/posts/2022-05-07-start-to-write-cmdlet-by-fsharp.html</link><title>F#で PowerShell コマンドレットを書き始めた</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;勉強がてら、F# で PowerShell のコマンドレットを書きはじめる。
↓ を参考にやる。ただし .NET 6.0 を対象にする。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://webcoder.info/fspsmodule.html&quot; title=&quot;Writing a PowerShell Core Module With F#, A Complete Guide | Brianary&quot;&gt;Writing a PowerShell Core Module With F#, A Complete Guide | Brianary&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;初めての要素が多いので、ゆっくり進める。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;F# でアプリ書くのが初&lt;/li&gt;&lt;li&gt;コマンドレットを書くのが初&lt;/li&gt;&lt;li&gt;dotnet CLI を使った開発が初&lt;/li&gt;&lt;li&gt;その他 PowerShell 系のツール(&lt;a href=&quot;https://github.com/pester/Pester&quot; title=&quot;Pester&quot;&gt;Pester&lt;/a&gt;,&lt;a href=&quot;https://github.com/PowerShell/platyPS&quot; title=&quot;platyPS&quot;&gt;platyPS&lt;/a&gt;)をちゃんと使うのが初&lt;ul&gt;
&lt;li&gt;参考にする記事にはないが、ビルドスクリプトも &lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;psake&quot;&gt;psake&lt;/a&gt; で書く&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;題材としては、&lt;a href=&quot;https://github.com/jasonmarcher/poco&quot; title=&quot;poco&quot;&gt;poco&lt;/a&gt; の再実装をしてみるつもり。&lt;/p&gt;
&lt;p&gt;諸々のツールが出てくるので一覧しておく。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub の Repo の作成に &lt;a href=&quot;https://github.com/microsoft/PowerShellForGitHub&quot; title=&quot;PowerShellForGitHub&quot;&gt;PowerShellForGitHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;remote repo の管理に &lt;a href=&quot;https://github.com/x-motemen/ghq&quot; title=&quot;ghq&quot;&gt;ghq&lt;/a&gt;&lt;/li&gt;&lt;li&gt;コミット署名のために &lt;a href=&quot;https://community.chocolatey.org/packages/Gpg4win&quot; title=&quot;Gpg4win&quot;&gt;Gpg4win&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;repo-&quot; href=&quot;#repo-&quot;&gt;repo とプロジェクトを作成する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;動くものになるまでは private repo で運用する。動かないなら公開しても意味がないからね。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# private repo を作成する。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$owner&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;krymtkts&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;pocof&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;New-GitHubRepository&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-RepositoryName&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;pocof&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Private&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# remote repo を clone する。&lt;/span&gt;&lt;br /&gt;ghq get &lt;span class=&quot;hljs-literal&quot;&gt;-p&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-GitHubRepository&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-OwnerName&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$owner&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-RepositoryName&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; ssh_url)&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(ghq root)/&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(ghq list &lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;)&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# initial commit を刻む。&lt;/span&gt;&lt;br /&gt;gpg&lt;span class=&quot;hljs-literal&quot;&gt;-connect-agent&lt;/span&gt; reloadagent /bye &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;- gpg-agent が立ち上がってこないので先に起こす。&lt;/span&gt;&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;--allow-empty&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Initial commit.&amp;#x27;&lt;/span&gt;&lt;br /&gt;dotnet new sln&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 空のプロジェクトを作成。&lt;/span&gt;&lt;br /&gt;dotnet new classlib &lt;span class=&quot;hljs-literal&quot;&gt;--language&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;F#&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--framework&lt;/span&gt; net6.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-o&lt;/span&gt; src/&lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;&lt;br /&gt;dotnet sln add src/&lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;/&lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;.fsproj&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; src/&lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# PowerShell 開発の依存関係を追加。&lt;/span&gt;&lt;br /&gt;dotnet add package PowerShellStandard.Library&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;New-ModuleManifest&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;.psd1&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;lt;helpItems schema=&amp;quot;maml&amp;quot; xmlns=&amp;quot;http://msh&amp;quot; /&amp;gt;&amp;#x27;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;.dll-Help.xml&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Encoding&lt;/span&gt; utf8
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで repo と空の F# プロジェクト &lt;code&gt;pocof.fsproj&lt;/code&gt; ができた。
次に、記事に記載の通り、 &lt;code&gt;pocof.fsproj&lt;/code&gt; に必要な情報を加筆する。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PropertyGroup&lt;/code&gt; に &lt;code&gt;Version&lt;/code&gt; 属性を追加&lt;/li&gt;&lt;li&gt;&lt;code&gt;ItemGroup&lt;/code&gt; 属性を追加して、コピーするファイルを記載する&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;また PowerShell のモジュール情報を &lt;code&gt;pocof.psd1&lt;/code&gt; 書き込む。
コマンドレットなので、 &lt;code&gt;RootModule&lt;/code&gt; を書き忘れるとコマンドがインポートできないのでご注意(書き忘れてて &lt;code&gt;Import-Module&lt;/code&gt; しても使えない！となった)。&lt;/p&gt;
&lt;p&gt;あと作成後に気づいたのだが、 作成された &lt;code&gt;*.sln&lt;/code&gt; 等のエンコーディングが UTF8 with BOM だったり改行が CRLF だったりするので、それらを UTF8 と LF に手で補正した。&lt;/p&gt;
&lt;p&gt;最後に 空の XML-based help file を作成しているが、これは &lt;code&gt;Get-Help&lt;/code&gt; で使うヘルプファイルで、後で PlatyPS で上書きされるやつ。
&lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/scripting/developer/help/naming-help-files?view=powershell-7.2&quot; title=&quot;Naming Help Files - PowerShell | Microsoft Docs&quot;&gt;Naming Help Files - PowerShell | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;F-&quot; href=&quot;#F-&quot;&gt;F# 開発環境を準備する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;わたしは VS Code を使っているので、F# 用の拡張機能を入れる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=Ionide.Ionide-fsharp&quot; title=&quot;Ionide for F# - Visual Studio Marketplace&quot;&gt;Ionide for F# - Visual Studio Marketplace&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;F# でフォーマッタといえば &lt;code&gt;fantomas&lt;/code&gt; のようなのだけど、個別に入れなくても Ionide がうまく拾えるらしい。 &lt;a href=&quot;https://github.com/ionide/ionide-vscode-fsharp/issues/1346&quot; title=&quot;Formatting Settings · Issue #1346 · ionide/ionide-vscode-fsharp&quot;&gt;Formatting Settings · Issue #1346 · ionide/ionide-vscode-fsharp&lt;/a&gt;&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;コードを編集する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;自動生成されたコードを編集する。
記事に記載のものだとパラメータに &lt;code&gt;Position&lt;/code&gt; がなくて Pester こけそうなのと、自分のやりたいことに合わせた引数を書くなど諸々の調整をする。&lt;/p&gt;
&lt;p&gt;Pester のテストコードも作成する。テストコードは &lt;code&gt;tests&lt;/code&gt; ディレクトリ配下に配置した。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;ビルド＆テスト実行&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;記事に記載の通りだと typo があったり &lt;code&gt;Import-Module&lt;/code&gt; 前に削除があって消えてしまう等ある。
編集して実行した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ModuleName&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Resolve-Path&lt;/span&gt; ./src/* | &lt;span class=&quot;hljs-built_in&quot;&gt;Split-Path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Leaf&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Import-LocalizedData&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-BindingVariable&lt;/span&gt; module &lt;span class=&quot;hljs-literal&quot;&gt;-BaseDirectory&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Resolve-Path&lt;/span&gt; ./src/*) &lt;span class=&quot;hljs-literal&quot;&gt;-FileName&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$ModuleName&lt;/span&gt;.psd1&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;.ModuleVersion &lt;span class=&quot;hljs-operator&quot;&gt;-ne&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Resolve-Path&lt;/span&gt; ./src/*/*.fsproj | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Xml&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;//Version/text()&amp;#x27;&lt;/span&gt;).Node.Value) {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Module manifest (.psd1) version does not match project (.fsproj) version.&amp;#x27;&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;dotnet publish&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cp&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Resolve-Path&lt;/span&gt; ./src/*/bin/Debug/*/publish/FSharp.Core.dll) (&lt;span class=&quot;hljs-built_in&quot;&gt;Resolve-Path&lt;/span&gt; ./src/*/bin/Debug/*/) &lt;span class=&quot;hljs-literal&quot;&gt;-Verbose&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# import して Pester 実行。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# モジュールのバージョンであったり export される Cmdlet が正しいかなど見る。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Import-Module&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Resolve-Path&lt;/span&gt; ./src/*/bin/Debug/*/publish/*.psd1) &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-Pester&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あとこれらを &lt;code&gt;psake&lt;/code&gt; で実行できるように &lt;code&gt;psakefile.ps1&lt;/code&gt; に記載した。&lt;/p&gt;
&lt;p&gt;F# のプロジェクトだったら &lt;a href=&quot;https://github.com/fsprojects/FAKE&quot; title=&quot;FAKE&quot;&gt;FAKE&lt;/a&gt; を使った方がいいのかなーと考えていた。となると、依存する &lt;a href=&quot;https://fsprojects.github.io/Paket/&quot; title=&quot;Paket&quot;&gt;Paket&lt;/a&gt; も入れないといけない。いま &lt;code&gt;dotnet&lt;/code&gt; CLI で管理してたのでいらないかなーと思った。
また、今回作りたいのは PowerShell のコマンドレットなので、 周辺のツールも PowerShell だ。これをいちいち &lt;code&gt;fake.cmd&lt;/code&gt; や &lt;code&gt;dotnet fake build&lt;/code&gt;を介して実行するのなんかダルいな...と億劫だったので、 FAKE の導入は見送ることにした。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;ドキュメントを生成する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;記事では &lt;a href=&quot;https://github.com/PowerShell/platyPS&quot; title=&quot;platyPS&quot;&gt;platyPS&lt;/a&gt; を使っているのでそれに従う。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 事前にビルドしたモジュールを Import-Module しておく。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;New-MarkdownHelp&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Module&lt;/span&gt; pocof &lt;span class=&quot;hljs-literal&quot;&gt;-OutputFolder&lt;/span&gt; ./docs &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; SilentlyContinue&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# dll-Help.xml を作るときに実行する。&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;New-ExternalHelp&lt;/span&gt; docs &lt;span class=&quot;hljs-literal&quot;&gt;-OutputPath&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Resolve-Path&lt;/span&gt; ./src/*/) &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コメントに記した通り、他のタスクと依存関係にある。こういうのは &lt;code&gt;psakefile.ps1&lt;/code&gt; にまとめる。&lt;/p&gt;
&lt;p&gt;ヘルプの作成元は Markdown をオリジナルとする方針。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;PowerShell-Gallery-&quot; href=&quot;#PowerShell-Gallery-&quot;&gt;PowerShell Gallery へのリリース&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;まだやらないけど手順だけ確立しておく。&lt;/p&gt;
&lt;p&gt;記事に記載のものだと、ビルドコンフィグレーションを Release にして Import、その後 Import したモジュールを公開、という手順になっている。&lt;/p&gt;
&lt;p&gt;個人的にやったことがあるのはフォルダを指定して公開する方だけなので、どっちにするかなーと悩んでいる。間違って古い Import 済みモジュールを公開するミスとかないのかな、というのが疑問。&lt;/p&gt;
&lt;p&gt;ま、勉強のためのものであるし、やったことない方を接客的に選んでみるのも一興か。コマンドレットが正しくエクスポートできているか、リリース前にテストするにもこの方法を取るのが良さそうだし。&lt;/p&gt;
&lt;p&gt;とはいえ記事に記載の通りやると、自分が普段利用している PowerShell Module のパスに直でリリース前のモジュールを打ち込んでしまう。
これはちょっと実用始めたら困りそうなので、ディレクトリを変える必要がある。
となると結局いつものパス指定でのリリース方式でええんちゃうか...&lt;/p&gt;
&lt;p&gt;いずれを選択するかはまた検討したい。&lt;/p&gt;
&lt;p&gt;また、これらのリリースタスクも &lt;code&gt;psakefile.ps1&lt;/code&gt; に定義するものとする。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;おわりに&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;これでひとまず準備完了。
ほぼ記事に記載のとおりやってきたけど、ちょいちょい自分用に変えたり、新しい要素については色々調べながらやってるので、進捗は亀のスピードだった。
動くものをこしらえれたら public repo にしよう。&lt;/p&gt;
&lt;p&gt;現時点で不足しているとわかっている点もある。
今回書きたいコマンドレットはインタラクティブなものなので、きっと Pester でテストできない点が出てくる。
それらは &lt;a href=&quot;https://fsprojects.github.io/FsUnit/&quot; title=&quot;FsUnit&quot;&gt;FsUnit&lt;/a&gt; を使って可能な限りテストを書きたい所存。&lt;/p&gt;
&lt;p&gt;あと困っているのが、参考にしている記事にも記載があったが、 DLL への参照が切れなくてファイルを消したりできなくなる(&lt;code&gt;Remove-Module&lt;/code&gt; 忘れとかでなく)。いまは都度 PowerShell のセッションを作り直してるけど相当に面倒なので、原因を突き止めてどうにかしたいな。&lt;/p&gt;
&lt;p&gt;未経験のものに触れるのは普段得られない刺激があって良い。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 07 May 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-04-29-good-bye-omp-module.html</guid><link>https://krymtkts.github.io/posts/2022-04-29-good-bye-omp-module.html</link><title>さよなら oh-my-posh モジュール</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;いつものように PowerShell Module を更新して PowerShell を立ち上げると次のようなメッセージが表示された。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Hey friend&lt;br /&gt;&lt;br /&gt;In an effort to grow oh-my-posh, the decision was made to no&lt;br /&gt;longer support the PowerShell module. Over the past year, the&lt;br /&gt;added benefit of the module disappeared, while the burden of&lt;br /&gt;maintaining it increased.&lt;br /&gt;&lt;br /&gt;However, this doesn&amp;#x27;t mean oh-my-posh disappears from your&lt;br /&gt;terminal, it just means that you&amp;#x27;ll have to use a different&lt;br /&gt;tool to install it.&lt;br /&gt;&lt;br /&gt;All you need to do, is follow the migration guide here:&lt;br /&gt;&lt;br /&gt;https://ohmyposh.dev/docs/migrating
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あら... oh-my-posh 3 から Go で実装されて、マルチプラットフォームなプロンプトテーマエンジンになってたけど、ついにその時が来たか...という感じ。&lt;/p&gt;
&lt;p&gt;とりあえず使えなくなる(というか更新できなくなる)と困るので、&lt;a href=&quot;https://ohmyposh.dev/docs/migrating&quot; title=&quot;移行手順&quot;&gt;移行手順&lt;/a&gt; に記載された移行手順を行うことにした。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;わたしの移行手順&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;記載の順番にやってもいいけど、慎重を期すため順番を変えた。&lt;/p&gt;
&lt;p&gt;まず &lt;code&gt;oh-my-posh&lt;/code&gt; が &lt;code&gt;PATH&lt;/code&gt; にある状態で、 &lt;code&gt;Set-PoshPrompt&lt;/code&gt; を &lt;code&gt;oh-my-posh init pwsh&lt;/code&gt; に変え、プロンプトの表示をチェックした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Set-PoshPrompt -Theme ~/.oh-my-posh.omp.json&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;oh&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt; init pwsh &lt;span class=&quot;hljs-literal&quot;&gt;--config&lt;/span&gt; ~/.custom.omp.json | &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-Expression&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当然のごとくきれいに出力されるので、 PowerShell Module から置き換える。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ohmyposh.dev/docs/installation/windows&quot; title=&quot;Windows 向けの公式なインストール手順&quot;&gt;Windows 向けの公式なインストール手順&lt;/a&gt;では &lt;code&gt;winget&lt;/code&gt;, &lt;code&gt;scoop&lt;/code&gt; それか手動での更新になっている。&lt;/p&gt;
&lt;p&gt;でもわたしは永らく &lt;code&gt;chocolatey&lt;/code&gt; を使っていることもあり、有志が公開してくれているパッケージを利用する。見たところバージョンも最新に追随していていい感じ。
&lt;a href=&quot;https://community.chocolatey.org/packages/oh-my-posh#versionhistory&quot; title=&quot;Chocolatey Software | Oh-My-Posh 7.74.3&quot;&gt;Chocolatey Software | Oh-My-Posh 7.74.3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;管理者権限で &lt;code&gt;cmd&lt;/code&gt; を開き、インストールする。補足：PowerShell でもインストールできるが、PowerShell 自体を &lt;code&gt;chocolatey&lt;/code&gt; でインストールしているのもあり &lt;code&gt;chocolatey&lt;/code&gt; でのインストールは &lt;code&gt;cmd&lt;/code&gt; で行うようにしている。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cmd&quot;&gt;choco install oh-my-posh -y
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このインストールの最後に、&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;PROFILE: C:\Users\takatoshi\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1&lt;br /&gt;oh-my-posh has been added to your profile. You may wish to append &amp;#x27;Set-PoshPrompt paradox&amp;#x27; to set a theme
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;と言われたが、 Windows PowerShell のプロファイルはおろかどこにも加筆されてないようだった。&lt;/p&gt;
&lt;p&gt;管理者権限で PowerShell を起動し、 oh-my-posh の Powershell Module を削除する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Uninstall-Module&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;oh&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AllVersions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;Import-Module oh-my-posh&lt;/code&gt; は元々書いてなかったので削除なし。代わりにプロファイルの中でインストール・更新するモジュール名を管理しているので、そこから取り除いた。&lt;/p&gt;
&lt;p&gt;以上。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;感想&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;何事もなく移行できて良かった。&lt;/p&gt;
&lt;p&gt;ただこれを機に、もう oh-my-posh にこだわらず、 &lt;a href=&quot;https://starship.rs/&quot; title=&quot;Starship&quot;&gt;Starship&lt;/a&gt; みたいなもっとイケてるプロンプトテーマエンジンに積極的に乗り換えてもいいかなーと思えてきた。&lt;/p&gt;
&lt;p&gt;元々 oh-my-posh を使ってたのは、 2018 年頃の PowerShell でいい感じの Powerline ができる唯一のツールだったからだ(わたしの観測範囲では。もう一つその名の通り Powerline というモジュールがあったが満足の行くカスタマイズができなかった&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;)。
テーマを PowerShell で書けて、PowerShellGet からインストールできるのも楽だった。&lt;/p&gt;
&lt;p&gt;とはいえ、それがマルチプラットフォームに対応した oh-my-posh の足枷になったみたいやけど。&lt;/p&gt;
&lt;p&gt;逆に利用者の立場からいえば、 oh-my-posh が明確に PowerShell に特化しなくなったということ。
これは、わたしが Power Fighter(勝手に作った PowerShell 使いの呼び名)であるから oh-my-posh を使い続けていたという理由もなくなったことになる。&lt;/p&gt;
&lt;p&gt;oh-my-posh が Go で書き換わったときに一番気に入らなかったのは &lt;em&gt;&lt;strong&gt;設定ファイルが JSON&lt;/strong&gt;&lt;/em&gt; なとこなので、そのフラストレーションを解消するいい機会をもらったのかも知れない。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;まだあったわ →&lt;a href=&quot;https://www.powershellgallery.com/packages/PowerLine/3.4.0&quot; title=&quot;PowerShell Gallery | PowerLine 3.4.0&quot;&gt;PowerShell Gallery | PowerLine 3.4.0&lt;/a&gt; &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Fri, 29 Apr 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-04-23-aws-rehabilitation.html</guid><link>https://krymtkts.github.io/posts/2022-04-23-aws-rehabilitation.html</link><title>AWS リハビリのハマり集</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;現職は半年ぶりの AWS ということで、ちまちまリハビリをしている。
諸々忘れてたりものによってはハマっている現状。記憶に定着させるため、ハマったところを記す。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;Hello-World-code-sam-init-code-&quot; href=&quot;#Hello-World-code-sam-init-code-&quot;&gt;Hello World 以外の &lt;code&gt;sam init&lt;/code&gt; できません&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;AWS SAM は前職でも使っていたが、久しぶりに触ったら詰まるところがあったので書いておく。&lt;/p&gt;
&lt;p&gt;久しぶりに &lt;code&gt;sam init&lt;/code&gt; すると 100%エラーで終わる。端末は Windows 11。
こんな風に ↓。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)&lt;br /&gt;Error: Can&amp;#x27;t find application template quick-start-web - check valid values in interactive init.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-sam-cli/issues/3692#issuecomment-1070222512&quot; title=&quot;Unable to create Serverless API using SAM v1.40.0 · Issue #3692 · aws/aws-sam-cli&quot;&gt;Unable to create Serverless API using SAM v1.40.0 · Issue #3692 · aws/aws-sam-cli&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;どうも Windows 限定の問題らしい。 &lt;code&gt;sam&lt;/code&gt; が使う template repository を &lt;code&gt;git clone&lt;/code&gt; できないという深刻なやつ。
AWS SAM の一時ディレクトリを消して、手動で &lt;code&gt;git clone&lt;/code&gt; したら解消する。これは Issue は Closed になっているものの、中々気付かんし原因を究明したい気がする。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;MFA-&quot; href=&quot;#MFA-&quot;&gt;MFA 有効化されたアクセスキーの使い方忘れた&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;タイトルの通り。&lt;/p&gt;
&lt;p&gt;そのまま使うとワンタイムパスの入力を求められないが、一時クリデンシャルを発行するときに出る。&lt;/p&gt;
&lt;p&gt;昔は MFA が必要な switch role するときに aws-mfa を使っていたが、 この度 AWS Tools for PowerShell で自分の利用ケースのみシンプルにこしらえた。
ワンタイムパスワードの入力には 1Password の CLI である &lt;a href=&quot;https://developer.1password.com/docs/cli/get-started&quot; title=&quot;&lt;code&gt;op&lt;/code&gt;&quot;&gt;&lt;code&gt;op&lt;/code&gt;&lt;/a&gt; を使うと究極に楽。現職で 1Password を使ってるので導入したみた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$env:AWS_REGION&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ap-northeast-1&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$user&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;krymtkts&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$AWSLogin&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;AWS&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$c&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-STSSessionToken&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-SerialNumber&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-IAMMFADevice&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-UserName&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$user&lt;/span&gt;).SerialNumber &lt;span class=&quot;hljs-literal&quot;&gt;-TokenCode&lt;/span&gt; (op item get &lt;span class=&quot;hljs-variable&quot;&gt;$AWSLogin&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--otp&lt;/span&gt;) &lt;span class=&quot;hljs-literal&quot;&gt;-ProfileName&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$user&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$env:AWS_ACCESS_KEY_ID&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$c&lt;/span&gt;.AccessKeyId&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$env:AWS_SECRET_ACCESS_KEY&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$c&lt;/span&gt;.SecretAccessKey&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$env:AWS_SESSION_TOKEN&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$c&lt;/span&gt;.SessionToken
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;楽～。これは PowerShell の profile に関数書いておいた。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;AWS-Tools-for-PowerShell-profile-&quot; href=&quot;#AWS-Tools-for-PowerShell-profile-&quot;&gt;AWS Tools for PowerShell は自動補完で一覧する profile を絞り込んでる&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;.aws/credentials&lt;/code&gt; にこういう profile があるとする。これ、 &lt;code&gt;mfa_serial&lt;/code&gt; が紛れ込んでる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;hljs-section&quot;&gt;[profile]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;aws_access_key_id&lt;/span&gt; = XXXXXXXXXXXXXXXXXXXX&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;aws_secret_access_key&lt;/span&gt; = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&lt;br /&gt;&lt;span class=&quot;hljs-attr&quot;&gt;mfa_serial&lt;/span&gt; = xxx
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;AWS CLI のタブ補完コマンド &lt;code&gt;aws_completer&lt;/code&gt; はこういうのがあっても問題なく profile を一覧できるが、 AWS Tools for PowerShell では一覧されなくなる。 &lt;code&gt;mfa_serial&lt;/code&gt; 以外には &lt;code&gt;role_arn&lt;/code&gt;, &lt;code&gt;source_profile&lt;/code&gt; があると一覧されなくなる。&lt;/p&gt;
&lt;p&gt;これ初めて知った。今後は、書き間違ってるから一覧されないんだ～と思いつくことができるが、一発目だったのでとても時間がかかった。ドキュメントに書いてる挙動なんかな～しらんけど。今度調べたい(いつ)。&lt;/p&gt;
&lt;p&gt;続くかも。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 23 Apr 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-04-16-convert-hatena-xml-to-md.html</guid><link>https://krymtkts.github.io/posts/2022-04-16-convert-hatena-xml-to-md.html</link><title>古のはてなダイアリー XML を Markdwon に変換する(いい感じに)</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;先日 Google ドライブの中に眠っていた XML を発掘した。古のはてなダイアリーからエクスポートされたやつだこれ。&lt;/p&gt;
&lt;p&gt;昔、プレーンテキストで日記をつけ始める前に、誰に見せるでもないブログを書いていた。何度かブログサービスに書いては止めるを繰り返していた。
そのうち最も最近までやってたのがはてなダイアリーで、そのバックアップがこれっぽい。
178 記事、2009 ~ 2011 の 3 年間もあるのに、すっかり忘れていた。&lt;/p&gt;
&lt;p&gt;これはぜひ今の日記に統合したい。ということではてなダイアリーの XML を Markdown に変換して取り込むことにした。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;変換する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;今回は Pandoc を使わず純粋に PowerShell だけで処理する。
Pandoc で&lt;a href=&quot;https://help.hatenablog.com/entry/text-hatena-list&quot; title=&quot;はてな記法&quot;&gt;はてな記法&lt;/a&gt;から Markdown に変換できるが、ごく一部の記事は既に日記があって追記しないといけないこともあり、PowerShell だけでやる方が融通が利く。&lt;/p&gt;
&lt;p&gt;XML なら PowerShell の主戦場なので、何をするにも楽だ。
使っているはてな記法もおおよそパターンマッチで置換できる(鬼の連続置換)。&lt;/p&gt;
&lt;p&gt;引用だけ正規表現での変換がわからんけど、一桁件数しかなかったので、手で書き換える。&lt;/p&gt;
&lt;p&gt;以下変換スクリプト。 &lt;code&gt;hatena2md.ps1&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;br /&gt;        &lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;,&lt;br /&gt;        &lt;span class=&quot;hljs-type&quot;&gt;HelpMessage&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;XML Path of hatena diary.&amp;quot;&lt;/span&gt;)]&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;ValidateScript&lt;/span&gt;({&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;if&lt;/span&gt; (-&lt;span class=&quot;hljs-type&quot;&gt;Not&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt;) -&lt;span class=&quot;hljs-type&quot;&gt;or&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; -&lt;span class=&quot;hljs-type&quot;&gt;notmatch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\.xml&amp;quot;&lt;/span&gt;)) {&lt;br /&gt;                &lt;span class=&quot;hljs-type&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;The file specified in the XmlPath argument must be XML.&amp;quot;&lt;/span&gt;&lt;br /&gt;            }&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$True&lt;/span&gt;&lt;br /&gt;        })]&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;System.IO.FileInfo&lt;/span&gt;]&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$XmlPath&lt;/span&gt;,&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;br /&gt;        &lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt;,&lt;br /&gt;        &lt;span class=&quot;hljs-type&quot;&gt;HelpMessage&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Output Path of Markdown diaries.&amp;quot;&lt;/span&gt;)]&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;ValidateScript&lt;/span&gt;({&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;if&lt;/span&gt; (-&lt;span class=&quot;hljs-type&quot;&gt;Not&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; ) -&lt;span class=&quot;hljs-type&quot;&gt;or&lt;/span&gt; -&lt;span class=&quot;hljs-type&quot;&gt;not&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; -&lt;span class=&quot;hljs-type&quot;&gt;PathType&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Container&lt;/span&gt;)) {&lt;br /&gt;                &lt;span class=&quot;hljs-type&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;The BlogPath argument must be a folder.&amp;quot;&lt;/span&gt;&lt;br /&gt;            }&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$True&lt;/span&gt;&lt;br /&gt;        })]&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;System.IO.FileInfo&lt;/span&gt;]&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$BlogPath&lt;/span&gt;&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$xml&lt;/span&gt; = [&lt;span class=&quot;hljs-built_in&quot;&gt;XML&lt;/span&gt;](&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$XmlPath&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Convert &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$xml&lt;/span&gt;.diary.day.Length) hatena XML to Markdown.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$xml&lt;/span&gt;.diary.day | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$date&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.date &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; SilentlyContinue&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;?) {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Error&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Cannot convert diary of &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.date)&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$diaryPath&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$BlogPath&lt;/span&gt;/&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$date&lt;/span&gt;.Year)/&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$date&lt;/span&gt;.ToString(&amp;#x27;yyyy-MM&amp;#x27;))/&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$date&lt;/span&gt;.toString(&amp;#x27;dd&amp;#x27;)).md&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$diaryPath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; SilentlyContinue | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;?) {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Add Content to exists diary of &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.date)&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$InvokeContent&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Add-Content&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$content&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;@&amp;quot;&lt;br /&gt;&lt;br /&gt;## はてなの日記&lt;br /&gt;&lt;br /&gt;&amp;quot;@&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Create new diary of &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.date)&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$InvokeContent&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Set-Content&amp;#x27;&lt;/span&gt;&lt;br /&gt;        mkdir &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Split-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$diaryPath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parent&lt;/span&gt;) | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$content&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;@&amp;quot;&lt;br /&gt;# &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$date&lt;/span&gt;.ToString(&amp;#x27;yyyy-MM/dd (ddd)&amp;#x27;))&lt;br /&gt;&lt;br /&gt;## はてなの日記&lt;br /&gt;&lt;br /&gt;&amp;quot;@&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$content&lt;/span&gt; += (&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.body &lt;span class=&quot;hljs-operator&quot;&gt;-split&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; `&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;^\*\d+\*(.+)$&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;### `$1`n&amp;quot;&lt;/span&gt; `&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;^=+$&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n---`n&amp;quot;&lt;/span&gt; `&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;^--(.+)&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;    - $1&amp;#x27;&lt;/span&gt; `&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;^-(.+)&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;- $1&amp;#x27;&lt;/span&gt; `&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;^\+\+(.+)&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;    1. $1&amp;#x27;&lt;/span&gt; `&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;^\+(.+)&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;1. $1&amp;#x27;&lt;/span&gt; `&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\&amp;gt;\|(\w+)\|&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n```````$1&amp;quot;&lt;/span&gt; `&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;(\&amp;gt;\|\||\&amp;gt;\|)&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n``````&amp;quot;&lt;/span&gt; `&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;(\|\|\&amp;lt;|\|\&amp;lt;)&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;```````n&amp;quot;&lt;/span&gt; `&lt;br /&gt;                &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\[(.+?)\:title=(.+?)]&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;[$2]($1)&amp;#x27;&lt;/span&gt;&lt;br /&gt;        }) &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$content&lt;/span&gt; | &amp;amp; &lt;span class=&quot;hljs-variable&quot;&gt;$InvokeContent&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$diaryPath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Encoding&lt;/span&gt; utf8 &lt;span class=&quot;hljs-literal&quot;&gt;-NoNewline&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;はてなダイアリーの XML から、自分の日記の構造に変換している。
はてなダイアリーの記事にはわかりやすく「はてなの日記」というセクションを設ける。&lt;/p&gt;
&lt;p&gt;基本ファイルを作成するが、既存のファイルが存在する場合は、追記する。
先述の通りセクションがあるので追記しても自然だ。&lt;/p&gt;
&lt;p&gt;ディレクトリ構造は&lt;a href=&quot;/posts/2022-04-02-convert-textile-to-md.html&quot; title=&quot;前回の Textile → Markdown 変換&quot;&gt;前回の Textile → Markdown 変換&lt;/a&gt; で記した通り ↓ 。 1 つの XML からこの形にファイルを出力する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;+---2013&lt;br /&gt;|   +---2013-01&lt;br /&gt;|   |       17.textile&lt;br /&gt;|   ︙      ︙&lt;br /&gt;︙&lt;br /&gt;\---2022&lt;br /&gt;   +---2022-01&lt;br /&gt;   ︙&lt;br /&gt;   \---2022-03&lt;br /&gt;            01.md&lt;br /&gt;            ︙&lt;br /&gt;            31.md
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;. .\hatena2md.ps1 &lt;span class=&quot;hljs-literal&quot;&gt;-XmlPath&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$XmlPath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-BlogPath&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$BlogPath&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;変換後の処理&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;変換後のファイルから&lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; で検索して該当するものを一覧し、書き換える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; | ? {&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; | % {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-split&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n&amp;quot;&lt;/span&gt;} | ? {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;^&amp;gt;&amp;gt;&amp;#x27;&lt;/span&gt;}} | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; FullName
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ココに来て順序付きリストの数字をやっぱりインクリメントしたい(前のステップでは&lt;code&gt;1.&lt;/code&gt;固定でいいかと思ってた)...ということで一部書き直した。&lt;/p&gt;
&lt;p&gt;最後に全体を &lt;a href=&quot;https://prettier.io/&quot; title=&quot;Prettier&quot;&gt;Prettier&lt;/a&gt; で清書する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;prettier &lt;span class=&quot;hljs-literal&quot;&gt;--write&lt;/span&gt; .
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最終チェックをして完了。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;まとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Textile からの変換よりも、量が 1/10 程度と少なかったこともあり、簡単にできた。&lt;/p&gt;
&lt;p&gt;コンテンツそれ自体は中々に青臭く、読んでると「わー！！！」と声を上げたくなるところもある。
ただ人生の転機が集中した期間だったこともあって、興味深い内容だった。貴重なログなので、これまた自己分析に使いたい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 16 Apr 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-04-09-jobchange-2022.html</guid><link>https://krymtkts.github.io/posts/2022-04-09-jobchange-2022.html</link><title>転職した 2022</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;また転職した。&lt;a href=&quot;/posts/2021-09-28-jobchange-2021.html&quot; title=&quot;前回の転職&quot;&gt;前回の転職&lt;/a&gt;から半年しか経ってないけど。&lt;/p&gt;
&lt;p&gt;退職前に諸々の誓約書に署名してるので諸々の守秘義務があり、多くを語ることはできない。
結構高く評価してもらってたのに辞めた理由を語るとすれば、ただひとえに「音楽性の違い」が原因かな。
あ、入社して知り合った 1 ヶ月パイセンが信頼のおける人だったのは良かった。&lt;/p&gt;
&lt;p&gt;幸運にも、より良い条件で次のご縁があったので、これは自分の真摯な姿勢が信頼を紡いできたおかげなんかなーと自分自身を讃えてみる。讃えてみるテスト。&lt;/p&gt;
&lt;p&gt;結果的にジョブホッパーみたいになってしまったから、ヘッドハンター()とかには「キャリアに傷がついてる」とかいちびられそうだが、こちとら仕事はちゃんと納めたからええのよ。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;この半年の間で伸びたところもなくはないけど、結構停滞感みたいなのを感じていた。
結局半年の間、技術情報を交換したり意見することもないし、あらゆる権限がなくて何なら自分の Google アカウントのアバターを変更する権限もなかった。全然人に会うこともなくコミュニケーションは週 1 回くらいとかだったので、初対面の人と会話したり、単に送るメッセージ考えるのも疲れるというのが現状。&lt;/p&gt;
&lt;p&gt;自分の職掌にはクラウドの「ク」もなく、全く触ることがなかったので、使っていない筋肉が随分衰えてしまった。
細かいことを忘れてるので、現職でしょーもないことであっても「アレ？どうやっけ？」となったりする。まだリハビリ中。&lt;/p&gt;
&lt;p&gt;また、ビジネスサイドの声から遠ざかっていたことで、言葉の理解力とか肌感覚が鈍った気がする。ここもリハビリ中。&lt;/p&gt;
&lt;p&gt;たった 1 週間程働いてみこの感覚なので、これからも他の衰えに気づくことが度々あるだろう。&lt;/p&gt;
&lt;p&gt;いずれの衰えも「強くてニューゲーム」できると嬉しいけど、そこはやってみないとわからんから、ただただ真摯に取り組むのみやな。自分の変化に気づけてるだけでアドバンテージかな。&lt;/p&gt;
&lt;p&gt;それにしても久しぶりに「仕事してる！」という実感があって良い。これはまさに「音楽性」が一致した結果なんかな。しらんけど。&lt;/p&gt;
&lt;p&gt;ただのポエムになった。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 09 Apr 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-04-02-convert-textile-to-md.html</guid><link>https://krymtkts.github.io/posts/2022-04-02-convert-textile-to-md.html</link><title>Textile を Markdown に変換する(いい感じに)</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;プレーンテキストで日記をつけ始めて今年で 9 年目になったぽい。
その日記だが、昔 Redmine を使ってたこともあって、最初の 5 年位の間 &lt;a href=&quot;https://textile-lang.com/&quot; title=&quot;Textile&quot;&gt;Textile&lt;/a&gt; で日記を書いていた時期がある。
この頃の文書を Markdown に変換したいと度々思っていたが、最近重い腰を上げて取り組み始めた。&lt;/p&gt;
&lt;p&gt;マークアップ言語の相互変換といえば、やはり Haskell で書かれた &lt;a href=&quot;https://pandoc.org/&quot; title=&quot;Pandoc&quot;&gt;Pandoc&lt;/a&gt; やろーというのが個人的なイメージ。簡単なケースで永らく使ってきたが、今回は困ったというか一筋縄ではいかない点が出てきた。&lt;/p&gt;
&lt;p&gt;例えば、 Pandoc で過去の日記を Textile から Markdown に変換するとしたらこんな感じのコマンドになる。&lt;/p&gt;
&lt;p&gt;(以降は視認性を確保するため、実際に実行したコマンドに改行を含めて記載する)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;pandoc &lt;span class=&quot;hljs-literal&quot;&gt;--from&lt;/span&gt;=textile &lt;span class=&quot;hljs-literal&quot;&gt;--to&lt;/span&gt;=gfm+east_asian_line_breaks `&lt;br /&gt;       &lt;span class=&quot;hljs-literal&quot;&gt;--shift-heading-level-by&lt;/span&gt;=&lt;span class=&quot;hljs-literal&quot;&gt;-4&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--eol&lt;/span&gt;=lf &lt;span class=&quot;hljs-literal&quot;&gt;--wrap&lt;/span&gt;=preserve `&lt;br /&gt;       ./diary.textile &lt;span class=&quot;hljs-literal&quot;&gt;--output&lt;/span&gt;=./diary.md
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;参照 &lt;a href=&quot;https://pandoc.org/MANUAL.html&quot; title=&quot;Pandoc - Pandoc User’s Guide&quot;&gt;Pandoc - Pandoc User’s Guide&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;結構いい感じの結果を導くオプションの組み合わせに手間取った。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;改行に半角スペース 2 つを使い、表の syntax も使うので &lt;code&gt;gfm+east_asian_line_breaks&lt;/code&gt;&lt;/li&gt;&lt;li&gt;見出しのレベルを変えるための &lt;code&gt;shift-heading-level-by=-4&lt;/code&gt; を指定&lt;ul&gt;
&lt;li&gt;Redmine の見た目上 &lt;code&gt;h5.&lt;/code&gt; にしてた(確か)&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;改行コードは LF で統一する &lt;code&gt;--eol=lf&lt;/code&gt;&lt;/li&gt;&lt;li&gt;長い行に空白があると折り返そうとするので &lt;code&gt;--wrap=preserve&lt;/code&gt; 原文を維持する&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;仮に日記が以下のような記述とする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;h5. 見出し&lt;br /&gt;&lt;br /&gt;# 順序付きリスト1&lt;br /&gt;** 箇条書きリスト1-1&lt;br /&gt;# 順序付きリスト2&lt;br /&gt;** bullet listアイテム2-1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&lt;br /&gt;* 箇条書きリスト3&lt;br /&gt;## 箇条書きリスト3-1&lt;br /&gt;箇条書きリスト3-1の 改行したコンテンツ&lt;br /&gt;&lt;br /&gt;* *箇条書きリスト2*&lt;br /&gt;箇条書きリスト2。&lt;br /&gt;|_.行1|1|&lt;br /&gt;|_.行2|20|&lt;br /&gt;&lt;br /&gt;* *箇条書きリスト3*&lt;br /&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;コード&lt;br /&gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;テキスト&lt;br /&gt;&lt;br /&gt;|_.行1|1|&lt;br /&gt;|_.行2|20|&lt;br /&gt;&lt;br /&gt;    |_.行1|1|&lt;br /&gt;    |_.行2|20|&lt;br /&gt;&lt;br /&gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;#x27;sh&amp;#x27;&amp;gt;&lt;br /&gt;コード&lt;br /&gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これを先述のコマンドで Textile から Markdown に変換すると...&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;hljs-section&quot;&gt;# 見出し&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;\# 順序付きリスト1&lt;br /&gt;&lt;br /&gt;箇条書きリスト1-1&lt;br /&gt;&lt;br /&gt;\# 順序付きリスト2&lt;br /&gt;&lt;br /&gt;bullet listアイテム2-1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt;   箇条書きリスト3&lt;br /&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;    1.&lt;/span&gt;  箇条書きリスト3-1  &lt;br /&gt;&lt;span class=&quot;hljs-code&quot;&gt;        箇条書きリスト3-1の 改行したコンテンツ&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;!-- --&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt;   &lt;span class=&quot;hljs-strong&quot;&gt;**箇条書きリスト2**&lt;/span&gt;  &lt;br /&gt;&lt;span class=&quot;hljs-code&quot;&gt;    箇条書きリスト2。  &lt;br /&gt;    \|\_.行1\|1\|  &lt;br /&gt;    \|\_.行2\|20\|&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;!-- --&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt;   &lt;span class=&quot;hljs-strong&quot;&gt;**箇条書きリスト3**&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-code&quot;&gt;        コード&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-code&quot;&gt;      &lt;br /&gt;    テキスト&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;| 行1 | 1   |&lt;br /&gt;|-----|-----|&lt;br /&gt;| 行2 | 20  |&lt;br /&gt;&lt;br /&gt;\|\&lt;span class=&quot;hljs-emphasis&quot;&gt;_.行1\|1\|  &lt;br /&gt;\|\_&lt;/span&gt;.行2\|20\|&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-code&quot;&gt;    &amp;lt;code class=&amp;#x27;sh&amp;#x27;&amp;gt;&lt;br /&gt;    コード&lt;br /&gt;    &amp;lt;/code&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このように、おもしろいことになる。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;順序付きリストと箇条書きリストが同じレベルに存在すると、後ろの方(この場合箇条書きリスト)しか変換できない&lt;ul&gt;
&lt;li&gt;これは事前に混在するリストを Textile から取り除くしかないか&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;リストと文の間の過剰な空白が気持ち悪い&lt;ul&gt;
&lt;li&gt;まだどうにかできそうなオプションを見つけられていないので、これは Textile -&amp;gt; Markdown 変換後に Prettier で変換する必要があるか&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;新たに挿入された謎の HTML コメントの行は、以下の Pandoc の仕様によるらしい&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pandoc.org/MANUAL.html#ending-a-list&quot; title=&quot;Ending a list | Pandoc - Pandoc User’s Guide&quot;&gt;Ending a list | Pandoc - Pandoc User’s Guide&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;blockquote&gt;
&lt;p&gt;To “cut off” the list after item two, you can insert some non-indented content, like an HTML comment, which won’t produce visible output in any format:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;表の変換は、箇条書きに連続しない＆インデントされていない箇所に限り、 Markdown の Table Syntax に変換される&lt;/li&gt;&lt;li&gt;当時の Redmine で使えなかったこともあり、コードブロックを &lt;code&gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;#39;lang&amp;#39;&amp;gt;&lt;/code&gt; で表現していた。これが Markdown に変換したとき &lt;code&gt;pre&lt;/code&gt; 要素だけ解釈されてしまう&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;1,4 は Pandoc で変換をかける前に手で直さざるを得ないので、正規表現に引っかかる範囲は一括変換をかける。1000 超える Textile ファイルがあるので流石に手作業は無理、可能な限り一括変換や。&lt;/p&gt;
&lt;p&gt;2, 3, 5 は変換後に対処する。これも機械的にどうにでもできそうか。&lt;/p&gt;
&lt;p&gt;日記のディレクトリ構造はこのような形になっており、変換作業はルートディレクトリから行う。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;+---2013&lt;br /&gt;|   +---2013-01&lt;br /&gt;|   |       17.textile&lt;br /&gt;|   |       18.textile&lt;br /&gt;|   ︙      ︙&lt;br /&gt;|   \---2013-12&lt;br /&gt;︙&lt;br /&gt;\---2022&lt;br /&gt;   +---2022-01&lt;br /&gt;   ︙&lt;br /&gt;   \---2022-03&lt;br /&gt;            01.md&lt;br /&gt;            ︙&lt;br /&gt;            31.md
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(色々 try &amp;amp; error して変換していたので、 入力の手間を省く目的でわかりきったコマンドはエイリアスを多用している)&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;4-&quot; href=&quot;#4-&quot;&gt;4 の解消&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;インデントされている表はなかったが、箇条書きの後に表が記載されているパターンがあり、そのうち、以下の 2 パターンがあった。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;箇条書き直後に表がある&lt;/li&gt;&lt;li&gt;箇条書きの後、更に文を挟んだ後に表がある&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;この 2 を引っ掛けるパターンを書くのに難儀した。
何故なら、表の syntax の行末に余分に空白や不要な文字がついていて、どうにもわたしの正規表現力では引っ掛けられない。&lt;/p&gt;
&lt;p&gt;どうにもうまくできないので妥協して、 2 回に分けて変換する。&lt;/p&gt;
&lt;p&gt;1 については雑ながらも一括変換可能。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; *.textile |&lt;br /&gt;? {(&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName ) &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;sls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Pattern&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;(\*|#).+\n\|&amp;#x27;&lt;/span&gt;} |&lt;br /&gt;%{&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName&lt;br /&gt;    ((&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;((\*|#).+\n)(\|)&amp;#x27;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`$1`n`$3&amp;quot;&lt;/span&gt; |&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NoNewline&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;改行コードは LF を使うので &lt;code&gt;-NoNewLine&lt;/code&gt; だ。&lt;/p&gt;
&lt;p&gt;2 はリストアップして清書がてら手メンテ...&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ファイル一覧をクリップボードへ&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; *.textile | ? {&lt;br /&gt;    (&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName ) &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;sls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Pattern&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\n[^\*#\|].+\n\|&amp;#x27;&lt;/span&gt;&lt;br /&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; FullName | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Clipboard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;1-&quot; href=&quot;#1-&quot;&gt;1 の解消&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Textile を見るに、箇条書きの後に太字 &lt;code&gt;*〇〇*&lt;/code&gt; を書いて見出しの代わりにしたかったような気配がするので、それを除外した順序づき/箇条書きリストを変換の対象にする。&lt;/p&gt;
&lt;p&gt;番号を参照していたりすると文脈が失われるので、一括変換できるか対象 23 件を目検したところ、レベル誤りだったり単に順序付きリストにし忘れているだけの箇所だったり。
それぞれに対処の仕方が異なるので、仕方ないがリストアップした対象を清書がてら手メンテ(2 回目)...&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ファイル一覧をクリップボードへ&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; *.textile | ? {&lt;br /&gt;    (&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName | ? {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;(^\*\s[^\*]|^#\s[^\*])&amp;#x27;&lt;/span&gt;}) &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n&amp;quot;&lt;/span&gt; |&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;sls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Pattern&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;(\*.+\n#|#.+\n\*)&amp;#x27;&lt;/span&gt;&lt;br /&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; FullName | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Clipboard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;Textile-gt-Markdown-&quot; href=&quot;#Textile-gt-Markdown-&quot;&gt;Textile -&amp;gt; Markdown の変換&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;先述の通りのオプションで Pandoc を実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; *.textile | %{&lt;br /&gt;    pandoc `&lt;br /&gt;        &lt;span class=&quot;hljs-literal&quot;&gt;--from&lt;/span&gt;=textile &lt;span class=&quot;hljs-literal&quot;&gt;--to&lt;/span&gt;=gfm+east_asian_line_breaks `&lt;br /&gt;        &lt;span class=&quot;hljs-literal&quot;&gt;--shift-heading-level-by&lt;/span&gt;=&lt;span class=&quot;hljs-literal&quot;&gt;-4&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--eol&lt;/span&gt;=lf `&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName &lt;span class=&quot;hljs-literal&quot;&gt;--output&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Directory)\&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name -replace &amp;#x27;textile&amp;#x27;,&amp;#x27;md&amp;#x27;)&amp;quot;&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;3-&quot; href=&quot;#3-&quot;&gt;3 の解消&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;変換後、まず最初に &lt;code&gt;&amp;lt;!-- --&amp;gt;&lt;/code&gt; を取り除く。最後に Prettier を実行してきれいな状態にしたいからだ。&lt;/p&gt;
&lt;p&gt;置換対象が Pandoc によって追加されたコメントだけなのか調べる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; *.md | % {&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName | &lt;span class=&quot;hljs-built_in&quot;&gt;sls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Pattern&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;^&amp;lt;!--.+--&amp;gt;&amp;#x27;&lt;/span&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;group&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Count Name                      &lt;span class=&quot;hljs-built_in&quot;&gt;Group&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                      &lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;hljs-number&quot;&gt;2275&lt;/span&gt; &amp;lt;!&lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt;&amp;gt;                  {&amp;lt;!&lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt;&amp;gt;, &amp;lt;!&lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt;&amp;gt;, &amp;lt;!&lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt;&amp;gt;, &amp;lt;!&lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt;&amp;gt;…}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;問題ないようなので一括置換する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; *.md | ? {&lt;span class=&quot;hljs-built_in&quot;&gt;sls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName &lt;span class=&quot;hljs-literal&quot;&gt;-Pattern&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;^&amp;lt;!--.+--&amp;gt;&amp;#x27;&lt;/span&gt;} | %{&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName&lt;br /&gt;    (&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt; | ? {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-notmatch&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;^&amp;lt;!--.+--&amp;gt;&amp;#x27;&lt;/span&gt;}) &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n&amp;quot;&lt;/span&gt; |&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NoNewline&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この一括変換結果、1000 超のファイルの差分に問題ないか &lt;code&gt;git diff --word-diff&lt;/code&gt; で見る。流石に多いので変更をグルーピングして見た。全部同じ変換結果なら1つにまとまる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;git &lt;span class=&quot;hljs-built_in&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--word-diff&lt;/span&gt; | ? {&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\[(\+|-)&amp;#x27;&lt;/span&gt;} | &lt;span class=&quot;hljs-built_in&quot;&gt;group&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この置換により HTML コメント削除後は空行が 2 行になり、かつ文末の改行が消えてしまうが、後に行う Prettier で補修される(はず)。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;5-&quot; href=&quot;#5-&quot;&gt;5 の解消&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;幸い、&lt;code&gt;class&lt;/code&gt; 属性なしの &lt;code&gt;code&lt;/code&gt; タグはなかった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;code class=&amp;quot;${language}&amp;quot;&lt;/code&gt; → &lt;code&gt;```${language}&lt;/code&gt; 、 &lt;code&gt;&amp;lt;/code&amp;gt;&lt;/code&gt; → &lt;code&gt;```&lt;/code&gt; へ変換する。一緒にやるイメージがなかったので 2 回置換する。
同時に、&lt;code&gt;pre&lt;/code&gt; タグが変換されたことによる半角スペース 4 個 があると文章のインデントと合わず正しくレンダリングできないので、取り除く。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; *.md | ? {&lt;span class=&quot;hljs-built_in&quot;&gt;sls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName &lt;span class=&quot;hljs-literal&quot;&gt;-Pattern&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;lt;code class=&amp;#x27;&lt;/span&gt;} | % {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName&lt;br /&gt;    (&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt; | % {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\s{0,4}&amp;lt;code class=&amp;quot;(\w+)&amp;quot;&amp;gt;&amp;#x27;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;```$1&amp;#x27;&lt;/span&gt; `&lt;br /&gt;           &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\s{0,4}&amp;lt;/code&amp;gt;&amp;#x27;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;```&amp;#x27;&lt;/span&gt;&lt;br /&gt;    }) &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;`n&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NoNewline&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;2-&quot; href=&quot;#2-&quot;&gt;2 の解消&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://prettier.io/&quot; title=&quot;Prettier&quot;&gt;Prettier&lt;/a&gt; を使う。数年前から Markdown の整形に使っているのでそれに合わせる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ForEach-Object&lt;/code&gt; して 1 ファイルずつ &lt;code&gt;prettier&lt;/code&gt; を実行するとそこそこに遅い。 &lt;a href=&quot;https://en.wikipedia.org/wiki/Glob_(programming)&quot; title=&quot;glob&quot;&gt;glob&lt;/a&gt; にまとめた方が速く実行できるので、ちょっとパターンが雑だがそのようにする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;prettier &lt;span class=&quot;hljs-literal&quot;&gt;--write&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;**/{&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;((&lt;br /&gt;    ls -Recurse -File *.textile | select -ExpandProperty DirectoryName |&lt;br /&gt;    Split-Path -Leaf | group | select -ExpandProperty Name ) -join &amp;#x27;,&amp;#x27;)}/*.md&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;が、先述のコマンドを実行したあとでPrettier 導入前から Markdown で書いていた古い日記もあまり綺麗でないことが判明した。
なので、全体的に整形してしまう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;prettier &lt;span class=&quot;hljs-literal&quot;&gt;--write&lt;/span&gt; .
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このとき箇条書きの書き忘れが見つかった。後述するような箇条書きがあると、 &lt;code&gt;prettier&lt;/code&gt; に見出しと判断されてレイアウトが崩れるので、事前に手で取り除く。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;- Bad な bullet list&lt;br /&gt;  -
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;最終チェック&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ココまで来たらもう大丈夫やろう、という感じで最終チェックしてたら、ココに来て痛恨のミス。
どうも箇条書き/順序付きリストの階層を誤っていると変換に失敗するようだった。 
1 の解消のときに回収しきれていないかった。&lt;/p&gt;
&lt;p&gt;before.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;** 壊れる箇条書きリスト&lt;br /&gt;#### 壊れる順序付きリスト
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;after.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;壊れる箇条書きリスト&lt;br /&gt;&lt;br /&gt;\#### 壊れる順序付きリスト
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;調べてみたら 50 ファイルくらい結構派手にぶち壊れている部分があった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; *.md | ? {&lt;span class=&quot;hljs-built_in&quot;&gt;sls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName &lt;span class=&quot;hljs-literal&quot;&gt;-Pattern&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\\(\*|#)\s&amp;#x27;&lt;/span&gt;} |&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; FullName
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これらは textile の段階から手直しし、 Textile → Markdown の変換からやり直す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; *.md | ? {&lt;span class=&quot;hljs-built_in&quot;&gt;sls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName &lt;span class=&quot;hljs-literal&quot;&gt;-Pattern&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\\(\*|#)\s&amp;#x27;&lt;/span&gt;} | % {&lt;br /&gt;    pandoc `&lt;br /&gt;        &lt;span class=&quot;hljs-literal&quot;&gt;--from&lt;/span&gt;=textile &lt;span class=&quot;hljs-literal&quot;&gt;--to&lt;/span&gt;=gfm+east_asian_line_breaks `&lt;br /&gt;        &lt;span class=&quot;hljs-literal&quot;&gt;--shift-heading-level-by&lt;/span&gt;=&lt;span class=&quot;hljs-literal&quot;&gt;-4&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--eol&lt;/span&gt;=lf `&lt;br /&gt;        (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName &lt;span class=&quot;hljs-operator&quot;&gt;-replace&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;.md&amp;#x27;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;.textile&amp;#x27;&lt;/span&gt;) &lt;span class=&quot;hljs-literal&quot;&gt;--output&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.FullName)&amp;quot;&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この後で先に行っていた 2,3,5 の変換をすれば、期待の変換結果が得られた。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;後始末&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;最後に、残しておいた Textile を全て削除する。当然、削除対象が正しいことを確認した後に消す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Dry run.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; * &lt;span class=&quot;hljs-literal&quot;&gt;-Include&lt;/span&gt; *.textile &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-WhatIf&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Execution.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; * &lt;span class=&quot;hljs-literal&quot;&gt;-Include&lt;/span&gt; *.textile &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;まとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;なかなか手間がかかったが、うまくできた。
今回の移行作業の中で、検知していない見落としもあるはずなので、そういうものは見つけたときに対処するものとする。&lt;/p&gt;
&lt;p&gt;以下気づき。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pandoc のオプションが大量にあり選ぶのが大変だが、おかげで期待する変換がしやすい&lt;ul&gt;
&lt;li&gt;2013 年位からちょくちょく使うがこんなにゴテゴテとオプションをつけたのは初めて&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;「息の長くなりそうなドキュメント」は事前にわからないので、普段からきれいなフォーマットにすれば、後々変換する機会があっても手間が省ける&lt;/li&gt;&lt;li&gt;プレーンテキストは正義&lt;/li&gt;&lt;li&gt;複数行またがるタイプの正規表現のパターン記述力が足りない&lt;/li&gt;&lt;li&gt;日記に事象と感情の変化をセットで書いていたので、あとから見ても面白い。自己分析に使えそう&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;</description><pubDate>Sat, 02 Apr 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-03-26-merge-blog-repo.html</guid><link>https://krymtkts.github.io/posts/2022-03-26-merge-blog-repo.html</link><title>Blog 用 Git repositories のマージ</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2022-03-05-customize-cryogen.html&quot; title=&quot;Cryogen の更新&quot;&gt;Cryogen の更新&lt;/a&gt; で 2 つに別れていた repo を統合できるようになったので、した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/krymtkts.github.io&quot; title=&quot;krymtkts/krymtkts.github.io&quot;&gt;krymtkts/krymtkts.github.io&lt;/a&gt; に &lt;a href=&quot;https://github.com/krymtkts/blog-cryogen&quot; title=&quot;krymtkts/blog-cryogen&quot;&gt;krymtkts/blog-cryogen&lt;/a&gt; の歴史をすべて引き込む。&lt;/p&gt;
&lt;p&gt;元は 1 つのコンテンツを 2 つに分けてるだけなので、統合は簡単だった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;git &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--create&lt;/span&gt; feature/&lt;span class=&quot;hljs-built_in&quot;&gt;merge-repo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Move existing blog contents.&lt;/span&gt;&lt;br /&gt;mkdir docs&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Exclude&lt;/span&gt; docs | %{&lt;span class=&quot;hljs-built_in&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Name ./docs }&lt;br /&gt;git add .&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Move blog files to &amp;#x27;docs&amp;#x27;.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Merge generator repo.&lt;/span&gt;&lt;br /&gt;git remote add upstream ssh://git@krymtkts.github.com:krymtkts/blog&lt;span class=&quot;hljs-literal&quot;&gt;-cryogen&lt;/span&gt;.git&lt;br /&gt;git fetch upstream&lt;br /&gt;git merge &lt;span class=&quot;hljs-literal&quot;&gt;--allow-unrelated-histories&lt;/span&gt; upstream/master&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# miscellaneous work.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;次に GitHub Pages の Source を &lt;code&gt;/docs&lt;/code&gt; に変えて表示確認する。
PR 作成後、GitHub Pages の対象 branch をマージ用の branch に向けて、 GitHub Actions による deploy を確認した。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GitHub Pages の Source を &lt;code&gt;master&lt;/code&gt; の &lt;code&gt;/(root)&lt;/code&gt;-&amp;gt; &lt;code&gt;feature/merge-repo&lt;/code&gt; の &lt;code&gt;/docs&lt;/code&gt; に変えて deploy 確認&lt;/li&gt;&lt;li&gt;PR をマージ＆ branch を残す&lt;/li&gt;&lt;li&gt;GitHub Pages の Source を &lt;code&gt;feature/merge-repo&lt;/code&gt; の &lt;code&gt;/docs&lt;/code&gt; -&amp;gt; &lt;code&gt;master&lt;/code&gt; の &lt;code&gt;/docs&lt;/code&gt; に変えて deploy 確認&lt;/li&gt;&lt;li&gt;&lt;code&gt;feature/merge-repo&lt;/code&gt; を消す&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;branch を消したときに自動で Source を追随してくれんのかも知れんが、 壊れたら面倒なので 1 手順ずつ確認した。&lt;/p&gt;
&lt;p&gt;スッキリした。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 26 Mar 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-03-19-useful-usafe-of-gist-permalink.html</guid><link>https://krymtkts.github.io/posts/2022-03-19-useful-usafe-of-gist-permalink.html</link><title>Gist の便利な使い方 ~ Permalink</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今更ながら最近知った。 Gist の Raw コンテンツの URL からコミットハッシュを取り除けば常に最新のリビジョンへの Permalink になる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/16589511/how-do-i-get-the-raw-version-of-a-gist-from-github/16589638#16589638&quot; title=&quot;How do I get the raw version of a gist from github? - Stack Overflow&quot;&gt;How do I get the raw version of a gist from github? - Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これを使えば、ローカルで patch を当てるのにめちゃくちゃ役に立つと気づいた。
ダウンロードの保存先を patch したいコード直にしたらそれで終わり。
patch を当てたいファイルの数だけ Gist 作らなあかんやんけ、というのはあれど、あまりに多い場合は Gist の中に複数ファイル置くとかかな。まだその規模まで届いてないのでそこはまあよい。&lt;/p&gt;
&lt;p&gt;これとか。 &lt;a href=&quot;https://krymtkts.github.io/posts/2021-08-30-patch-to-vscode-extension&quot; title=&quot;VS Code の拡張機能に ローカル patch する&quot;&gt;VS Code の拡張機能に ローカル patch する&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;メンテナがもう活動してないっぽくて PR がマージされることもないので、ローカル patch するのが手っ取り早い。&lt;/p&gt;
&lt;p&gt;Gist に変更対象のコードを置いて、こういう関数を作りまして、実行すればパッチが完了する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Edit-EverMonkey&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$evermonkey&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;~\.vscode\extensions\michalyao.evermonkey-2.4.5&amp;#x27;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$evermonkey&lt;/span&gt;) {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Verbose&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;There is no evermonkey.&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$params&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        Uri     = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://gist.githubusercontent.com/krymtkts/8a5a3a5a7e1efe9db7f2c6bbda337571/raw/converterplus.js&amp;#x27;&lt;/span&gt;&lt;br /&gt;        OutFile = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$evermonkey&lt;/span&gt;\out\src\converterplus.js&amp;quot;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; @params&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あとこれ。&lt;a href=&quot;/posts/2021-07-11-my-terminal-icons.html&quot; title=&quot;Terminal-Icons のアイコングリフのコードポイントを変えたい&quot;&gt;Terminal-Icons のアイコングリフのコードポイントを変えたい&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;version up の度にいっつも自分用グリフを上書きしてるけど、それが楽になる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Edit-TerminalIcons&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$ti&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Module&lt;/span&gt; Terminal&lt;span class=&quot;hljs-literal&quot;&gt;-Icons&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ErrorAction&lt;/span&gt; SilentlyContinue&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$ti&lt;/span&gt;) {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Error&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Terminal-Icons not found. install it!&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$params&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        Uri     = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://gist.githubusercontent.com/krymtkts/4457a23124b2db860a6b32eba6490b03/raw/glyphs.ps1&amp;#x27;&lt;/span&gt;&lt;br /&gt;        OutFile = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(Split-Path &lt;span class=&quot;hljs-variable&quot;&gt;$ti&lt;/span&gt;.Path -Parent)\Data\glyphs.ps1&amp;quot;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; @params&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;他に PowerShell の profile も Gist で管理しているので、複数の端末間で共有するのに使っている。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Update-Profile&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$profilehome&lt;/span&gt; = (&lt;span class=&quot;hljs-variable&quot;&gt;$PROFILE&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Split-Path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parent&lt;/span&gt;)&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$params&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;br /&gt;        Uri     = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://gist.githubusercontent.com/krymtkts/f8af667c32b16fc28a815243b316c5be/raw/Microsoft.PowerShell_profile.ps1&amp;#x27;&lt;/span&gt;&lt;br /&gt;        OutFile = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$profilehome&lt;/span&gt;/Microsoft.PowerShell_profile.ps1&amp;quot;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; @params&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-operator&quot;&gt;-not&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$profilehome&lt;/span&gt;\Microsoft.VSCode_profile.ps1&amp;quot;&lt;/span&gt;)) {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;New-Item&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ItemType&lt;/span&gt; HardLink &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$profilehome&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Microsoft.VSCode_profile.ps1&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Value&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$profilehome&lt;/span&gt;\Microsoft.PowerShell_profile.ps1&amp;quot;&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;便利だ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 19 Mar 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-03-13-create-huge-text-file-in-pwsh.html</guid><link>https://krymtkts.github.io/posts/2022-03-13-create-huge-text-file-in-pwsh.html</link><title>PowerShell でクソデカテキストファイルを作る</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;先日、クソデカテキストファイルを作成しなければならない場面があり、以下のスクリプトをしたためた。
Windows なので単にサイズが大きいだけのファイルなら &lt;code&gt;fsutil createnew&lt;/code&gt; を使えるけど、クソデカテキストファイルを作る手段は知らなかったからだ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; kusodeka.txt &lt;span class=&quot;hljs-literal&quot;&gt;-Encoding&lt;/span&gt; ascii &lt;span class=&quot;hljs-literal&quot;&gt;-NoNewline&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Value&lt;/span&gt; (&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x&amp;#x27;&lt;/span&gt; * [&lt;span class=&quot;hljs-type&quot;&gt;Math&lt;/span&gt;]::Pow(&lt;span class=&quot;hljs-number&quot;&gt;1024&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このスクリプト、 Out of Memory でエラー終了する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; kusodeka.txt &lt;span class=&quot;hljs-literal&quot;&gt;-Encoding&lt;/span&gt; ascii &lt;span class=&quot;hljs-literal&quot;&gt;-NoNewline&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Value&lt;/span&gt; (&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x&amp;#x27;&lt;/span&gt; * [&lt;span class=&quot;hljs-type&quot;&gt;Math&lt;/span&gt;]::Pow(&lt;span class=&quot;hljs-number&quot;&gt;1024&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;))&lt;br /&gt;OperationStopped: Exception of &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;System.OutOfMemoryException&amp;#x27;&lt;/span&gt; was thrown.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;どうも文字列の確保できる最大サイズの制限みたい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x&amp;#x27;&lt;/span&gt; * [&lt;span class=&quot;hljs-type&quot;&gt;Math&lt;/span&gt;]::Pow(&lt;span class=&quot;hljs-number&quot;&gt;1024&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;) | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;OperationStopped: Exception of &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;System.OutOfMemoryException&amp;#x27;&lt;/span&gt; was thrown.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;↓ のサイズならいける。 1GB - 32B からはエラーになる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x&amp;#x27;&lt;/span&gt; * ([&lt;span class=&quot;hljs-type&quot;&gt;Math&lt;/span&gt;]::Pow(&lt;span class=&quot;hljs-number&quot;&gt;1024&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;)&lt;span class=&quot;hljs-literal&quot;&gt;-33&lt;/span&gt;) | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;答えは.NET の&lt;code&gt;String&lt;/code&gt;クラスのドキュメントに書いてた →&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.string?redirectedfrom=MSDN&amp;view=net-6.0&quot; title=&quot;String Class (System) | Microsoft Docs&quot;&gt;String Class (System) | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The maximum size of a String object in memory is 2-GB, or about 1 billion characters.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;2GB には到底届いてないし、今回引っかかってるのは後者か。
ほーん、という感じ。最大の文字列長とか考えたこともなかったわ。&lt;/p&gt;
&lt;p&gt;因みにこの最大文字数の超過エラーを回避してクソデカテキストファイルを作るには、以下のようにデータを分割して小分けに書き込みする必要がある。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;1024&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Add-Content&lt;/span&gt; kusodeka.txt &lt;span class=&quot;hljs-literal&quot;&gt;-Encoding&lt;/span&gt; ascii &lt;span class=&quot;hljs-literal&quot;&gt;-NoNewline&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Value&lt;/span&gt; (&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x&amp;#x27;&lt;/span&gt; * [&lt;span class=&quot;hljs-type&quot;&gt;Math&lt;/span&gt;]::Pow(&lt;span class=&quot;hljs-number&quot;&gt;1024&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ついでに調べた PowerShell の配列の上限は、添字の型であろう &lt;code&gt;int&lt;/code&gt; の範囲っぽいがドキュメントは見当たらなかった。これはまた PowerShell のソースコードでも読むか。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# いける&lt;/span&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]::MinValue..[&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]::MaxValue | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# いけない(int の演算エラーかこれ)&lt;/span&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]::MinValue..([&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]::MaxValue + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# &amp;gt; OperationStopped: Value was either too large or too small for an Int32.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# いけない(カッコで評価されちゃい overflow か)&lt;/span&gt;&lt;br /&gt;([&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]::MinValue..[&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;]::MaxValue) | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# OperationStopped: Arithmetic operation resulted in an overflow.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;世の中まだ知らないことがいっぱいあるもんやなあ。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2022-03-15-&quot; href=&quot;#2022-03-15-&quot;&gt;2022-03-15 追記&lt;/a&gt;&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# これが限界ぽい。&lt;/span&gt;&lt;br /&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;2147483591&lt;/span&gt;) | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;2147483592&lt;/span&gt;) | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# OperationStopped: Array dimensions exceeded supported range.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;でエラー。この場合ちゃんと Array の range の問題だとエラーに出る。
カッコを入れてなかったら評価が端折られて期待の振る舞いをしていなかった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.array?view=net-6.0#remarks&quot; title=&quot;Array Class (System) | Microsoft Docs&quot;&gt;Array Class (System) | Microsoft Docs&lt;/a&gt; に記載のカッコの中に該当するわけやな。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The array size is limited to a total of 4 billion elements, and to a maximum index of 0X7FEFFFFF in any given dimension (0X7FFFFFC7 for byte arrays and arrays of single-byte structures).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;[&lt;span class=&quot;hljs-built_in&quot;&gt;long&lt;/span&gt;]::Parse(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;7FFFFFC7&amp;#x27;&lt;/span&gt;,[&lt;span class=&quot;hljs-type&quot;&gt;System.Globalization.NumberStyles&lt;/span&gt;]::HexNumber)&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 2147483591&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;いやー、スッキリした！&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 13 Mar 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-03-05-customize-cryogen.html</guid><link>https://krymtkts.github.io/posts/2022-03-05-customize-cryogen.html</link><title>Cryogen のカスタマイズ</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2022-02-27-issue-with-cryogen-version-bump.html&quot; title=&quot;前回の投稿&quot;&gt;前回の投稿&lt;/a&gt;で、 &lt;a href=&quot;https://cryogenweb.org/&quot; title=&quot;Cryogen&quot;&gt;Cryogen&lt;/a&gt; のバージョンアップに伴い Cryogen 自体のカスタマイズが必要だとを書いた。&lt;/p&gt;
&lt;p&gt;カスタマイズ自体はかなり簡単にできたのだが、 Clojure 経験不足だからか正直なところドキュメントの記載だけではピンと来なかった。
ということで、またわからなくなること必至のため記しておく。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cryogen-core&lt;/code&gt; のバージョンは &lt;code&gt;0.4.1&lt;/code&gt; だ。&lt;/p&gt;
&lt;p&gt;対象のドキュメント &lt;a href=&quot;https://cryogenweb.org/docs/customizing-cryogen.html#customizing-the-code&quot; title=&quot;Cryogen: Customizing/Extending Cryogen&quot;&gt;Cryogen: Customizing/Extending Cryogen&lt;/a&gt; を以下に全文引用する。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can copy the &lt;code&gt;cryogen-core.compiler&lt;/code&gt; namespace directly into your project (where it will override the one from the cryogen-core.jar) and modify it to your liking. It is not very long or complicated and is quite easy to modify. That is &lt;a href=&quot;https://github.com/cryogen-project/cryogen-docs/blob/fd601c857cc88f7cb633a41c47b4c692e1522ed8/src/cryogen/compiler.clj&quot; title=&quot;what we did for this site&quot;&gt;what we did for this site&lt;/a&gt; (although it uses a much older version of cryogen-core, you may still use the same strategy today).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;機械翻訳にリンクを添えた ↓&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;cryogen-core.compiler&lt;/code&gt; 名前空間をプロジェクトに直接コピーし（cryogen-core.jar のものを上書きします）、好みに応じて変更することができます。これはそれほど長くもなく、複雑でもなく、非常に簡単に修正することができます。このサイトでは、&lt;a href=&quot;https://github.com/cryogen-project/cryogen-docs/blob/fd601c857cc88f7cb633a41c47b4c692e1522ed8/src/cryogen/compiler.clj&quot; title=&quot;このような方法&quot;&gt;このような方法&lt;/a&gt;をとっています（かなり古いバージョンの cryogen-core を使用していますが、現在でも同じ方法をとることができます）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;早い話が「Cryogen の公式ページのコードを真似ろ」。&lt;/p&gt;
&lt;p&gt;はじめはナンノコッチャと思ったのだけど、Cryogen の repo のコードを眺めて「&lt;a href=&quot;https://github.com/cryogen-project/cryogen-core/blob/31bcbfdad59e8eaed4a6d417682e51ef1e90982c/src/cryogen_core/compiler.clj&quot; title=&quot;&lt;code&gt;cryogen_core/compiler.clj&lt;/code&gt;&quot;&gt;&lt;code&gt;cryogen_core/compiler.clj&lt;/code&gt;&lt;/a&gt;をコピって自分でサイトジェネレータを書いたらええんやで？」だと理解した。&lt;/p&gt;
&lt;p&gt;Cryogen のエントリポイントは &lt;code&gt;cryogen/core.clj&lt;/code&gt; と &lt;code&gt;cryogen/server.clj&lt;/code&gt; があるが、いずれもサイトジェネレータは &lt;code&gt;cryogen-core.compiler&lt;/code&gt; 名前空間の &lt;code&gt;compile-assets-timed&lt;/code&gt; を呼び出してるだけなので、これを &lt;code&gt;cryogen_core/compiler.clj&lt;/code&gt; からコピった自分用ジェネレータに変える、という趣旨らしい。&lt;/p&gt;
&lt;p&gt;とった手順は以下の通り。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cryogen-project/cryogen-core/blob/31bcbfdad59e8eaed4a6d417682e51ef1e90982c/src/cryogen_core/compiler.clj&quot; title=&quot;&lt;code&gt;cryogen_core/compiler.clj&lt;/code&gt;&quot;&gt;&lt;code&gt;cryogen_core/compiler.clj&lt;/code&gt;&lt;/a&gt; をコピって自分のサイトのコードに &lt;code&gt;src/cryogen/compiler.clj&lt;/code&gt; として配置する&lt;/li&gt;&lt;li&gt;&lt;code&gt;src/cryogen/compiler.clj&lt;/code&gt; を自分の必要な形に書き換える&lt;ul&gt;
&lt;li&gt;今回デフォルトの Cryogen から変えたかったのは、 RSS フィードの要約機能を取り除いて HTML 全文載せるようにすることだった&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/cryogen-project/cryogen-core/blob/31bcbfdad59e8eaed4a6d417682e51ef1e90982c/src/cryogen_core/compiler.clj#L474-L487&quot; title=&quot;&lt;code&gt;add-description&lt;/code&gt;&quot;&gt;&lt;code&gt;add-description&lt;/code&gt;&lt;/a&gt; 関数の中で利用されている &lt;code&gt;util/enlive-&amp;gt;plain-text&lt;/code&gt; を &lt;code&gt;util/enlive-&amp;gt;html-text&lt;/code&gt; に変更、&lt;code&gt;add-description&lt;/code&gt; に依存する関数 &lt;code&gt;compile-assets&lt;/code&gt;, &lt;code&gt;compile-assets-timed&lt;/code&gt; を &lt;code&gt;cryogen.compiler&lt;/code&gt; に定義した&lt;/li&gt;&lt;li&gt;それ以外の関数は &lt;code&gt;cryogen-core.compiler&lt;/code&gt; を参照する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;cryogen/core.clj&lt;/code&gt; と &lt;code&gt;cryogen/server.clj&lt;/code&gt; で、 &lt;code&gt;compile-assets-timed&lt;/code&gt; の名前空間を &lt;code&gt;cryogen-core.compiler&lt;/code&gt; → &lt;code&gt;cryogen.compiler&lt;/code&gt; に変える&lt;/li&gt;&lt;li&gt;&lt;code&gt;lein serve&lt;/code&gt; してエラーがない＆期待の出力になっていれば完了&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;これで概ね自分が期待する出力を得られるようになった(はず)。
気付かないところで破壊的な変更をしているかも知れないので、それは経過観測していく。この投稿をした後で RSS フィードが本当に届くか心配だ。&lt;/p&gt;
&lt;p&gt;あと既知の問題として、新たに追加された &lt;code&gt;lein serve:fast&lt;/code&gt; がちゃんと動いてんのかこれ？ であったり、 Markdown 保存時の再生成が怪しかったりする。
これらは、ちまちま直していきたい。&lt;/p&gt;
&lt;p&gt;これで repo の統合だったり GitHub Action 化が見えてきた。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 05 Mar 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-02-27-issue-with-cryogen-version-bump.html</guid><link>https://krymtkts.github.io/posts/2022-02-27-issue-with-cryogen-version-bump.html</link><title>Cryogen バージョンアップに伴う困りごと</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;このブログを作るのに &lt;a href=&quot;https://github.com/cryogen-project/cryogen&quot; title=&quot;Cryogen&quot;&gt;Cryogen&lt;/a&gt; を利用している。
作った当初から一切のバージョンアップをしていなかったのだが、先週からちまちま手を動かし始めた。&lt;/p&gt;
&lt;p&gt;最近の Cryogen では出力先のディレクトリを指定できる様になっているので、 &lt;code&gt;docs&lt;/code&gt; 出力するようにすれば今 &lt;a href=&quot;https://github.com/krymtkts/blog-cryogen&quot; title=&quot;krymtkts/blog-cryogen&quot;&gt;krymtkts/blog-cryogen&lt;/a&gt; と &lt;a href=&quot;https://github.com/krymtkts/krymtkts.github.io&quot; title=&quot;krymtkts/krymtkts.github.io&quot;&gt;krymtkts/krymtkts.github.io&lt;/a&gt; の 2 つに別れている repo を統合できる。
そも、出力結果を repo の管理下に置かず Github Actions で済ます選択もできるようになるんじゃないかな。&lt;/p&gt;
&lt;p&gt;新しい Cryogen では雛形のディレクトリ構造が変わっているのだが、このバージョンアップによるマイグレーション自体は大したことはない。雑に言えば以下のタスクがあるだけだ。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;新しい Cryogen で雛形を作成する&lt;ul&gt;
&lt;li&gt;雛形に含まれるポストや利用しないテーマ等を取り除いておく&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;既存のコンテンツとテーマを 1 に移動する&lt;ul&gt;
&lt;li&gt;&lt;code&gt;resources\templates\themes&lt;/code&gt; -&amp;gt; &lt;code&gt;themes&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;resources\templates\img&lt;/code&gt; -&amp;gt; &lt;code&gt;content\img&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;resources\templates\md&lt;/code&gt; -&amp;gt; &lt;code&gt;content\md&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;config.edn&lt;/code&gt; 新しいパラメータに書き換える&lt;/li&gt;&lt;li&gt;&lt;code&gt;lein serve&lt;/code&gt; で出力して確認&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;一通り手を動かしてみて、tag へのリンクが壊れたりの細かいバグはあったが、概ね破壊的な変更なく OK やなというところまではできた。&lt;/p&gt;
&lt;p&gt;ところが困ったことに、RSS Feed の出力だけは大きく変わってしまうのを避けられなかった。どうも新しい Cryogen では RSS Feed への出力は要約だけにする仕様に変わったらしい。
ワークアラウンドとして、&lt;code&gt;config.edn&lt;/code&gt; の &lt;code&gt;blocks-per-preview&lt;/code&gt; の数値を大きくすれば要約に全文を含めることはできる。でもそれまで可能だった HTML での埋め込みはできなくなってしまった。
&lt;a href=&quot;https://github.com/cryogen-project/cryogen/issues/241&quot; title=&quot;RSS feed: only publishes article&amp;#39;s &amp;quot;summary&amp;quot; · Issue #241 · cryogen-project/cryogen&quot;&gt;RSS feed: only publishes article&amp;#39;s &amp;quot;summary&amp;quot; · Issue #241 · cryogen-project/cryogen&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;コード的にこの辺。 ページの &lt;code&gt;description&lt;/code&gt; が Feed に出力されるのだが、 plain text 以外の選択肢がない。なんでや。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cryogen-project/cryogen-core/blob/31bcbfdad59e8eaed4a6d417682e51ef1e90982c/src/cryogen_core/compiler.clj#L474-L487&quot; title=&quot;cryogen-core/compiler.clj at 31bcbfdad59e8eaed4a6d417682e51ef1e90982c · cryogen-project/cryogen-core&quot;&gt;cryogen-core/compiler.clj at 31bcbfdad59e8eaed4a6d417682e51ef1e90982c · cryogen-project/cryogen-core&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;add-description&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Add plain text `:description` to the page/post for use in meta description etc.&amp;quot;&lt;/span&gt;&lt;br /&gt;  [{&lt;span class=&quot;hljs-symbol&quot;&gt;:keys&lt;/span&gt; [blocks-per-preview description-include-elements]&lt;br /&gt;    &lt;span class=&quot;hljs-symbol&quot;&gt;:or&lt;/span&gt;   {description-include-elements #{&lt;span class=&quot;hljs-symbol&quot;&gt;:p&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:h1&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:h2&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:h3&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:h4&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:h5&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:h6&lt;/span&gt;}}}&lt;br /&gt;   page]&lt;br /&gt;  (&lt;span class=&quot;hljs-name&quot;&gt;update&lt;/span&gt;&lt;br /&gt;    page &lt;span class=&quot;hljs-symbol&quot;&gt;:description&lt;/span&gt;&lt;br /&gt;    #(&lt;span class=&quot;hljs-name&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cond&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;       (&lt;span class=&quot;hljs-name&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;false?&lt;/span&gt;&lt;/span&gt; %) &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;;; if set via page meta to false, do not set&lt;/span&gt;&lt;br /&gt;       % %    &lt;span class=&quot;hljs-comment&quot;&gt;;; if set via page meta, use it&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;hljs-symbol&quot;&gt;:else&lt;/span&gt; (&lt;span class=&quot;hljs-name&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; (&lt;span class=&quot;hljs-name&quot;&gt;enlive/select&lt;/span&gt;&lt;br /&gt;                    (&lt;span class=&quot;hljs-name&quot;&gt;preview-dom&lt;/span&gt; blocks-per-preview (&lt;span class=&quot;hljs-symbol&quot;&gt;:content-dom&lt;/span&gt; page))&lt;br /&gt;                    [(&lt;span class=&quot;hljs-name&quot;&gt;set&lt;/span&gt; description-include-elements)])&lt;br /&gt;                  (&lt;span class=&quot;hljs-name&quot;&gt;util/enlive-&amp;gt;plain-text&lt;/span&gt;)))))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/cryogen-project/cryogen-core/blob/31bcbfdad59e8eaed4a6d417682e51ef1e90982c/src/cryogen_core/util.clj#L38-L41&quot; title=&quot;cryogen-core/util.clj at 31bcbfdad59e8eaed4a6d417682e51ef1e90982c · cryogen-project/cryogen-core&quot;&gt;cryogen-core/util.clj at 31bcbfdad59e8eaed4a6d417682e51ef1e90982c · cryogen-project/cryogen-core&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;enlive-&amp;gt;plain-text&lt;/span&gt; [node-or-nodes]&lt;br /&gt;  (&lt;span class=&quot;hljs-name&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; node-or-nodes&lt;br /&gt;       (&lt;span class=&quot;hljs-name&quot;&gt;enlive/texts&lt;/span&gt;)&lt;br /&gt;       (&lt;span class=&quot;hljs-name&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt;&lt;/span&gt; str)))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;RSS リーダー利用者としての個人的な意見だが、正直なところ技術ブログなんかであれば全文マークアップ可能な状態で配信してほしい。割と RSS リーダーだけ読んで済ませることも多い。
最近はフィードに全文載っけないのが主流ぽくはあるが、これは多分広告表示とかアクセス解析のためにサイトを訪れてほしいからであって、そういう動機がないのであれば全文配信しない理由がない。&lt;/p&gt;
&lt;p&gt;なのでわたしのブログもそのようにしていたのだけど、このバージョンアップでそれができなくなるのは個人的にちょっと受け入れられないと判断した。
RSS リーダーでこのブログを購読する最有力ユーザはわたし自身なので、自分の意見が一番えらい。&lt;/p&gt;
&lt;p&gt;現状だとどうしようないのだが、 Cryogen 自体に手を入れることができるのでそれをやってみようとしている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cryogenweb.org/docs/customizing-cryogen.html#customizing-the-code&quot; title=&quot;Cryogen: Customizing/Extending Cryogen - Customizing the code&quot;&gt;Cryogen: Customizing/Extending Cryogen - Customizing the code&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;続く。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 27 Feb 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-02-19-i-cant-graduate-from-tortoise-git.html</guid><link>https://krymtkts.github.io/posts/2022-02-19-i-cant-graduate-from-tortoise-git.html</link><title>Tortoise Git から卒業できない</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今どきの Git の使い手は、 「CLI で使ってない奴はニワカ」みたいな硬派な人とか、&lt;a href=&quot;https://www.gitkraken.com/&quot; title=&quot;GitKraken&quot;&gt;GitKraken&lt;/a&gt; とかのイケてる Git クライアントや VS Code で &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens&quot; title=&quot;GitLens&quot;&gt;GitLens&lt;/a&gt; やら &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph&quot; title=&quot;Git Graph&quot;&gt;Git Graph&lt;/a&gt; 使ってる勢なんじゃないだろうか。&lt;/p&gt;
&lt;p&gt;わたしは長らく &lt;a href=&quot;https://tortoisegit.org/&quot; title=&quot;TortoiseGit&quot;&gt;TortoiseGit&lt;/a&gt; から卒業できないでいる。&lt;/p&gt;
&lt;p&gt;コミットやログ、ブランチやリセットやマージ等諸々の基本的な操作は全部 CLI でやるが、ある操作だけは TortoiseGit でやるのが楽過ぎて手放せないでいる。それは歴史の改竄だ。&lt;/p&gt;
&lt;p&gt;わたしも VS Code ユーザなので、勿論 GitLens やら Git Graph を使ったことはある。
だが、殊この歴史の改竄については Tortoise Git を超えてない(機能を知らんだけかも知らんが)。
&lt;a href=&quot;https://github.com/jesseduffield/lazygit&quot; title=&quot;jesseduffield/lazygit&quot;&gt;jesseduffield/lazygit&lt;/a&gt; だけはわたしの要求を満たせそうな素晴らしいツールに感じたのだが、 &lt;a href=&quot;https://github.com/microsoft/terminal&quot; title=&quot;Windows Terminal&quot;&gt;Windows Terminal&lt;/a&gt; で利用すると&lt;code&gt;┐&lt;/code&gt;とかの描画幅がワイド判定されて画面がクチャクチャになってしまう(わたしが pwsher でなくコマンドプロンプターならバッチリはまったであろうツールだ)。&lt;/p&gt;
&lt;p&gt;具体的に言うと、 &lt;a href=&quot;https://tortoisegit.org/docs/tortoisegit/tgit-dug-cherrypick.html&quot; title=&quot;Cherry picking&quot;&gt;Cherry picking&lt;/a&gt; がめちゃくちゃ便利でずっと使ってるのだけど、みんな歴史を改竄しないのだろうか。
わたしが歴史を改竄するのは、まだ一度もリモートに push していないローカルで育てたブランチを、デビュー前に清書するためだ。ローカルで思いのままに吐き散らしたコミット粒度及びログを、push 前に整えるのはプログラマの嗜みだ。&lt;/p&gt;
&lt;p&gt;使用例は以下の通り。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;思いのままにコミットを積み上げる&lt;/li&gt;&lt;li&gt;リセット前にタグを打つ&lt;/li&gt;&lt;li&gt;push 用のブランチをベースブランチにリセットする&lt;/li&gt;&lt;li&gt;思いのままに積み上げたコミットを丁寧に cherry pick し、公開するに適切なコミット粒度・コミットログへ書き換える&lt;/li&gt;&lt;li&gt;タグを打った元の状態と差分がないことを確認した後でめでたく push&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;重要なのは 3、ここでコミットの順番を入れ替えたりまとめたり分割したりという操作をするが、Tortoise Git 以外ではこういうことができないように見える。流行り？の GitKraken でさえこの有様 → &lt;a href=&quot;https://feedback.gitkraken.com/suggestions/191932/add-support-for-splitting-an-existing-commit&quot; title=&quot;Add support for splitting an existing commit - GitKraken&quot;&gt;Add support for splitting an existing commit - GitKraken&lt;/a&gt;
え、分割できへんの！？的な。&lt;/p&gt;
&lt;p&gt;最近見た限りだと、GitLens や Git Graph では reset したコミット以降の変更を 1 コミットにまとめるとかはできるっぽかった。でもそういうのがしたいわけじゃない。もっと派手にやりたいんじゃ！&lt;/p&gt;
&lt;p&gt;1 で思いのままにコミットを積み上げる等言語道断という意見もあろうが、都度〃やった内容をペコペココミットするリズム感がほしいので結局こうやってしまう。みんないちいちコミットの粒度を頭に入れた上で、アソコを直してココを直して...とかやってるのだろうか。多分やってないでしょう。&lt;/p&gt;
&lt;p&gt;より良い歴史改竄体験を求めて別のツールを探してみたいが、ググった感じだと派手な歴史改竄機能がみられず、あんまりみんなやらないっぽいのではと思っている。みんな素直に &lt;code&gt;git rebase --interactive&lt;/code&gt;(Interactive Rebasing) してるんだろうきっと。&lt;/p&gt;
&lt;p&gt;あーあとひとつ重要な機能を忘れていた。 &lt;a href=&quot;https://github.com/dahlbyk/posh-git&quot; title=&quot;dahlbyk/posh-git&quot;&gt;dahlbyk/posh-git&lt;/a&gt; を使っていると &lt;a href=&quot;https://github.com/dahlbyk/posh-git/wiki/Posh--Git-Module-Functions&quot; title=&quot;&lt;code&gt;tgit&lt;/code&gt;&quot;&gt;&lt;code&gt;tgit&lt;/code&gt;&lt;/a&gt; という素敵な関数が提供されることでより一層 Tortoise Git から離れにくくなる。 &lt;code&gt;tgit&lt;/code&gt; は Tortoise Git の任意の機能を召喚する魔法の関数なのだ。
この珍妙な関数を使うせいで、ペアプロ時に「あ！コマンド間違ってますよ！」と言われたこともあるが、便利なんだから仕方がない。勿論 Tab 補完もついている。&lt;/p&gt;
&lt;p&gt;もうここまで沼に飲まれていると使い続ければ良いのでは...という気もしないではないが、より良いツールが出てきたらぜひ乗り換えたい。あるいは全部 CLI に寄せるか。
未来の自分に託した。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 19 Feb 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-02-12-publish-to-powershell-gallery-etc.html</guid><link>https://krymtkts.github.io/posts/2022-02-12-publish-to-powershell-gallery-etc.html</link><title>PoweShell Gallery へ公開するためのステップ覚書</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;タイトルの通り。これは未来の自分へのバトンだ。&lt;/p&gt;
&lt;p&gt;毎回 PoweShell Gallery への公開方法を忘れたりする。 &lt;a href=&quot;/tags/powershellgallery.html&quot; title=&quot;弊ブログの&lt;code&gt;powershellgallery&lt;/code&gt;タグ&quot;&gt;弊ブログの&lt;code&gt;powershellgallery&lt;/code&gt;タグ&lt;/a&gt;を参照すればどれだけ同じミスを繰り返してるかアホさがわかる。
加えて &lt;a href=&quot;https://github.com/microsoft/PowerShellForGitHub&quot; title=&quot;microsoft/PowerShellForGitHub&quot;&gt;microsoft/PowerShellForGitHub&lt;/a&gt; で repo を作るのもしょっちゅう忘れる。
こちらに関してはもうそろそろ &lt;a href=&quot;https://github.com/cli/cli&quot; title=&quot;&lt;code&gt;gh&lt;/code&gt;&quot;&gt;&lt;code&gt;gh&lt;/code&gt;&lt;/a&gt;に乗り換えた方がいいのかも知れん。(けど、そうすると PowerShell の旨味であるオブジェクトでゴニョゴニョやりやすい世界がなくなってしまうのは困る)&lt;/p&gt;
&lt;p&gt;なのでこれらを定型化して &lt;code&gt;psake&lt;/code&gt; タスクに落とし込む等したいな～と考えている(今度はその&lt;code&gt;psake&lt;/code&gt;タスクが秘伝のソース化するかも知れんがそれはそれ)。
そのためにいつも何をやっているかを以下にリストアップする。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;前提。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PSMFAttendance&lt;/code&gt; の作成時にやったことを踏まえている&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/x-motemen/ghq&quot; title=&quot;ghq&quot;&gt;ghq&lt;/a&gt; を使っている前提&lt;/li&gt;&lt;li&gt;MS 公式文書はこちら &lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/publishing-guidelines?view=powershell-7.2&quot; title=&quot;PowerShell Gallery Publishing Guidelines and Best Practices - PowerShell | Microsoft Docs&quot;&gt;PowerShell Gallery Publishing Guidelines and Best Practices - PowerShell | Microsoft Docs&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;残念ながら過去のメモ(&lt;a href=&quot;https://github.com/krymtkts/Get-GzipContent&quot; title=&quot;krymtkts/Get-GzipContent&quot;&gt;krymtkts/Get-GzipContent&lt;/a&gt;を公開したとき)からは URL が変わっていた。今回はどうかな。&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;Step-1-repo-&quot; href=&quot;#Step-1-repo-&quot;&gt;Step 1. repo とモジュールマニフェストの作成&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;まず最初のステップはモジュールの雛形作成。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# create repo.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$owner&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;krymtkts&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSMFAttendance&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;New-GitHubRepository&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-RepositoryName&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Private&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-LicenseTemplate&lt;/span&gt; MIT&lt;br /&gt;ghq get &lt;span class=&quot;hljs-literal&quot;&gt;-p&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-GitHubRepository&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-OwnerName&lt;/span&gt; krymtkts &lt;span class=&quot;hljs-literal&quot;&gt;-RepositoryName&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; ssh_url)&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(ghq root)/&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(ghq list &lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;)&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# create module manifest.&lt;/span&gt;&lt;br /&gt;mkdir &lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$author&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Takatoshi Kuriyama&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;New-ModuleManifest&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;./&lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;/&lt;span class=&quot;hljs-variable&quot;&gt;$module&lt;/span&gt;.psd1&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ModuleVersion&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Author&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$author&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Copyright&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;(c) &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;((get-date).Year) &lt;span class=&quot;hljs-variable&quot;&gt;$author&lt;/span&gt;. All rights reserved.&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;PowerShell Gallery への公開コマンド &lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/powershellget/publish-module?view=powershell-7.2&quot; title=&quot;&lt;code&gt;Publish-Module&lt;/code&gt; (PowerShellGet)&quot;&gt;&lt;code&gt;Publish-Module&lt;/code&gt; (PowerShellGet)&lt;/a&gt; は、指定したディレクトリの中身を全部 PowerShell Gallery にぶち上げるため、モジュール以外のファイルを配置していても全て雲の上に持っていかれてしまう(除外設定がないのだ)。
そういう事故を起こさないためにも、モジュールリリース用のディレクトリを作成することをおすすめする。
そこでモジュールを開発するか、リリース対象のコードをそこにコピーした上で公開する、というのに限るのではないだろうか。わたしはコピーしたあとの掃除とか考えるのが面倒なので前者。&lt;/p&gt;
&lt;p&gt;先にモジュールマニフェストを作るのは、動作確認なんかで関数がエクスポートできているか見るのに使うからだ。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;Step-2-&quot; href=&quot;#Step-2-&quot;&gt;Step 2. モジュールマニフェストの更新&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;次は実装して、マニフェストの更新。
マニフェストに記すべき内容については公式のドキュメントを読むのが良い。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/scripting/gallery/how-to/publishing-packages/publishing-a-package?view=powershell-7.2#required-metadata-for-items-published-to-the-powershell-gallery&quot; title=&quot;Creating and publishing an item - PowerShell | Microsoft Docs&quot;&gt;Creating and publishing an item - PowerShell | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;とはいえわたしは大したモジュールを作らないのもあり、いつも更新するのは限られたフィールドだけだ。主に以下。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Description&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;PowerShellVersion&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;*ToExport&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;PrivateData.PSData.Tags&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;PrivateData.PSData.LicenseUri&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;PrivateData.PSData.ProjectUri&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;この中でわかりにくいのが、互換性のあるプラットフォームの指定。これは &lt;code&gt;Tags&lt;/code&gt; で表す。
&lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/publishing-guidelines?view=powershell-7.2#tag-your-package-with-the-compatible-pseditions-and-platforms&quot; title=&quot;PowerShell Gallery Publishing Guidelines and Best Practices - PowerShell | Microsoft Docs&quot;&gt;PowerShell Gallery Publishing Guidelines and Best Practices - PowerShell | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;マニフェストの更新は手で書いてもよいが、&lt;code&gt;Update-ModuleManifest&lt;/code&gt; も使える。
ただし &lt;code&gt;New-ModuleManifest&lt;/code&gt; と &lt;code&gt;Update-ModuleManifest&lt;/code&gt; で出力結果のフォーマットが異なる(後者はインデントされない)のがイライラするので、手でやることが多いか。
ただ自動化していくとすれば、ここは &lt;code&gt;Update-ModuleManifest&lt;/code&gt; に従うところか(こいつインデントしてくれへんのだが)。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;Last-Step-PowerShell-Gallery-&quot; href=&quot;#Last-Step-PowerShell-Gallery-&quot;&gt;Last Step. PowerShell Gallery 公開&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;最後は PowerShell Gallery への公開だ。&lt;/p&gt;
&lt;p&gt;PowerShell Gallery への公開を実施する前に、API キーの期限が切れていないか必ずチェックしておく。
キーの有効期限が切れている場合のエラーが非常にわかりにくいので、無駄にトラシューに時間を費やさずに済ますためにも公開前にチェック兼ねて毎回キーを更新するのが妥当では？
API キーの有効期限は最長 1 年しかないので、しょっちゅう切らしている。むしろ公開前に更新するフローであれば、期限も最短にできるのでよりセキュアかも知れない。&lt;/p&gt;
&lt;p&gt;API キー はモジュール名に対して &lt;a href=&quot;https://en.wikipedia.org/wiki/Glob_(programming)&quot; title=&quot;glob パターン&quot;&gt;glob パターン&lt;/a&gt;でスコープを切れる。過去には面倒を回避するために&lt;code&gt;*&lt;/code&gt;パターンを使ったりしていたが、今はパッケージ名の完全一致を利用していて、パッケージ毎に API キーを分けるようにしている。&lt;/p&gt;
&lt;p&gt;公開の手順は &lt;a href=&quot;https://github.com/krymtkts/Get-GzipContent&quot; title=&quot;krymtkts/Get-GzipContent&quot;&gt;krymtkts/Get-GzipContent&lt;/a&gt;を公開したときスクリプトを使う。&lt;/p&gt;
&lt;p&gt;このスクリプトでは &lt;code&gt;PSScriptAnalyzer&lt;/code&gt; を使ったチェックが成功した後に公開する。
また、&lt;code&gt;WhatIf&lt;/code&gt; は Dry Run として置き換えた上で使うようにしていた。
&lt;code&gt;WhatIf&lt;/code&gt; を使わないことで覚えることが増えて面倒な気もするが、とにかく間違って公開すると面倒なので、初期値を Dry Run にしたいという意図だった(多分)。この辺は &lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-shouldprocess?view=powershell-7.2&quot; title=&quot;&lt;code&gt;ShouldProcess&lt;/code&gt;&quot;&gt;&lt;code&gt;ShouldProcess&lt;/code&gt;&lt;/a&gt; の勉強をしたらより良い案があるかも知れん。&lt;/p&gt;
&lt;p&gt;PowerShell Gallery でのバージョニングは基本的に Semantic Versioning なので、何かしらミスったらモジュールの非公開はできるけど、同じバージョンへの更新はできない。パッチバージョンを上げて再公開とかしかできない。これはミスったら恥ずかしいしやり直しがきかないから、 Dry Run しまくる。この「何かしらミスったら」を Pester とかで事前チェックできると良いのだろうけど。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Param&lt;/span&gt; (&lt;br /&gt;    [&lt;span class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$ApiKey&lt;/span&gt;,&lt;br /&gt;    [&lt;span class=&quot;hljs-type&quot;&gt;ValidateSet&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Publish&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;DryRun&amp;#x27;&lt;/span&gt;)]&lt;span class=&quot;hljs-variable&quot;&gt;$Mode&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;DryRun&amp;#x27;&lt;/span&gt;&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ModuleName&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-File&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; ./ &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;*.psd1&amp;#x27;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Split-Path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parent&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ArtifactPath&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.\&lt;span class=&quot;hljs-variable&quot;&gt;$ModuleName&lt;/span&gt;\&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Check modules under &lt;span class=&quot;hljs-variable&quot;&gt;$ArtifactPath&lt;/span&gt;.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$report&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-ScriptAnalyzer&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$ArtifactPath&lt;/span&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Settings&lt;/span&gt; PSGallery&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$report&lt;/span&gt;) {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Violation found.&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$report&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;exit&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Check passed.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$Mode&lt;/span&gt;) {&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Publish&amp;#x27;&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Publishing module: &lt;span class=&quot;hljs-variable&quot;&gt;$ModuleName&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Publish-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$ArtifactPath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NugetAPIKey&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$ApiKey&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Verbose&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;DryRun&amp;#x27;&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[DRY-RUN]Publishing module: &lt;span class=&quot;hljs-variable&quot;&gt;$ModuleName&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Publish-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$ArtifactPath&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NugetAPIKey&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$ApiKey&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Verbose&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-WhatIf&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;?) {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Successfully published.&amp;#x27;&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Error&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Failed to publish.&amp;#x27;&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;今改めて見るとこのスクリプト、API キーは Credential に変更した方がマトモだ。ぜひ対応したい。&lt;/p&gt;
&lt;p&gt;このように使う。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;.\publish.ps1 &lt;span class=&quot;hljs-literal&quot;&gt;-Mode&lt;/span&gt; DryRun &lt;span class=&quot;hljs-literal&quot;&gt;-ApiKey&lt;/span&gt; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&lt;br /&gt;&lt;br /&gt;.\publish.ps1 &lt;span class=&quot;hljs-literal&quot;&gt;-Mode&lt;/span&gt; Publish &lt;span class=&quot;hljs-literal&quot;&gt;-ApiKey&lt;/span&gt; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;公開後は最終チェック、自端末へモジュールをインストールして一通り使えるか見ている。何しかちゃんと出来てるか不安。&lt;/p&gt;
&lt;p&gt;公開できたら、 repo の&lt;code&gt;README.md&lt;/code&gt; に以下を加筆する。これは流石に自動化無理なのでいいや。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PowerShell Gallery からのインストール方法&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://shields.io/category/downloads&quot; title=&quot;Shields.io&quot;&gt;Shields.io&lt;/a&gt; の PowerShell Gallery のダウンロード&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;終。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;おわりに&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;手順起こしてみてあれやけど、これもうすぐにでも &lt;code&gt;psake&lt;/code&gt; タスク化できそう。単にサボってただけだったか...&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 12 Feb 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-02-06-back-to-old-context-menu-in-win-11-pwsh.html</guid><link>https://krymtkts.github.io/posts/2022-02-06-back-to-old-context-menu-in-win-11-pwsh.html</link><title>Windows11 のコンテキストメニューを前のんに戻す(PowerShell で)</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;Windows11 にてコンテキストメニューの UI が変わった。
しかし自身は普段コンテキストメニューを使わないのであまり気にならなかった。&lt;/p&gt;
&lt;p&gt;のだが、たまたま 7z 圧縮されたファイルを渡されたことで、右クリックで 7zip で開けないのクソめんどい...と気になり始めた。
なので前のコンテキストメニューに戻す。PowerShell で。&lt;/p&gt;
&lt;p&gt;レジストリを編集する必要があるらしい。情報元 ↓
&lt;a href=&quot;https://www.tomshardware.com/how-to/windows-11-classic-context-menus&quot; title=&quot;How to Get Full Context Menus in Windows 11 | Tom&amp;#39;s Hardware&quot;&gt;How to Get Full Context Menus in Windows 11 | Tom&amp;#39;s Hardware&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;New-Item&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Split-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Parent&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set-ItemProperty&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;(Default)&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Value&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-ItemProperty&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Stop-Process&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; explorer &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Gist → &lt;a href=&quot;https://gist.github.com/krymtkts/30af31454d510ce0c34cfeb2fefec072&quot; title=&quot;Return to the previous context menu in Windows 11.&quot;&gt;Return to the previous context menu in Windows 11.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;↓ キーの名前は case insensitive なのかーい！&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ItemProperty&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(default)    :&lt;br /&gt;PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Classes\CLSID\{&lt;span class=&quot;hljs-number&quot;&gt;86&lt;/span&gt;ca1aa0&lt;span class=&quot;hljs-literal&quot;&gt;-34aa-4e8b-a509-50c905bae2a2&lt;/span&gt;}\In&lt;br /&gt;               procServer32&lt;br /&gt;PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Classes\CLSID\{&lt;span class=&quot;hljs-number&quot;&gt;86&lt;/span&gt;ca1aa0&lt;span class=&quot;hljs-literal&quot;&gt;-34aa-4e8b-a509-50c905bae2a2&lt;/span&gt;}&lt;br /&gt;PSChildName  : InprocServer32&lt;br /&gt;PSDrive      : HKCU&lt;br /&gt;PSProvider   : Microsoft.PowerShell.Core\Registry
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;終わり。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 06 Feb 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-02-05-build-pwsh-2022.html</guid><link>https://krymtkts.github.io/posts/2022-02-05-build-pwsh-2022.html</link><title>2022-02 版 PowerShell のビルド</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;PowerShell のパラメータバインディングについて調べていてコードに潜る時に、やっぱりローカルでビルドしたいよな！と思ったので、試してみた。
結果、副産物的に PowerShell 自体のコードをいじれる環境ができた。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;PC は Razer Blade Stealth 2017、Windows 11 Home 21H2 22000.469 だ。&lt;/p&gt;
&lt;p&gt;まず ビルドの方法を探す。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;README.md&lt;/code&gt;から辿って&lt;a href=&quot;https://github.com/PowerShell/PowerShell/blob/master/docs/building/windows-core.md&quot; title=&quot;Build PowerShell on Windows for .NET Core&quot;&gt;Build PowerShell on Windows for .NET Core&lt;/a&gt;に辿り着いた。
わたしは &lt;code&gt;dotnet&lt;/code&gt; を使った CLI ビルドがしたいので &lt;a href=&quot;https://github.com/PowerShell/PowerShell/blob/master/docs/building/windows-core.md#net-cli&quot; title=&quot;.NET CLI&quot;&gt;.NET CLI&lt;/a&gt; のやり方を使う。
ゆーても惚れ惚れするくらい簡単。以下だけ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Import-Module&lt;/span&gt; ./build.psm1&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Start-PSBootstrap&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ビルドに使うのは &lt;code&gt;Start-PSBuild&lt;/code&gt; らしい。&lt;code&gt;build.psm1&lt;/code&gt; を見たらわかるが、多くの関数が定義されてる。今回使うのはそのうちの 3 つだけだ。
これらの関数が何を行うためのものかのコメントがあまりないので、それぞれドキュメントからタグルなり使いみちを調べるのも一興か。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Command&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ListImported&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Source &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; build&lt;br /&gt;&lt;br /&gt;CommandType     Name                                               Version    Source&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-----------&lt;/span&gt;     &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                                               &lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;    &lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;Clear-PSRepo&lt;/span&gt;                                       &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;build&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ︙&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;Start-PSBootstrap&lt;/span&gt;                                  &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;build&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Function&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;Start-PSBuild&lt;/span&gt;                                      &lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;hljs-title&quot;&gt;0&lt;/span&gt;        &lt;span class=&quot;hljs-title&quot;&gt;build&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ︙&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;PC にインストール済みの &lt;code&gt;dotnet&lt;/code&gt; が &lt;code&gt;6.0.101&lt;/code&gt; だったので、試しに &lt;code&gt;6.0.101&lt;/code&gt; でビルドする。
&lt;code&gt;global.json&lt;/code&gt;内の&lt;code&gt;sdk.version&lt;/code&gt;という属性がある。このときは&lt;code&gt;6.0.100&lt;/code&gt;がデフォルト値になってたので、使いたいバージョンに変える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;PS&amp;gt; git diff&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;diff --git a/global.json b/global.json&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;index 047020849..e52d340bc 100644&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;--- a/global.json&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;+++ b/global.json&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -1,5 +1,5 @@&lt;/span&gt;&lt;br /&gt; {&lt;br /&gt;   &amp;quot;sdk&amp;quot;: {&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    &amp;quot;version&amp;quot;: &amp;quot;6.0.100&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    &amp;quot;version&amp;quot;: &amp;quot;6.0.101&amp;quot;&lt;/span&gt;&lt;br /&gt;   }&lt;br /&gt; }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;Start-PSBuild&lt;/code&gt; を実行することでビルドできる。
Razer Blade Stealth 2017 だとビルドに 2 分近くかかった。
ビルド物はドキュメントに記載の通り &lt;code&gt;./src/powershell-win-core/bin/Debug/net6.0/win7-x64/publish/pwsh.exe&lt;/code&gt; に出力された。
普通に起動すると実行時エラーで死んだけど、プロファイル読み込みを外せば起動した。ﾔｯﾀﾈ！&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; ./src/powershell&lt;span class=&quot;hljs-literal&quot;&gt;-win-core&lt;/span&gt;/bin/Debug/net6.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;/win7&lt;span class=&quot;hljs-literal&quot;&gt;-x64&lt;/span&gt;/publish/pwsh.exe &lt;span class=&quot;hljs-comment&quot;&gt;# 死&lt;/span&gt;&lt;br /&gt;PowerShell &lt;span class=&quot;hljs-number&quot;&gt;7.2&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-preview&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-222-g0ef30e54c70b9d5d69a35d1aeecdf2820cc1ab3b&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Process&lt;/span&gt; terminated. Assertion failed.&lt;br /&gt;No locals tuple should have been created yet.&lt;br /&gt;   at System.Management.Automation.Diagnostics.Assert(Boolean condition, String whyThisShouldNeverHappen, String detailMessage) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; C:\Users\takatoshi\dev\github.com\PowerShell\PowerShell\src\System.Management.Automation\utils\assert.cs:line &lt;span class=&quot;hljs-number&quot;&gt;202&lt;/span&gt;&lt;br /&gt;   at System.Management.Automation.Diagnostics.Assert(Boolean condition, String whyThisShouldNeverHappen) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; C:\Users\takatoshi\dev\github.com\PowerShell\PowerShell\src\System.Management.Automation\utils\assert.cs:line &lt;span class=&quot;hljs-number&quot;&gt;134&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# ... スタックトレースは続く&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; ./src/powershell&lt;span class=&quot;hljs-literal&quot;&gt;-win-core&lt;/span&gt;/bin/Debug/net6.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;/win7&lt;span class=&quot;hljs-literal&quot;&gt;-x64&lt;/span&gt;/publish/pwsh.exe &lt;span class=&quot;hljs-literal&quot;&gt;-NoProfile&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# Good!&lt;/span&gt;&lt;br /&gt;PowerShell &lt;span class=&quot;hljs-number&quot;&gt;7.2&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-preview&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-222-g0ef30e54c70b9d5d69a35d1aeecdf2820cc1ab3b&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt; C:\Users\takatoshi\dev\github.com\PowerShell\PowerShell\src\powershell&lt;span class=&quot;hljs-literal&quot;&gt;-win-core&lt;/span&gt;\bin\Debug\net6.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\win7&lt;span class=&quot;hljs-literal&quot;&gt;-x64&lt;/span&gt;\publish&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最後にビルド生成物などを掃除するには &lt;code&gt;Clear-PSRepo&lt;/code&gt; を実行すれば良い。&lt;/p&gt;
&lt;p&gt;終。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 05 Feb 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-01-30-pwsh-parameter-binding-parse-datetime.html</guid><link>https://krymtkts.github.io/posts/2022-01-30-pwsh-parameter-binding-parse-datetime.html</link><title>PowerShell のパラメータバインディングは &quot;3 時&quot; を Datetime 型にパースする</title><description>&lt;div class=&quot;section&quot;&gt;&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;いきなりまとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;PowerShell の関数なりコマンドレットがパラメータを受け取る場合、パラメータバインディングの仕組みで型ごとの変換処理をしており、日付型のパラメータでは&lt;code&gt;DateTime.Parse&lt;/code&gt; しているのがわかった。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;経緯&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;先日 &lt;a href=&quot;/posts/2022-01-23-scheduled-task-in-powershell.html&quot; title=&quot;ScheduledTask を設定した&quot;&gt;ScheduledTask を設定した&lt;/a&gt;くだりで初めて知った。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtasktrigger?view=windowsserver2022-ps#example-1--register-a-scheduled-task-that-starts-a-task-once&quot; title=&quot;New-ScheduledTaskTrigger (ScheduledTasks) | Microsoft Docs&quot;&gt;New-ScheduledTaskTrigger (ScheduledTasks) | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;を見ていて、 &lt;code&gt;-At 3pm&lt;/code&gt; て何これ？と思って日本語も試した。
使い所がわかりかねるが、以下のようなジャパナイズされた入力でも OK!
ただし漢数字、曜日や午前/午後は &lt;code&gt;Parse&lt;/code&gt; できないので無理な。&lt;/p&gt;
&lt;p&gt;参照: &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/base-types/parsing-datetime&quot; title=&quot;Convert strings to DateTime | Microsoft Docs&quot;&gt;Convert strings to DateTime | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;時&lt;br /&gt;&lt;br /&gt;Wednesday, January &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;年&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;月&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;日&lt;br /&gt;&lt;br /&gt;Monday, June &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2006&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt;: Cannot bind &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Date&amp;#x27;&lt;/span&gt;. Cannot convert value &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;3じ&amp;quot;&lt;/span&gt; to &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;System.DateTime&amp;quot;&lt;/span&gt;. Error: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;The string &amp;#x27;3じ&amp;#x27; was not recognized as a valid DateTime. There is an unknown word starting at index &amp;#x27;1&amp;#x27;.&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;どういう仕組や。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;大まかな予測&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;コマンドレットや関数に渡す前、引数の型 &lt;code&gt;DateTime&lt;/code&gt; の時点で捏ねくっている様子。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;hiduke&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;(&lt;br /&gt;    [&lt;span class=&quot;hljs-built_in&quot;&gt;datetime&lt;/span&gt;]&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$d&lt;/span&gt;&lt;br /&gt;  )&lt;br /&gt;  &lt;span class=&quot;hljs-variable&quot;&gt;$d&lt;/span&gt;&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; hiduke &lt;span class=&quot;hljs-literal&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;時&lt;br /&gt;&lt;br /&gt;Wednesday, January &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;キャストとパースの違いを見る。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; [&lt;span class=&quot;hljs-built_in&quot;&gt;DateTime&lt;/span&gt;]::Parse(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;3時&amp;#x27;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;Wednesday, January &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; [&lt;span class=&quot;hljs-built_in&quot;&gt;DateTime&lt;/span&gt;]::Parse(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;3じ&amp;#x27;&lt;/span&gt;)&lt;br /&gt;MethodInvocationException: Exception calling &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Parse&amp;quot;&lt;/span&gt; with &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;1&amp;quot;&lt;/span&gt; argument(s): &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;The string &amp;#x27;3じ&amp;#x27; was not recognized as a valid DateTime. There is an unknown word starting at index &amp;#x27;1&amp;#x27;.&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; [&lt;span class=&quot;hljs-built_in&quot;&gt;DateTime&lt;/span&gt;]&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;3時&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Wednesday, January &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; [&lt;span class=&quot;hljs-built_in&quot;&gt;DateTime&lt;/span&gt;]&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;3じ&amp;#x27;&lt;/span&gt;&lt;br /&gt;InvalidArgument: Cannot convert value &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;3じ&amp;quot;&lt;/span&gt; to &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;System.DateTime&amp;quot;&lt;/span&gt;. Error: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;The string &amp;#x27;3じ&amp;#x27; was not recognized as a valid DateTime. There is an unknown word starting at index &amp;#x27;1&amp;#x27;.&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;同じエラーメッセージ出てるので、 PowerShell が指定の型に評価するのに &lt;code&gt;DateTime.Parse&lt;/code&gt; を呼んでる。
真面目に考えたことなかったが、PowerShell 自体の機能でパラメーターバインディングというらしい。
&lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parameters?view=powershell-7.2&quot; title=&quot;about Parameters - PowerShell | Microsoft Docs&quot;&gt;about Parameters - PowerShell | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(今更ながら)また一つ学んでしまったようだな...&lt;/p&gt;
&lt;p&gt;パラメーターバインディングの処理内容を知るには &lt;code&gt;Trace-Command&lt;/code&gt; が使える。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Trace-Command&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-PSHost&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; ParameterBinding {&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ}&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5488&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; : BIND NAMED cmd line args [&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5491&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; : BIND POSITIONAL cmd line args [&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5493&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :     BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5495&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :         BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;] SKIPPED&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5496&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :     BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5497&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :         BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;] SKIPPED&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5499&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :     BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5501&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :         BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;] SKIPPED&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5503&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :     BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5504&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :         COERCE arg to [&lt;span class=&quot;hljs-type&quot;&gt;System.DateTime&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5506&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :             Trying to convert argument value from System.String to System.DateTime&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5509&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :             CONVERT arg &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; to &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;using&lt;/span&gt; LanguagePrimitives.ConvertTo&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;47&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05.5519&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :             ERROR: ERROR: COERCE FAILED: arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] could not be converted to the &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;System.DateTime&lt;/span&gt;]&lt;br /&gt;(...端折る...)&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt;: Cannot bind &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Date&amp;#x27;&lt;/span&gt;. Cannot convert value &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;3じ&amp;quot;&lt;/span&gt; to &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;System.DateTime&amp;quot;&lt;/span&gt;. Error: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;The string &amp;#x27;3じ&amp;#x27; was not recognized as a valid DateTime. There is an unknown word starting at index &amp;#x27;1&amp;#x27;.&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;パラメータバインディング時によしなにしてるのがわかってきたところで、力尽きた。
PowerShell のパラメータバインディングの仕組みに関しては宿題やな。気長に見ていくしかない。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;潜る&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;ここまで来れたので、次は PowerShell のパラメータバインディングのコードに潜り込む。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Trace-Command&lt;/code&gt; の ParameterBinding Information に出てた&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;COERCE FAILED: arg .+ could not be converted to the parameter type &amp;quot;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;&amp;quot;CONVERT arg type to param type using LanguagePrimitives.ConvertTo&amp;quot;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;から、 &lt;a href=&quot;https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/ParameterBinderBase.cs#L1262&quot; title=&quot;&lt;code&gt;ParameterBinderBase.cs&lt;/code&gt;&quot;&gt;&lt;code&gt;ParameterBinderBase.cs&lt;/code&gt;&lt;/a&gt;にたどり着いた。&lt;/p&gt;
&lt;p&gt;例外がスローされたのがどこか &lt;code&gt;LanguagePrimitives.ConvertTo&lt;/code&gt; から先を探るのにはちょっと情報が足りなかったので、&lt;code&gt;Trace-Command&lt;/code&gt; に TypeConversion を足して出力した。&lt;/p&gt;
&lt;p&gt;TypeConversion が有用なのがわかったのは、&lt;a href=&quot;https://github.com/PowerShell/PowerShell/blob/0ef30e54c70b9d5d69a35d1aeecdf2820cc1ab3b/src/System.Management.Automation/engine/LanguagePrimitives.cs#L4837&quot; title=&quot;&lt;code&gt;LanguagePrimitives.cs&lt;/code&gt; 内の &lt;code&gt;ConvertTo&lt;/code&gt;&quot;&gt;&lt;code&gt;LanguagePrimitives.cs&lt;/code&gt; 内の &lt;code&gt;ConvertTo&lt;/code&gt;&lt;/a&gt;を追ってたらトレース情報にまんまその名前が出てきたから。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Trace-Command&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-PSHost&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; ParameterBinding,TypeConversion {&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ}&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2304&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; : BIND NAMED cmd line args [&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2309&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; : BIND POSITIONAL cmd line args [&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2312&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :     BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2314&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :         BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;] SKIPPED&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2315&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :     BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2318&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :         BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;] SKIPPED&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2320&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :     BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2322&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :         BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;] SKIPPED&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2325&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :     BIND arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] to &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;Date&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2326&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :         COERCE arg to [&lt;span class=&quot;hljs-type&quot;&gt;System.DateTime&lt;/span&gt;]&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2329&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :             Trying to convert argument value from System.String to System.DateTime&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2331&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :             CONVERT arg &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; to &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;using&lt;/span&gt; LanguagePrimitives.ConvertTo&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2336&lt;/span&gt; TypeConversion Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :             Converting &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;3じ&amp;quot;&lt;/span&gt; to &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;System.DateTime&amp;quot;&lt;/span&gt;.&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2346&lt;/span&gt; TypeConversion Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :                 Exception calling Parse method with CultureInfo: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;The string &amp;#x27;3じ&amp;#x27; was not recognized as a valid DateTime. There is an unknown word starting at index &amp;#x27;1&amp;#x27;.&amp;quot;&lt;/span&gt;.&lt;br /&gt;DEBUG: &lt;span class=&quot;hljs-number&quot;&gt;2022&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-01-30&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;52.2350&lt;/span&gt; ParameterBinding Information: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :             ERROR: ERROR: COERCE FAILED: arg [&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;じ] could not be converted to the &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; [&lt;span class=&quot;hljs-type&quot;&gt;System.DateTime&lt;/span&gt;]&lt;br /&gt;(...端折る...)&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt;: Cannot bind &lt;span class=&quot;hljs-keyword&quot;&gt;parameter&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Date&amp;#x27;&lt;/span&gt;. Cannot convert value &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;3じ&amp;quot;&lt;/span&gt; to &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;System.DateTime&amp;quot;&lt;/span&gt;. Error: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;The string &amp;#x27;3じ&amp;#x27; was not recognized as a valid DateTime. There is an unknown word starting at index &amp;#x27;1&amp;#x27;.&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ParameterBinding Information のエラー出力までに TypeConversion Information が足されたのがわかる。いい感じじゃないか。&lt;/p&gt;
&lt;p&gt;このキーワードを元にコードを探ると、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PowerShell/PowerShell/blob/0ef30e54c70b9d5d69a35d1aeecdf2820cc1ab3b/src/System.Management.Automation/engine/LanguagePrimitives.cs#L5226-L5287&quot; title=&quot;&lt;code&gt;LanguagePrimitives.cs&lt;/code&gt; 内の &lt;code&gt;FigureParseConversion&lt;/code&gt;&quot;&gt;&lt;code&gt;LanguagePrimitives.cs&lt;/code&gt; 内の &lt;code&gt;FigureParseConversion&lt;/code&gt;&lt;/a&gt; でパースに使うメソッドをリフレクションで取得している&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/PowerShell/PowerShell/blob/0ef30e54c70b9d5d69a35d1aeecdf2820cc1ab3b/src/System.Management.Automation/engine/LanguagePrimitives.cs#L3747-L3780&quot; title=&quot;&lt;code&gt;LanguagePrimitives.cs&lt;/code&gt; 内の &lt;code&gt;ConvertViaParseMethod&lt;/code&gt;&quot;&gt;&lt;code&gt;LanguagePrimitives.cs&lt;/code&gt; 内の &lt;code&gt;ConvertViaParseMethod&lt;/code&gt;&lt;/a&gt; で取得したメソッドを使ったパースが行われてる&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;というのがわかった。&lt;/p&gt;
&lt;p&gt;やっぱり &lt;code&gt;Datetime.Parse&lt;/code&gt; を使ってたんや。あー、スッキリした！&lt;/p&gt;
&lt;p&gt;というか PowerShell 使ってる割にちゃんと勉強してないから、せなあかんな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 30 Jan 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-01-23-scheduled-task-in-powershell.html</guid><link>https://krymtkts.github.io/posts/2022-01-23-scheduled-task-in-powershell.html</link><title>Windows のタスクを操作する(PowerShell で)</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;決まった時間までにやらなければいけないことがあるとする。それを人間力でカバーするのは、それなりに資源の浪費になるので自動化したいとする。
最近の Windows ならタスクスケジューラで直に書いてもいいけど、操作めんどすぎるので普通に考えたらスクリプトにするでしょう。
これを Windows 11 と PowerShell 7.2.1 でやる。&lt;/p&gt;
&lt;p&gt;それでは &lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/scheduledtasks/?view=windowsserver2019-ps&quot; title=&quot;ScheduledTasks Module&quot;&gt;ScheduledTasks Module&lt;/a&gt; を使う。
このモジュールは Window なら以下のシステムフォルダにひっそりと存在する。令和のこの時代になんつー古い(v1)話なんや、とは思う。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; ScheduledTasks &lt;span class=&quot;hljs-literal&quot;&gt;-ListAvailable&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    Directory: C:\WINDOWS\system32\WindowsPowerShell\v1.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\Modules&lt;br /&gt;&lt;br /&gt;ModuleType Version    PreRelease Name                                PSEdition ExportedCommands&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;    &lt;span class=&quot;hljs-literal&quot;&gt;----------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                                &lt;span class=&quot;hljs-literal&quot;&gt;---------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;----------------&lt;/span&gt;&lt;br /&gt;Manifest   &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0.0&lt;/span&gt;               ScheduledTasks                      Core,Desk {&lt;span class=&quot;hljs-built_in&quot;&gt;Get-ScheduledTask&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;Set-ScheduledTask&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;Register-Sche&lt;/span&gt;…
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;WindowsPowerShell(v5.1)なら &lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/psscheduledjob/?view=powershell-5.1&quot; title=&quot;PSScheduledJob Module&quot;&gt;PSScheduledJob Module&lt;/a&gt; が使えるが、 PowerShell 7 では使えない(&lt;code&gt;Import-Module&lt;/code&gt; もできない)ので、 &lt;code&gt;ScheduledTask&lt;/code&gt; 一択かと。&lt;/p&gt;
&lt;p&gt;ではいくつかのレシピを以下に記す。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;日次で指定時間に実行(人間味のあるズレを添えて)&lt;/a&gt;&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$pwsh&lt;/span&gt; = (&lt;span class=&quot;hljs-built_in&quot;&gt;get-command&lt;/span&gt; pwsh).Source&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$action&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;New-ScheduledTaskAction&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Execute&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$pwsh&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Argument&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;-NonInteractive -Command &amp;quot;Invoke-MyCommand&amp;quot;&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$trigger&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;New-ScheduledTaskTrigger&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Daily&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-At&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;46&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-RandomDelay&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$task&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;New-ScheduledTask&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Action&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$action&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Trigger&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$trigger&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Register-ScheduledTask&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-InputObject&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$task&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-TaskName&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;morning-action&amp;#x27;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;指定時間に起動して実行待ちするタスク ≒ 実行許諾の通知的なもの&lt;/a&gt;&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$pwsh&lt;/span&gt; = (&lt;span class=&quot;hljs-built_in&quot;&gt;get-command&lt;/span&gt; pwsh).Source&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$action&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;New-ScheduledTaskAction&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Execute&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$pwsh&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Argument&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;-Command &amp;quot;{Read-Host `&amp;quot;press key`&amp;quot; | Out-Null; Invoke-MyCommand}.Invoke()&amp;quot;&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$trigger&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;New-ScheduledTaskTrigger&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Daily&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-At&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;17&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$task&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;New-ScheduledTask&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Action&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$action&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Trigger&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$trigger&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Register-ScheduledTask&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-InputObject&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$task&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-TaskName&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;evening-action&amp;#x27;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;単発で指定時間に実行(人間味のあるズレを添えて)&lt;/a&gt;&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$pwsh&lt;/span&gt; = (&lt;span class=&quot;hljs-built_in&quot;&gt;get-command&lt;/span&gt; pwsh).Source&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$action&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;New-ScheduledTaskAction&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Execute&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$pwsh&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Argument&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;-NonInteractive -Command &amp;quot;Invoke-MyCommand&amp;quot;&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$jitter&lt;/span&gt; = (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Random&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Minimum&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Maximum&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt;*&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;))&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$timing&lt;/span&gt; = (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;2022-01-30 17:05&amp;#x27;&lt;/span&gt;).AddSeconds(&lt;span class=&quot;hljs-variable&quot;&gt;$jitter&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$trigger&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;New-ScheduledTaskTrigger&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-At&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$timing&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Once&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$setting&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;New-ScheduledTaskSettingsSet&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-DeleteExpiredTaskAfter&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$task&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;New-ScheduledTask&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Action&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$action&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Trigger&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$trigger&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Settings&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$setting&lt;/span&gt; | `&lt;br /&gt;    %{ &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;.Triggers[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;].EndBoundary = &lt;span class=&quot;hljs-variable&quot;&gt;$timing&lt;/span&gt;.AddMinutes(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;).ToString(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;s&amp;#x27;&lt;/span&gt;); &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Register-ScheduledTask&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-InputObject&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$task&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-TaskName&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;single-action&amp;#x27;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このレシピではズレの算出は自前で行っている。&lt;code&gt;New-ScheduledTaskTrigger&lt;/code&gt; に &lt;code&gt;-RandomDelay&lt;/code&gt; を指定しておくのもアリだが、単発であるし具体的にいつ実行されるかがわかる方が好ましいかと考えた。&lt;/p&gt;
&lt;p&gt;単発タスクなので、実行後にタスクを廃棄したいとする。その場合は例のように &lt;code&gt;-Settings&lt;/code&gt; で自動削除の設定を有効にする必要がある。
同時に、タスクの期限切れの日時も指定する必要があるが、これはコマンドレットのオプションでは設定できない。直接オブジェクトに代入することで設定する(各 &lt;code&gt;Triggers&lt;/code&gt; で &lt;code&gt;EndBoundary&lt;/code&gt; を設定)。&lt;/p&gt;
&lt;p&gt;参照: &lt;a href=&quot;https://stackoverflow.com/questions/29337135/powershell-v4-create-remote-task-scheduler-task-set-to-expire-and-delete/35777432#35777432&quot; title=&quot;Powershell v4. Create remote task scheduler task set to expire and delete - Stack Overflow&quot;&gt;Powershell v4. Create remote task scheduler task set to expire and delete - Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;注意&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;いくつかの注意点がある。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;実行ファイルは絶対パス指定&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;実行ファイルは絶パス(絶対パスのわかりにくい略称)指定じゃないといけない。コマンドプロンプトでパスを通していたとしても、 &lt;code&gt;pwsh&lt;/code&gt; とかだとタスクスケジューラちゃんは実行ファイルを見つけられない。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-code-pwsh-code-code-Command-code-&quot; href=&quot;#-code-pwsh-code-code-Command-code-&quot;&gt;&lt;code&gt;pwsh&lt;/code&gt; の引数 &lt;code&gt;Command&lt;/code&gt; はダブルクォートで書く&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;&lt;code&gt;New-ScheduledTaskAction&lt;/code&gt; の引数 &lt;code&gt;Argument&lt;/code&gt; に、 &lt;code&gt;pwsh&lt;/code&gt; に渡す引数を定義する。
この時、引数 &lt;code&gt;Command&lt;/code&gt; に渡す文字列はダブルクォートで書くこと。
コマンドプロンプトで試せばわかるが、ダブルクォートはコマンドプロンプトで文字列として解釈され &lt;code&gt;pwsh&lt;/code&gt; に渡るのに対し、シングルクォートは文字列と解釈されないそのままが渡されている様子。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cmd&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;C:\&lt;span class=&quot;hljs-title&quot;&gt;Windows&lt;/span&gt;\&lt;span class=&quot;hljs-title&quot;&gt;system32&lt;/span&gt;&amp;gt;&lt;span class=&quot;hljs-title&quot;&gt;pwsh&lt;/span&gt; -&lt;span class=&quot;hljs-title&quot;&gt;NonInteractive&lt;/span&gt; -&lt;span class=&quot;hljs-title&quot;&gt;Command&lt;/span&gt; &amp;quot;&lt;span class=&quot;hljs-title&quot;&gt;Write&lt;/span&gt;-&lt;span class=&quot;hljs-title&quot;&gt;Host&lt;/span&gt; 123&amp;quot;&lt;br /&gt;123&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-title&quot;&gt;C&lt;/span&gt;:\&lt;span class=&quot;hljs-title&quot;&gt;Windows&lt;/span&gt;\&lt;span class=&quot;hljs-title&quot;&gt;system32&lt;/span&gt;&amp;gt;&lt;span class=&quot;hljs-title&quot;&gt;pwsh&lt;/span&gt; -&lt;span class=&quot;hljs-title&quot;&gt;NonInteractive&lt;/span&gt; -&lt;span class=&quot;hljs-title&quot;&gt;Command&lt;/span&gt; &amp;#x27;&lt;span class=&quot;hljs-title&quot;&gt;Write&lt;/span&gt;-&lt;span class=&quot;hljs-title&quot;&gt;Host&lt;/span&gt; 123&amp;#x27;&lt;br /&gt;&lt;span class=&quot;hljs-title&quot;&gt;Write&lt;/span&gt;-&lt;span class=&quot;hljs-title&quot;&gt;Host&lt;/span&gt; 123&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この挙動のソースはコレ ↓ くらいしか見つからんかった。オフィシャルな情報はないのかな。あったら是非引用したい。(コマンドプロンプト界の常識過ぎるテーマなのか？)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/24173825/what-does-single-quoting-do-in-windows-batch-files/24181667#24181667&quot; title=&quot;cmd - What does single-quoting do in Windows batch files? - Stack Overflow&quot;&gt;cmd - What does single-quoting do in Windows batch files? - Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-code-Read-Host-code-Interactive-code-pwsh-code-&quot; href=&quot;#-code-Read-Host-code-Interactive-code-pwsh-code-&quot;&gt;&lt;code&gt;Read-Host&lt;/code&gt; するからにゃぁ Interactive で &lt;code&gt;pwsh&lt;/code&gt; を起動しろよな&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;Read-Host&lt;/code&gt; する例なのに、間違って &lt;code&gt;-NoInteractive&lt;/code&gt; をつけてしまうと、このようにおもしろエラーを頂戴するのでご注意。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;C:\Windows\system32&amp;gt;pwsh &lt;span class=&quot;hljs-literal&quot;&gt;-NonInteractive&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Command&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{Read-Host `&amp;quot;press key`&amp;quot; | Out-Null; Invoke-MyCommand}.Invoke()&amp;quot;&lt;/span&gt;&lt;br /&gt;MethodInvocationException: Exception calling &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Invoke&amp;quot;&lt;/span&gt; with &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;0&amp;quot;&lt;/span&gt; argument(s): &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;PowerShell is in NonInteractive mode. Read and Prompt functionality is not available.&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description><pubDate>Sun, 23 Jan 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-01-15-move-taskbar-to-the-top-in-win11-pwsh.html</guid><link>https://krymtkts.github.io/posts/2022-01-15-move-taskbar-to-the-top-in-win11-pwsh.html</link><title>Windows 11 のタスクバーを天に(PowerShell で)</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;Windows11 ではメニューからタスクバーを天に持ち上げれなくなったので、みんなレジストリを操作して実現している。手順はどこでも手に入るが、以下のページを参照した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.tomshardware.com/how-to/windows-11-taskbar-move-to-top&quot; title=&quot;How to Move the Taskbar to the Top in Windows 11 | Tom&amp;#39;s Hardware&quot;&gt;How to Move the Taskbar to the Top in Windows 11 | Tom&amp;#39;s Hardware&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;regedit&lt;/code&gt; を開く&lt;/li&gt;&lt;li&gt;&lt;code&gt;HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3&lt;/code&gt; を開く&lt;/li&gt;&lt;li&gt;&lt;code&gt;Settings&lt;/code&gt; を編集し保存する&lt;ul&gt;
&lt;li&gt;2 行目を &lt;code&gt;7A F4 00 00 03 00 00 00&lt;/code&gt; -&amp;gt; &lt;code&gt;7A F4 00 00 01 00 00 00&lt;/code&gt;にする&lt;ul&gt;
&lt;li&gt;デフォルトの&lt;code&gt;03&lt;/code&gt;が下、&lt;code&gt;01&lt;/code&gt;が上というわけ&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;explorer&lt;/code&gt; を再起動する&lt;ul&gt;
&lt;li&gt;コマンドプロンプトで&lt;ol&gt;
&lt;li&gt;&lt;code&gt;taskkill /f /im explorer.exe&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;start explorer.exe&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;これが PC 変わる度にやるのクソめんどいので、PowerShell でスクリプト化した。
そんなに機会はないけど一々覚えてないので先程のページを見にったりと、とにかくめんどい。&lt;/p&gt;
&lt;p&gt;PowerShell 7.2.1 でやった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ShowHex&lt;/span&gt; = {&lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; ([&lt;span class=&quot;hljs-built_in&quot;&gt;array&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$arr&lt;/span&gt;) (&lt;span class=&quot;hljs-variable&quot;&gt;$arr&lt;/span&gt; | %{[&lt;span class=&quot;hljs-type&quot;&gt;System.Convert&lt;/span&gt;]::ToHexString(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;)}) &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27; &amp;#x27;&lt;/span&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Settings&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$org&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ItemProperty&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ExpandProperty&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ShowHex&lt;/span&gt;.Invoke((,&lt;span class=&quot;hljs-variable&quot;&gt;$org&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$new&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;() + &lt;span class=&quot;hljs-variable&quot;&gt;$org&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$new&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;12&lt;/span&gt;] = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;x01&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ShowHex&lt;/span&gt;.Invoke((,&lt;span class=&quot;hljs-variable&quot;&gt;$new&lt;/span&gt;))&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Compare-Object&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$org&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$new&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set-ItemProperty&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$path&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-name&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$key&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Value&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$new&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Stop-Process&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; explorer &lt;span class=&quot;hljs-literal&quot;&gt;-Force&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;## if explorer doesn&amp;#x27;t restart, start explorer manually.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Start-Process -Name explorer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;万が一失敗してたら &lt;code&gt;$org&lt;/code&gt; で &lt;code&gt;Set-ItemProperty&lt;/code&gt; して戻す必要があるので、成功(≒ 天にタスクバー)を確認するまで窓を閉じない方が良かろう。
ちゃんと期待の更新ができているか確認するために、レジストリの値を 16 進数に変換して標準出力までしちゃう。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/krymtkts/ba83a0612bba84b5e8229d64e9d8681a&quot; title=&quot;Gist はこちら&quot;&gt;Gist はこちら&lt;/a&gt;。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;おまけ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;taskkill&lt;/code&gt; は PowerShell で言うところの何か調べたときのページ ↓&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.pdq.com/blog/what-is-the-powershell-equivalent-of-taskkill/&quot; title=&quot;What Is The PowerShell Equivalent Of Taskkill | PDQ.com&quot;&gt;What Is The PowerShell Equivalent Of Taskkill | PDQ.com&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Okay, I&amp;#39;ll be the first to admit it; the name is a little lackluster. Especially when compared to &lt;strong&gt;TASKKILL!!!!!!&lt;/strong&gt; &lt;strong&gt;Stop-Process&lt;/strong&gt; just doesn&amp;#39;t carry the same hostile undertones Thankfully, Microsoft at least gave us &lt;strong&gt;kill&lt;/strong&gt; as an alias, so we&amp;#39;ve got that going for us. Regardless, let&amp;#39;s see if it still packs the same task-killing punch.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;さて、最初に断っておきますが、このネーミングは少し物足りないですね。特に&lt;strong&gt;TASKKILL!!!!!!&lt;strong&gt;と比較するとね。 ありがたいことに、Microsoft は少なくとも&lt;/strong&gt;kill&lt;/strong&gt;という別名をつけてくれました。 ともかく、同じようにタスクを殺すパンチをパックしているかどうか見てみましょう。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;こんなん笑うわｗ&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 15 Jan 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2022-01-09-planning.html</guid><link>https://krymtkts.github.io/posts/2022-01-09-planning.html</link><title>2022</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;できたら or できなかったらどうなるというのがないが、例年通り目標をたてる。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;テーマ: 自分の人生は自分で決める&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;これは自分の中でずっと言い聞かせていることなのだけど、去年一昨年は外的要因によって見失いがちだった。改めて見つめ直したいテーマにした。&lt;/p&gt;
&lt;p&gt;単になんでもかんでも自分で決めたいわけじゃなくて、意見を持ってこうなのだと考えているところに、決断の資源を割く様にする。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2021-&quot; href=&quot;#2021-&quot;&gt;2021 年の目標&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;継続する目標。前年未達だった目標は基本継続としたいが、OSS への貢献については保留とする。&lt;/p&gt;
&lt;p&gt;なんでかというとわたし自身が積極的でなくて「バグ見っけたら起票しよう」くらいのアクションしか例年やってないから、個別に項を設けて書いても意味がない。
AWS Tools for PowerShell のくだりで実感したが、やるんだったら Pull Request をマージしてくらいまでドライブしないと、如何なる小規模プロジェクトでもメンテナの負荷になり得る。結局コードで殴りつけてあげないと誰のためにもならない。とはいえ貢献したいプロジェクトを探して～とかやるのはなんか違う。
自作ツールの更新周りで既存のツールを色々見ていくだろうから、その流れで貢献することがあればできたらいいかなくらいにする。なんか無責任な感じもするけど、わたしの資源はわたしが思った(というか期待した)ほど多くなくて、やりたいことができないってのが常なので。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;住みたい場所を決める&lt;ul&gt;
&lt;li&gt;わたしは田舎に住み(薪ストーブやり)たいが、妻は車でなくても生活圏内を移動できることを重視してるので、落とし所を探す。なんか良い選択肢ないかなー&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;積ん読の消化 1 冊/月&lt;ul&gt;
&lt;li&gt;前年からペースを上げて、読書習慣を改善する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;自作ツールの更新&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/PSMFAttendance&quot; title=&quot;PSMFAttendance&quot;&gt;PSMFAttendance&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;はよ Gallery に登録しろ&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/mccall-bot&quot; title=&quot;mccall-bot&quot;&gt;mccall-bot&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;現職は Slack 文化がないため使い所が自分のチャンネルしかなく持て余している。放置したままだとマッコールさんにも申し訳ないので、なんか行く末を決めて差し上げたほうが良いのかもと考えている&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;ギター練習を 30 分/毎日&lt;ul&gt;
&lt;li&gt;たまにはバンド練習やりたいけど、世情を見つつ判断する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://krymtkts.github.io/&quot; title=&quot;このブログ&quot;&gt;このブログ&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;毎月の更新リズムを維持する&lt;/li&gt;&lt;li&gt;&lt;code&gt;todo.txt&lt;/code&gt; に放置テーマが結構溜まってきていることも鑑み、粛々と消化したい&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;追加する目標。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;深酒で怪我をしない&lt;ul&gt;
&lt;li&gt;寄る年波もあり怪我の治りが遅いので超重要課題&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;知らない言語を学ぶ F#&lt;ul&gt;
&lt;li&gt;PowerShell で面倒なスクリプトを書くとき、代わりに F#で書こうという気になったので今勉強している&lt;/li&gt;&lt;li&gt;なんかツールを書いたらゴールとしよう&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;</description><pubDate>Sun, 09 Jan 2022 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-12-31-retrospective2021.html</guid><link>https://krymtkts.github.io/posts/2021-12-31-retrospective2021.html</link><title>振り返り 2021 年</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;2021 年を振り返る。&lt;/p&gt;
&lt;p&gt;2021 年のテーマは「自分を大事に」だった。肉体・精神共に大事にできてへんのちゃうん？という上半期から、大事にするための判断に絡んだ下半期。&lt;/p&gt;
&lt;p&gt;決して悪い方向には向かっていないが、2021 年は迷いの多い年だった。判断としては信念に沿ったモノだったはずなのだが、外的要因や体力不足による判断低下から自分自身の判断とその結果に相当の迷いがあった。&lt;/p&gt;
&lt;p&gt;大きな出来事は 2 個だけか。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;働きすぎた&lt;/li&gt;&lt;li&gt;転職&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;働きすぎた&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;2020 年末から 2021 年始は殆ど休みもなく「2020 年秋の新機能開発」に奔走していた。冬やけどな。
これはチーム総力戦の鬼の休日出勤によってなんとか本番へリリースされたのだけど敗戦処理は 2021 年 2 月頃まであったような感じやったな～、もはや懐かしい景色。&lt;/p&gt;
&lt;p&gt;その新機能開発によって圧迫されてしまった機能もちょいちょいバグはあれど重大な問題なく本番へリリースできた(奇跡的に)。またリリース後の残作業に 1 年目の若手とおよそ 2week のスクラムもどきで敗戦処理をできたのはよかった。前職の若手教育は OJT が主なのだが、リスキーな案件ばかりで開発やらせてあげられないので、こういった場を設けられるのはやはりリードエンジニアたる所以だったなと感じる(これは自画自賛)。
この辺はまだ限界突破してなかったが、休日出勤を繰り返したことで感覚がおかしくなって、3 月以降徐々に稼働時間がかさんでいった。&lt;/p&gt;
&lt;p&gt;3 月頃から入ったプロジェクトは、開発も始めていないのに締切だけあり、割り振られたリソースではどうあがいても足りないくらいだった。外向けのコミットメントもされてたせいで誰も止められない暴走列車と化したプロジェクト。今思い出してもドキドキするな～。プログラマなら感覚的に WBS とか見て「あ、やばいな」という肌感触があると思うが、まさにあれだった。打開策ないかスケジュール見直し頼んでみたりとか人足し依頼してみたような記憶もあるけど抜本的な解決に至らず。&lt;/p&gt;
&lt;p&gt;どうにもできなかったので、人身御供的にリードエンジニアが全てを背負うしかあるまいなとわたしも暴走し、 SES やってた時以来の過重労働で 36 協定の制限突破する勢い出してた。万が一法律に触れそうなら会社も動くやろ的な。いやーほんまに良くない判断ね。まさにアドレナリンジャンキーと化していた。
結局スケジュールに決定的に間に合わないと判断してもらえたことで、わたしからいくつかのしごとが引き剥がしてもらい、エンジニアがドカドカ投入されてメチャクチャ綱渡り的に開発・リリースしていった形だったような気がする。
正直なところ肉体・精神共に不調だったので、細かく覚えてない。これも日記見ながら書いたくらいや。ある種、燃え尽き症候群的な状態に陥ってたのだろう。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;転職&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;そしてこの過重労働の間に、ヘッドハンター()からオファーをもらって、転職することにした。&lt;/p&gt;
&lt;p&gt;当時の判断は&lt;a href=&quot;/posts/2021-09-28-jobchange-2021.html&quot; title=&quot;過去の日記&quot;&gt;過去の日記&lt;/a&gt;に書いてあるが、この振り返りの文脈でいうとまた思うところがある。プロジェクトの悪いところ全部盛りみたいな状況から「こんなに苦しいならもうチーム開発などいらぬ！」みたいな聖帝的感覚に陥ってただろうなと改めて感じる(現職はほぼ一人ひとり働く感じ)。わたしの中では前職の元同僚達と働くのは楽しいことだったので転職するのに相当の迷いがあった。一緒に飲んだらかなりの確率でわたしが酔っ払って負傷するので危険な仲間。&lt;/p&gt;
&lt;p&gt;この転職、入社前から諸々のトラブルはあったものの、辛うじてまだ生き残ってる。直前にヘッドハンター()に手のひら返されたり、ヘッド(略)が先に入れた社員が即辞めてたり、1 ヶ月パイセンが左遷(とわたしは表現している)されたりして、あんま精神衛生の環境は良くない。&lt;/p&gt;
&lt;p&gt;ただ悪いことばかりではない。リモート慣れしていない会社にフルリモートで参画しても、関係者と意見交換しつつ一人で仕事を進められる自信ができた。また最近仕事で深く踏み込んでなかったフロントエンド開発(TypeScript + React.js で Atomic Components する)をやってフロントエンド戦国時代を肌で感じたりできたのは良。
入社前からやりたかったところは未だやれてない状況なので煮え切らないが、これまた期待値だけで報酬は上がったりしてるので、筋は悪くないのかなと。&lt;/p&gt;
&lt;p&gt;やっぱどこでもそれなりに動けるな、という自信が確たるもんになった。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2021-&quot; href=&quot;#2021-&quot;&gt;2021 年目標と成果&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;年初に以下の目標を設定した。50%超えたしぼちぼちということにする。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ 住みたい場所を決める&lt;ul&gt;
&lt;li&gt;意見のすり合わせが進んでいない&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️ 仕事上の掃除&lt;ul&gt;
&lt;li&gt;掃除の仕方が転職って形になったが、引き継ぎも最低限やったので良しとしてくれ...&lt;/li&gt;&lt;li&gt;のちの調査によると、引き継いだ仕事の 33% だけがわたしのシナリオ通り進めて、他は放置されているらしい。ショッキングな結果やがそこは残された者共や前職が決めるとこやからな、何も言うまい&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️ 昇給&lt;ul&gt;
&lt;li&gt;前職の昇給は満足じゃなかったが、転職して上がった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;🔺 積ん読の消化&lt;ul&gt;
&lt;li&gt;技術書以外含めて 1 冊/2 ヵ月&lt;/li&gt;&lt;li&gt;ライフハックや書評とかのライトな本から再開し、今は技術書も読めるようになってきた。転職後少しずつ習慣を取り戻せている&lt;/li&gt;&lt;li&gt;やはり読書のためには疲労感の改善が重要やな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;❌ OSS へのコントリビューション&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/aws/aws-tools-for-powershell/issues/225&quot; title=&quot;&lt;code&gt;aws/aws-tools-for-powershell&lt;/code&gt; のバグレポート&quot;&gt;&lt;code&gt;aws/aws-tools-for-powershell&lt;/code&gt; のバグレポート&lt;/a&gt;しただけ&lt;ul&gt;
&lt;li&gt;なんか忙しそうで進展ないし、修正試みた方が良かったな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;あとは自作のツールか。まだ PSGallery に登録してないけど。 &lt;a href=&quot;https://github.com/krymtkts/PSMFAttendance&quot; title=&quot;krymtkts/PSMFAttendance&quot;&gt;krymtkts/PSMFAttendance&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;🔺 自作ツールの更新&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/Get-GzipContent&quot; title=&quot;krymtkts/Get-GzipContent: Get-Content for gzip files.&quot;&gt;krymtkts/Get-GzipContent: Get-Content for gzip files.&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;ちょっとだけやった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/mccall-bot&quot; title=&quot;mccall-bot&quot;&gt;mccall-bot&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;やってない&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️ ギター練習を 30 分/週 3 回&lt;ul&gt;
&lt;li&gt;割と出来てる。耳コピ少し/songsterr で曲覚えたり&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️ &lt;a href=&quot;https://krymtkts.github.io/&quot; title=&quot;このブログ&quot;&gt;このブログ&lt;/a&gt;を毎月更新する&lt;ul&gt;
&lt;li&gt;6 月ズルしたけどコンスタントにかけるようになったかな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️ 日頃使ってるスニペット的なのを Gist に登録していく&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/krymtkts&quot; title=&quot;krymtkts’s gists&quot;&gt;krymtkts’s gists&lt;/a&gt; みたら月 1 個くらいで数少ないけどぼちぼちやっとるな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;やっぱ転職の判断した頃から制御を自分に戻せてるのか、自分向けの目標は簡単なところからできるようになったんじゃないかな。
ここから大きく変化を～とか欲張らず、ちまちま積み重ねれたらいいな。&lt;/p&gt;
&lt;p&gt;おわり。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Fri, 31 Dec 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-12-26-fnm-tips-with-ccleaner.html</guid><link>https://krymtkts.github.io/posts/2021-12-26-fnm-tips-with-ccleaner.html</link><title>fnm でインストールした処理系は Temp フォルダからシンボリックリンクされるので ccleaner で消える話(当然)</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;最近、 Node.js 処理系のバージョン管理に fnm を使っている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Schniz/fnm&quot; title=&quot;Schniz/fnm: 🚀 Fast and simple Node.js version manager, built in Rust&quot;&gt;Schniz/fnm: 🚀 Fast and simple Node.js version manager, built in Rust&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;お仕事 PC(Windows) では Yarn を使うのだが、 それまで使っていた Nodist だとどうにも Yarn が内部的に参照する npx が新しいバージョンに変わらなくてエラーが解消できなかった。&lt;/p&gt;
&lt;p&gt;これが fnm なら何の問題もなくサクサク動く。&lt;a href=&quot;https://community.chocolatey.org/packages/fnm&quot; title=&quot;chocolatey&quot;&gt;chocolatey&lt;/a&gt; でインストールできるし、&lt;code&gt;.node-version&lt;/code&gt;, &lt;code&gt;.nvmrc &lt;/code&gt; をうまく使える点でも良、重宝している。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fnm env&lt;/code&gt; で使う処理系を指定した環境変数を生成＆利用したいツールに反映させる必要があるため、 VS Code なんかは terminal 経由で起動する必要があるのだけど(それしか方法を知らん)、これは元々わたしの作業スタイルだったので特に問題ない。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;事件は突然に&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ある日、怪現象に悩まされた。&lt;/p&gt;
&lt;p&gt;何気なく VS Code を立ち上げると、 &lt;code&gt;textlint&lt;/code&gt; が見つからないというエラーが出力されていた。&lt;code&gt;textlint&lt;/code&gt; だけでなく、 &lt;code&gt;npm&lt;/code&gt; も &lt;code&gt;node&lt;/code&gt; も消え去っていたのだ。その時はさっさと作業を始めたかったので、処理系やモジュールを再インストールすることで現状復帰した。これが最も手っ取り早い。&lt;/p&gt;
&lt;p&gt;この原因は後でからわかったのだが非常に単純な話であって、Temp フォルダの中身を再帰的に消したことで fnm がインストールした処理系全ても無に帰したのだ。&lt;/p&gt;
&lt;p&gt;わたしは Temp フォルダやその他のゴミ掃除目的に ccleaner を長らく使っている。ccleaner は Temp フォルダの中身を一覧して消す。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fnm&lt;/code&gt; がインストールした処理系自体は &lt;code&gt;$env:FNM_DIR&lt;/code&gt; に配置される。
&lt;code&gt;fnm env&lt;/code&gt; を実行すると、Temp フォルダ内に &lt;code&gt;$env:FNM_DIR&lt;/code&gt; 配下の特定バージョンへ向けたシンボリックリンクを作成する。そのシンボリックリンクのパスは &lt;code&gt;$env:FNM_MULTICHELL_PATH&lt;/code&gt; に格納されている。&lt;/p&gt;
&lt;p&gt;おわかりいただけただろうか。&lt;/p&gt;
&lt;p&gt;ccleaner のように Temp フォルダを探索的に掃除するなら、以下のコマンドで事前に削除されるファイルが何処のものか知ると良い。こんなの事故るまで頭が回らんわ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$env:FNM_MULTISHELL_PATH&lt;/span&gt;/../ | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; LinkTarget
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;対策&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;現状、ccleaner 等の Temp フォルダを掃除するアプリで、 &lt;code&gt;fnm&lt;/code&gt; のフォルダを除外するしかないか。
しかしそうなると、使われなくなった &lt;code&gt;$env:FNM_MULTISHELL_PATH&lt;/code&gt; の掃除を自力でする必要が出てくる。
&lt;code&gt;fnm env&lt;/code&gt; の度に処理系へのシンボリックリンクが作成されるので、掃除はこまめに行う必要がある(だからこそ Temp フォルダに作成しているのだろうけど)。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fnm&lt;/code&gt; 自体には手動でこのシンボリックリンクを消すコマンドもないみたいなので、とりあえずは PowerShell の Profile で古いやつを消す様にするのが妥当なラインかな。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# てきとーにこんなのを想像&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$env:FNM_MULTISHELL_PATH&lt;/span&gt;/../ | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; CreationTime &lt;span class=&quot;hljs-operator&quot;&gt;-LE&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt;).AddDays(&lt;span class=&quot;hljs-literal&quot;&gt;-1&lt;/span&gt;) | &lt;span class=&quot;hljs-built_in&quot;&gt;Remove-Item&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description><pubDate>Sun, 26 Dec 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-12-04-pyenv-win.html</guid><link>https://krymtkts.github.io/posts/2021-12-04-pyenv-win.html</link><title>pyenv-win</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;Python の処理系をローカルに直で入れることに抵抗はなかったのだが、chocolatey で Python3 を入れていると pin でもしない限りバージョンが進んでいって処理系が乱雑に配置されるので、Python 自体のバージョン管理をすることにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/pyenv-win/pyenv-win&quot; title=&quot;pyenv-win/pyenv-win: pyenv for Windows. pyenv is a simple python version management tool. It lets you easily switch between multiple versions of Python. It&amp;#39;s simple, unobtrusive, and follows the UNIX tradition of single-purpose tools that do one thing well.&quot;&gt;pyenv-win/pyenv-win: pyenv for Windows. pyenv is a simple python version management tool. It lets you easily switch between multiple versions of Python. It&amp;#39;s simple, unobtrusive, and follows the UNIX tradition of single-purpose tools that do one thing well.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;事前に Windows が Microsoft Store アプリの Python を使わないようにしておく必要がある。これがクソめんどい。以下は &lt;code&gt;README.md&lt;/code&gt; からの引用。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE: If you are running Windows 10 1905 or newer, you might need to disable the built-in Python launcher via Start &amp;gt; &amp;quot;Manage App Execution Aliases&amp;quot; and turning off the &amp;quot;App Installer&amp;quot; aliases for Python&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Win キーを押下して &amp;quot;Manage App Execution Aliases&amp;quot; をタイプするのが現状の最速と思うが、できたら &lt;code&gt;ms-settings&lt;/code&gt; スキームで一発で飛べたら良いのに(&lt;code&gt;ms-settings:appsfeatures&lt;/code&gt;で手前まで行くのが精一杯)。&lt;/p&gt;
&lt;p&gt;わたしは chocolatey ユーザなので、 chocolatey でこの pyenv をインストールした。この場合環境変数の設定が chocolatey により行われるので幾分サボれる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://community.chocolatey.org/packages/pyenv-win#psdsc&quot; title=&quot;Chocolatey Software | pyenv-win 2.64.11&quot;&gt;Chocolatey Software | pyenv-win 2.64.11&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;わたしの場合は chocolatey 操作とゴミを消すのだけ管理者権限が必要なようにしてるのでそうしたが、それ以外は普通で行った。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;(pip freeze | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-StringData&lt;/span&gt;).Keys | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; requirements.txt &lt;span class=&quot;hljs-comment&quot;&gt;# モジュールを控える&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;choco uninstall python3 &lt;span class=&quot;hljs-literal&quot;&gt;-y&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; C:/Python* &lt;span class=&quot;hljs-literal&quot;&gt;-recurse&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-force&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# ゴミを消す&lt;/span&gt;&lt;br /&gt;choco install pyenv&lt;span class=&quot;hljs-literal&quot;&gt;-win&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-y&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;pyenv install &lt;span class=&quot;hljs-number&quot;&gt;3.9&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# まだ 3.10.0 がリリースキャンディデートしかなかったので&lt;/span&gt;&lt;br /&gt;pyenv global &lt;span class=&quot;hljs-number&quot;&gt;3.9&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;&lt;br /&gt;pyenv rehash &lt;span class=&quot;hljs-comment&quot;&gt;# バージョン切り替え後に必要&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;pip &lt;span class=&quot;hljs-literal&quot;&gt;--version&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# 確認&lt;/span&gt;&lt;br /&gt;python &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; pip install &lt;span class=&quot;hljs-literal&quot;&gt;--upgrade&lt;/span&gt; pip &lt;span class=&quot;hljs-comment&quot;&gt;# 更新してって出たので更新&lt;/span&gt;&lt;br /&gt;pip install &lt;span class=&quot;hljs-literal&quot;&gt;-r&lt;/span&gt; requirements.txt &lt;span class=&quot;hljs-comment&quot;&gt;# モジュール復元&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# done.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-code-requirements-txt-code-&quot; href=&quot;#-code-requirements-txt-code-&quot;&gt;バージョン移行時の &lt;code&gt;requirements.txt&lt;/code&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;バージョン乗り換え時の &lt;code&gt;requirements.txt&lt;/code&gt; の作成だが、単純に &lt;code&gt;pip freeze&lt;/code&gt; の出力を使うとバージョン不整合で取り込めないことがある。
なのでわたしの場合は雑にモジュール名だけにフィルタリングしたものを使う。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;(pip freeze | &lt;span class=&quot;hljs-built_in&quot;&gt;ConvertFrom-StringData&lt;/span&gt;).Keys | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Content&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description><pubDate>Sat, 04 Dec 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-11-27-psmfattendance.html</guid><link>https://krymtkts.github.io/posts/2021-11-27-psmfattendance.html</link><title>PowerShell で Money Forward クラウド勤怠を操作する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;現職について 2 ヶ月が経とうとしているが、まだ爆殺されてない。ので馴染んできているのかも知れない。コミュニケーションが少なくても(定例を除き、最少 DM1 通/週とか)何とかやっていけるものだなという気づきを得た。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;現職では勤怠の管理に Money Forward クラウド勤怠を利用している(時間管理なのだ)。
始めに書いておくと、勤怠管理システムはなんでか知らんがそれぞれに特色があって、どのツールを使っても一癖あるモノだというのがわたしの見解。その中でも Money Forward クラウド勤怠は悪くない印象だ。&lt;/p&gt;
&lt;p&gt;しかし、わたしという人間がどうにもこうにも打刻という行為が大の苦手で、非常に億劫だ(労務管理の上で必要なんはわかるけど仕事の前後で打刻しないといけないとかワシら機械か、人間のやることじゃないと。某筋肉番組のショットガンタッチならいざ知らず)。&lt;/p&gt;
&lt;p&gt;プログラマというのは怠惰なので、ブラウザで一々アクセスして打刻ボタンを押すのも苦痛なのであって、即ち半自動化に至るのは自然なことだ。
自動化じゃなく半自動化なのがポイント。自動化したら勤務してないのに勤務してるみたいなやばいことになりかねへん。自動化できるケーパビリティを持ちつつも半自動で使うのが職業プログラマの倫理？&lt;/p&gt;
&lt;p&gt;そこでまず自分で作りたくないので誰かが書いたツールを探すと、&lt;a href=&quot;https://github.com/puhitaku/mfpy&quot; title=&quot;puhitaku/mfpy: MoneyForward クラウド勤怠といい感じに通信していい感じに打刻するやつ&quot;&gt;puhitaku/mfpy: MoneyForward クラウド勤怠といい感じに通信していい感じに打刻するやつ&lt;/a&gt; が見つかった。良さそう。&lt;/p&gt;
&lt;p&gt;でも PowerShell でどうしてもやりたかった。なので PowerShell で作った ↓&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/PSMFAttendance&quot; title=&quot;krymtkts/PSMFAttendance&quot;&gt;krymtkts/PSMFAttendance&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今は出退勤のリアルタイム打刻しかできない。今後、わたしがグータラできる水準まで高めるには次の機能が必要かなーと考えている。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;二重打刻防止&lt;ul&gt;
&lt;li&gt;なんと出勤や退勤が無限多重打刻できる仕様なので、これを防止したい&lt;ul&gt;
&lt;li&gt;そのためには勤怠実績の一覧を取得する機能が必要になる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;打刻のリマインド機能&lt;ul&gt;
&lt;li&gt;これは &lt;code&gt;*-ScheduledTask&lt;/code&gt; でなんとかでけへんかなと考えているが...やったことない&lt;ul&gt;
&lt;li&gt;過去にタスクスケジューラでスケジュール実行をしてたけど PowerShell でやりたいし&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;勤務実績の入力&lt;ul&gt;
&lt;li&gt;打刻忘れの場合この作業が必要なので&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;あと、PowerShell Gallery の登録まだなのでしないと。アレのやり方毎回忘れるし簡単な方法ないんかというのも悩みどころ。あの工程を&lt;code&gt;psake&lt;/code&gt; のタスクにまとめるのはなんかで見たことあるけど、初回は手でやるか。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;因みに自動化について利用規約に触れないか気になったのだが、見た感じ問題なさそうだった。
&lt;a href=&quot;https://biz.moneyforward.com/agreement/&quot; title=&quot;利用規約 | 会計ソフト マネーフォワード クラウド&quot;&gt;利用規約 | 会計ソフト マネーフォワード クラウド&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 27 Nov 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-10-30-toolchain-of-powershell.html</guid><link>https://krymtkts.github.io/posts/2021-10-30-toolchain-of-powershell.html</link><title>PowerShell のツールチェーン</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今更読んだ ↓&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devblogs.microsoft.com/powershell/powershellget-3-0-preview-11-release/#features-to-expect-in-coming-preview-releases&quot; title=&quot;PowerShellGet 3.0 Preview 11 Release - PowerShell Team&quot;&gt;PowerShellGet 3.0 Preview 11 Release - PowerShell Team&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;モジュールの依存性管理がくるっぽ。&lt;/p&gt;
&lt;p&gt;これを機に NuGet のバージョンレンジ記法を学ばないといけないかな。PowerShell 使うけど NuGet と直接的な縁ないので触れずに来た。
&lt;a href=&quot;https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges-and-wildcards&quot; title=&quot;NuGet Package Version Reference | Microsoft Docs&quot;&gt;NuGet Package Version Reference | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;それはさておき、先述の PowerShellGet のネタはまだ正式なものでもなく、プレビュー機能が来てるわけでもない。だから今はまだ従来の術を使うのが良いだろうと考えている。
真面目に PowerShell 開発したことがないので、その辺の知ってるモジュールを棚卸しし、調べ直した。&lt;/p&gt;
&lt;p&gt;ここに書いたあるような内容は、PowerShell で書かれているアプリの GitHub repo を見たらだいたい出てくるのじゃないだろうか。
わたしの場合は、&lt;a href=&quot;https://github.com/jasonmarcher/poco&quot; title=&quot;jasonmarcher/poco&quot;&gt;jasonmarcher/poco&lt;/a&gt;で初めて&lt;code&gt;psakefile.ps1&lt;/code&gt;を見つけてそこから世界へ踏み入れた感じ。&lt;/p&gt;
&lt;p&gt;そして、この記事をまとめているときに「ああそういえば Awesome 〇〇ってあったなー」と思いググると、PowerShell 版も見つかったので置いておく。この記事に書いたツールチェーンは全部 Awesome の方に載ってた...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/janikvonrotz/awesome-powershell&quot; title=&quot;janikvonrotz/awesome-powershell: A curated list of delightful PowerShell modules and resources&quot;&gt;janikvonrotz/awesome-powershell: A curated list of delightful PowerShell modules and resources&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;ビルド&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;PowerShell はスクリプトなのでコンパイルはないが、静的解析・テスト・パッケージング等のことをひっくるめて、ここではビルドと呼ぶことにする。&lt;/p&gt;
&lt;p&gt;やはり&lt;a href=&quot;https://github.com/psake&quot; title=&quot;psake&quot;&gt;psake&lt;/a&gt; が有名でしょう。&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;psake/psake&quot;&gt;psake/psake&lt;/a&gt; は基盤のようなもので、汎用的なビルドタスクなんかは&lt;a href=&quot;https://github.com/psake/PowerShellBuild&quot; title=&quot;psake/PowerShellBuild&quot;&gt;psake/PowerShellBuild&lt;/a&gt;に定義されている。
肝心の&lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;psake/psake&quot;&gt;psake/psake&lt;/a&gt;のビルドには自身ではなく&lt;a href=&quot;https://github.com/RamblingCookieMonster/BuildHelpers&quot; title=&quot;RamblingCookieMonster/BuildHelpers&quot;&gt;RamblingCookieMonster/BuildHelpers&lt;/a&gt;が使われているというのがこれまたややこしい。
&lt;a href=&quot;https://github.com/RamblingCookieMonster/BuildHelpers&quot; title=&quot;RamblingCookieMonster/BuildHelpers&quot;&gt;RamblingCookieMonster/BuildHelpers&lt;/a&gt;それ自身は、CI/CD シナリオで使えるヘルパーだぜ？と自称しているだけあり、その用途(GitHub Actions)で使われている&lt;/p&gt;
&lt;p&gt;因みに&lt;a href=&quot;https://github.com/nightroman/Invoke-Build&quot; title=&quot;Invoke-Build&quot;&gt;Invoke-Build&lt;/a&gt;なんていうのもいて、これは使ったことない。GitHub のグラフはこちらの方が比較的アクティブかな。
README.md 見る限り&lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;psake&quot;&gt;psake&lt;/a&gt;よりも使いやすいぜ！って書いてあるので、何か大変なことでもあったのかなと勘ぐってしまう。
わたしはまだ真面目に使い込めていないこともあり、&lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;psake&quot;&gt;psake&lt;/a&gt;の闇を知らないだけかも知れない。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;依存性管理&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;モジュールあるところに依存性管理あり。PowerShell も例に漏れずある。
&lt;a href=&quot;https://github.com/RamblingCookieMonster/PSDepend&quot; title=&quot;RamblingCookieMonster/PSDepend&quot;&gt;RamblingCookieMonster/PSDepend&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;話は変わるが、&lt;a href=&quot;https://github.com/RamblingCookieMonster&quot; title=&quot;RamblingCookieMonster (Warren Frame)&quot;&gt;RamblingCookieMonster (Warren Frame)&lt;/a&gt;さんは他にも PowerShell のツールを色々書かれている。
&lt;a href=&quot;https://github.com/RamblingCookieMonster/PSDeploy&quot; title=&quot;RamblingCookieMonster/PSDeploy&quot;&gt;RamblingCookieMonster/PSDeploy&lt;/a&gt;だったり、わたしも最近所用で使った&lt;a href=&quot;https://github.com/RamblingCookieMonster/PSSlack&quot; title=&quot;RamblingCookieMonster/PSSlack&quot;&gt;RamblingCookieMonster/PSSlack&lt;/a&gt;だったり(最新の API に対応してないけど)。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;テスト/静的解析&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/pester/Pester&quot; title=&quot;pester/Pester&quot;&gt;pester/Pester&lt;/a&gt; しか知らん。BDD スタイルでクールよね。
&lt;a href=&quot;https://github.com/PowerShell/PSScriptAnalyzer&quot; title=&quot;PowerShell/PSScriptAnalyzer&quot;&gt;PowerShell/PSScriptAnalyzer&lt;/a&gt; しか知らん。
いずれも開発もアクティブだし唯一無二か？&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Awesome ~ を見つけたことだし、他にも色々見てみるか。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;と書いたがどう考えても有名じゃない。わたしも知ったの 2,3 年くらい前。最近は repo のグラフもほとんど息してなく見える。「枯れてる」のかも知れんけど。 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sat, 30 Oct 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-09-28-jobchange-2021.html</guid><link>https://krymtkts.github.io/posts/2021-09-28-jobchange-2021.html</link><title>転職する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;転職する。2021-10-01 から新しい会社だ。&lt;/p&gt;
&lt;p&gt;前職(まだ退職日を迎えていないが便宜上こう呼ぶ)に決定的な不満があったわけではなく、諸々の条件で現状を上回るオファーをもらったのが大きい。
以下に判断時の Good/Bad を一覧す。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Good&lt;ul&gt;
&lt;li&gt;いま GCP、そのうち Azure を加えてマルチクラウド&lt;/li&gt;&lt;li&gt;GitHub&lt;/li&gt;&lt;li&gt;少人数チームでの開発&lt;/li&gt;&lt;li&gt;額面年収 3 桁万 UP&lt;/li&gt;&lt;li&gt;みなし残業の上限が下がる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;Bad&lt;ul&gt;
&lt;li&gt;確定拠出年金がない&lt;/li&gt;&lt;li&gt;超成果主義&lt;/li&gt;&lt;li&gt;レッドオーシャン？&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;お話を伺った限り、自分が貢献できそうなテーマも色々ある感じだったし、「やってみたいこと」のような挑戦に対する Welcome な姿勢がとても印象的だった。
正直なところ選考らしい選考された覚えなく、「一緒に働いてみないとわからない」という CTO の観点のもと採用判断されている。そのため入ってからパフォ出せなかったら多分盛大に爆死するんだろうなと。そこだけは不安なのだが、それこそ「働いてみないとわからない」。
とはいえ、自分も地べた這いずる中の下のエンジニアとはいえ 15 年以上の経験があるので、貢献できることがあるだろうという前向きな姿勢ではある。
(全く手も足も出せずに爆殺されるかも知れんけど。)&lt;/p&gt;
&lt;p&gt;やるのは久しぶりの通信系アプリ。dotnet も仕事で使うのは 10 年ぶりか。
なんでもやりたいマンなので、入社後じわじわ守備範囲を広めていくイメージをしている。&lt;/p&gt;
&lt;p&gt;今回で 4 回目の転職だが、えんじにゃー転職はリモートワークの普及で大きく景色を変えたような印象があった。どこも DX()で人手がほしいことも重なってか。事実今回の転職は大阪の人材を買い叩く流れで採用いただいたわけである。&lt;/p&gt;
&lt;p&gt;心残りがなかったわけではない。前職の辞め方、個人的には引き継ぎは最低限やったけど、あまりいい辞め方ではなかったなと思っている。自分がやり始めてとっちらかっていることが多い状態で、今やめるのもなーと考えていた。
とはいえ自分の人生をより良くできるのは自分自身だ。そのためには今いる環境に変化をもたらすか、あるいは環境を別の環境に変えてしまうかしかない。
2 年ちょっとの在籍期間は前者の行動をしてたが、今回は後者を選択したと。&lt;/p&gt;
&lt;p&gt;この日記は、入社半年とか 1 年後、または爆死時とかの区切りで読み返そうと思う。
わたし自身も、このうねり狂う変化の波を乗りこなせるかのチャレンジ一年生なのである。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;休みの間に、積んでた HADES をやり始めた。死にゲーで最高。時間が溶ける...&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Tue, 28 Sep 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-08-30-patch-to-vscode-extension.html</guid><link>https://krymtkts.github.io/posts/2021-08-30-patch-to-vscode-extension.html</link><title>VS Code の拡張機能に ローカル patch する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;VS Code の拡張機能にバグがある場合、メンテナが Marketplace に修正版を公開するのを待つ以外にも、自力で修正する方法がある。
ちょうどよく使っている&lt;a href=&quot;https://github.com/michalyao/evermonkey&quot; title=&quot;michalyao/evermonkey&quot;&gt;michalyao/evermonkey&lt;/a&gt;が、壊れてしまってから 3 週間程経っても一向に対応されないので、その方法で一時的に回避した。&lt;/p&gt;
&lt;p&gt;Issue は以下の通り。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/michalyao/evermonkey/issues/161&quot; title=&quot;Evernote Error: 11 - Illegal to contain comments in ENML · Issue #161 · michalyao/evermonkey&quot;&gt;Evernote Error: 11 - Illegal to contain comments in ENML · Issue #161 · michalyao/evermonkey&lt;/a&gt;。&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;エラーの原因は&lt;a href=&quot;https://dev.evernote.com/doc/articles/enml.php&quot; title=&quot;ENML&quot;&gt;ENML&lt;/a&gt;が HTML コメントを許容しなくなったことで、 これにより upload できなくなってしまった。コメントを許容しないって記述は一見なさそうだが、Upload 時のエラーになってる。&lt;/p&gt;
&lt;p&gt;この&lt;a href=&quot;https://dev.evernote.com/doc/articles/enml.php&quot; title=&quot;ENML&quot;&gt;ENML&lt;/a&gt;の変更に対する Pull Request は&lt;a href=&quot;https://github.com/michalyao/evermonkey/pull/162&quot; title=&quot;ある&quot;&gt;ある&lt;/a&gt;のだが、どうでもいいところでコンフリクトしていたり、メンテナが忙しいのかチェックされていない状態にある。
すぐに修正を適用するには、この PR の patch を自分の VS Code に適用すればいい。&lt;/p&gt;
&lt;p&gt;VS Code の拡張機能は &lt;code&gt;~/.vscode/extensions&lt;/code&gt; にある&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;。今回の対象となるファイルは&lt;code&gt;converterplus.js&lt;/code&gt;。
PowerShell には&lt;code&gt;patch&lt;/code&gt;コマンドが無いので今回は手で patch した。
元は TypeScript で記述されているが、&lt;a href=&quot;https://github.com/cancastilho/evermonkey/commit/70991c155f08101d14a4ab4c64ad36d66f9850a3?branch=70991c155f08101d14a4ab4c64ad36d66f9850a3&amp;diff=split&quot; title=&quot;変更内容&quot;&gt;変更内容&lt;/a&gt;は素の JavaScript と同じなのでそのままコピペできる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;code &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; ~\.vscode\extensions\michalyao.evermonkey&lt;span class=&quot;hljs-literal&quot;&gt;-2&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;4.5&lt;/span&gt;\out\src\converterplus.js).FullName
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;↑ クソどうでもいいコードスニペット。
でも知らなかった点として、&lt;code&gt;~&lt;/code&gt;は PowerShell がユーザーディレクトリに評価するのでそのままだと VS Code に渡せなかった、というのがわかった記念に。&lt;/p&gt;
&lt;p&gt;変更が終わったら、 VS Code で&lt;code&gt;Developer: Reload Windows&lt;/code&gt;すれば拡張機能に施した変更が VS Code に取り込まれる。
因みにここでは&lt;code&gt;Developer: Restart Extension Host&lt;/code&gt;で良いはずだが、割と Extension Host を起動できない Notification が表示される。
それが面倒なので&lt;code&gt;Developer: Reload Windows&lt;/code&gt;で丸ごと再起動している。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;これで無事に Evernote を利用できる状況まで戻った。でもこのままメンテナが音信不通だとこの拡張機能を VS Code で使い続けることも難しくなりそう。こりゃ参ったね。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://vscode-docs.readthedocs.io/en/stable/extensions/install-extension/&quot; title=&quot;Install extension - vscode-docs&quot;&gt;Install extension - vscode-docs&lt;/a&gt; &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Mon, 30 Aug 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-07-18-psake-completion.html</guid><link>https://krymtkts.github.io/posts/2021-07-18-psake-completion.html</link><title>psake の Task 名を自動補完する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;ほぼ趣味レベルなのだが、所謂タスクランナーとして&lt;a href=&quot;https://github.com/psake/psake&quot; title=&quot;psake&quot;&gt;psake&lt;/a&gt;を使っている。趣味レベルなのは、Go とか Python とかでは &lt;code&gt;make&lt;/code&gt; を使うので &lt;code&gt;psake&lt;/code&gt; を製品コードでは使ったことなくて、自分の細々とした面倒な処理をスクリプト化してまとめるのに &lt;code&gt;psake&lt;/code&gt; を使ってるからだ。&lt;/p&gt;
&lt;p&gt;そんな訳で利用頻度も高くなかったのだが、なんか最近は AWS のリソースを操作するニッチなスクリプト(例えば開発環境とかステージング環境だけに使うようなやつ)が大量にあって、それをまとめるのに使い出した。
その御蔭で利用頻度が高まり、いやーよくできたツールやな～などと改めて思っていたが、今まで不満に感じなかった自動補完がないことがストレスになってきた。タスクが増え過ぎて名前が覚えられないのだ。&lt;/p&gt;
&lt;p&gt;ｷﾞｯﾊﾌﾞの repo を確認すると、古の&lt;code&gt;TabExpansion&lt;/code&gt;版はあれど、今どきの&lt;code&gt;Register-ArgumentCompleter&lt;/code&gt;版がない。
&lt;a href=&quot;https://github.com/psake/psake/blob/master/tabexpansion/PsakeTabExpansion.ps1&quot; title=&quot;psake/PsakeTabExpansion.ps1 at master · psake/psake&quot;&gt;psake/PsakeTabExpansion.ps1 at master · psake/psake&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今更&lt;code&gt;TabExpansion&lt;/code&gt;使いたくないので、&lt;code&gt;Register-ArgumentCompleter&lt;/code&gt;用に合わせてこしらえた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/krymtkts/b2e6742691fdca6ca09567ca146063df&quot; title=&quot;This is Register-ArgumentCompleter version of https://github.com/psake/psake/blob/master/tabexpansion/PsakeTabExpansion.ps1.&quot;&gt;This is Register-ArgumentCompleter version of https://github.com/psake/psake/blob/master/tabexpansion/PsakeTabExpansion.ps1.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;使ってみていまんとこ良さそうな感じ。問題なさそうなら本家に PRO ぶん投げてみてもいいかもね。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;以下は&lt;code&gt;Register-ArgumentCompleter&lt;/code&gt;のスクリプトブロックをデバッグするときの個人的メモ。&lt;/p&gt;
&lt;p&gt;その時の入力でトリガーされたスクリプトブロックの引数を確認するのに &lt;code&gt;Write-Host&lt;/code&gt; とか使うと厄介だと思うので、ログファイル的なものをこしらえておき、別窓で&lt;code&gt;tail&lt;/code&gt;してあげると見易くなる(と思っている)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Register-ArgumentCompleter&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-CommandName&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-Psake&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ParameterName&lt;/span&gt; taskList &lt;span class=&quot;hljs-literal&quot;&gt;-ScriptBlock&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$commandName&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$parameterName&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$wordToComplete&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$commandAst&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$fakeBoundParameters&lt;/span&gt;)&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$commandName&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$parameterName&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$wordToComplete&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$commandAst&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$fakeBoundParameters&lt;/span&gt;&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; test.log&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$commandAst&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;(?&amp;lt;file&amp;gt;[^\.]*\.ps1)&amp;#x27;&lt;/span&gt;) {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$Matches&lt;/span&gt;.file&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;YEAH&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; test.log&lt;br /&gt;    }&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;psakefile.ps1&amp;#x27;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;DEFAULT&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; test.log&lt;br /&gt;    }&lt;br /&gt;    &amp;amp; &lt;span class=&quot;hljs-variable&quot;&gt;$commandName&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-buildFile&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-docs&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-nologo&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-String&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Stream&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; { &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-match&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;^[^ ]*&amp;quot;&lt;/span&gt;) { &lt;span class=&quot;hljs-variable&quot;&gt;$matches&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] } } | `&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-notin&lt;/span&gt; (&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Name&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;----&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;) } | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; { !&lt;span class=&quot;hljs-variable&quot;&gt;$wordToComplete&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-or&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-like&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$wordToComplete&lt;/span&gt;*&amp;quot;&lt;/span&gt; }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; .\test.log &lt;span class=&quot;hljs-literal&quot;&gt;-Wait&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Tail&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Invoke-psake, taskList, I, invoke-psake -buildFile .\psakefile.ps1 -taskList I, System.Collections.Hashtable&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Invoke-psake, taskList, In, invoke-psake -taskList In, System.Collections.Hashtable&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# DEFAULT&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Invoke-psake, taskList, I, invoke-psake -buildFile .\psakefile.ps1 -taskList I, System.Collections.Hashtable&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# YEAH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;どーでもいーけどこの日記の deploy をｷﾞｯﾊﾌﾞｱｸｼｮﾝ化したい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;追記。&lt;/p&gt;
&lt;p&gt;デバッグ中に気づいたのだが、プロファイル内で &lt;code&gt;$psake&lt;/code&gt; という変数を作ると &lt;code&gt;Invoke-psake&lt;/code&gt; が壊れるという事に気づいた。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;🤖 takatoshi  &lt;span class=&quot;hljs-built_in&quot;&gt;invoke-psake&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-nologo&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt;: C:\Program Files\PowerShell\Modules\psake\&lt;span class=&quot;hljs-number&quot;&gt;4.9&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\private\&lt;span class=&quot;hljs-built_in&quot;&gt;Get-DefaultBuildFile&lt;/span&gt;.ps1:&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;&lt;br /&gt;Line |&lt;br /&gt;   &lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt; |      &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;test-path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$psake&lt;/span&gt;.config_default.buildFileName &lt;span class=&quot;hljs-literal&quot;&gt;-pathType&lt;/span&gt; Leaf) …&lt;br /&gt;     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;     | Value cannot be null. (&lt;span class=&quot;hljs-keyword&quot;&gt;Parameter&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;The provided Path argument was null or an empty collection.&amp;#x27;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Test-Path&lt;/span&gt;: C:\Program Files\PowerShell\Modules\psake\&lt;span class=&quot;hljs-number&quot;&gt;4.9&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\private\&lt;span class=&quot;hljs-built_in&quot;&gt;Get-DefaultBuildFile&lt;/span&gt;.ps1:&lt;span class=&quot;hljs-number&quot;&gt;11&lt;/span&gt;&lt;br /&gt;Line |&lt;br /&gt;  &lt;span class=&quot;hljs-number&quot;&gt;11&lt;/span&gt; |  …   } &lt;span class=&quot;hljs-keyword&quot;&gt;elseif&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;test-path&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$psake&lt;/span&gt;.config_default.legacyBuildFileName &lt;span class=&quot;hljs-literal&quot;&gt;-path&lt;/span&gt; …&lt;br /&gt;     |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;     | Value cannot be null. (&lt;span class=&quot;hljs-keyword&quot;&gt;Parameter&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;The provided Path argument was null or an empty collection.&amp;#x27;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;InvalidOperation: C:\Program Files\PowerShell\Modules\psake\&lt;span class=&quot;hljs-number&quot;&gt;4.9&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\public\&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-psake&lt;/span&gt;.ps1:&lt;span class=&quot;hljs-number&quot;&gt;327&lt;/span&gt;&lt;br /&gt;Line |&lt;br /&gt; &lt;span class=&quot;hljs-number&quot;&gt;327&lt;/span&gt; |          &lt;span class=&quot;hljs-variable&quot;&gt;$psake&lt;/span&gt;.build_success = &lt;span class=&quot;hljs-variable&quot;&gt;$false&lt;/span&gt;&lt;br /&gt;     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;     | The property &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;build_success&amp;#x27;&lt;/span&gt; cannot be found on this object. Verify that the property exists and can be &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;罠すぎる...&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 18 Jul 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-07-11-my-terminal-icons.html</guid><link>https://krymtkts.github.io/posts/2021-07-11-my-terminal-icons.html</link><title>Terminal-Icons のアイコングリフのコードポイントを変えたい</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;先日、&lt;a href=&quot;/posts/2021-07-01-i-want-to-change-codepoint.html&quot; title=&quot;わたしの改造 Migu で Terminal-Icons の見栄えが悪い話&quot;&gt;わたしの改造 Migu で Terminal-Icons の見栄えが悪い話&lt;/a&gt;を書いた。
あの後、チマチマ作業を行い、ある程度納得の行くものが出来上がったのでまとめておく。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;まず、先日の記事に書いていた豆腐は、ありゃー Material Design Icons を改造 Migu に組み込んでいないからであった。無知蒙昧。
あと Weather Icons もいらねーだろと思ってたしてなかったが、この際なので打ち込んじまえ！と意気込み処置を行うた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/fontmerger/commit/81681e6de10149ed34dda60e9b6b806374efa472&quot; title=&quot;Add fonts. · krymtkts/fontmerger@81681e6&quot;&gt;Add fonts. · krymtkts/fontmerger@81681e6&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/fontmerger/commit/44c72fc3cc6cbabb44d25c3268d4191f81c78fed&quot; title=&quot;Update font settings. · krymtkts/fontmerger@44c72fc&quot;&gt;Update font settings. · krymtkts/fontmerger@44c72fc&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Weather Icons は、なんか知らんがサイズを調整してパッチすると結構縦長になってしまってた。
が、ちょっと前に足しといた縦比/横比だけ調整するパラメータがいい感じに使え、我ながら先見の明を感じた(何&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/fontmerger/commit/7653e06d1f106b8dbcc01f30dc9ea25c175a3916&quot; title=&quot;Split scale option to x and y scale. Add force_narrow option that for… · krymtkts/fontmerger@7653e06&quot;&gt;Split scale option to x and y scale. Add force_narrow option that for… · krymtkts/fontmerger@7653e06&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;こうしてまたさらにイイカンジの Migu になったところで、Terminal-Icons の&lt;code&gt;glyphs.ps1&lt;/code&gt;を上書きするモンをこしらえて完成とした。
ブツは Gist に上げた → &lt;a href=&quot;https://gist.github.com/krymtkts/4457a23124b2db860a6b32eba6490b03&quot; title=&quot;my Terminal-Icons glyphs.&quot;&gt;my Terminal-Icons glyphs.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Material Design Icons はコードポイントがわかりやすくずれるだけなので機械的にずらすだけで OK だった。
Weather Icons と Octicons あたりは Nerd Fonts ではよくわからん順番に組み替えてるようだった。
コード読むのめんどかったので、モウ泥臭くヒューマンマニピュレーションにて処置...気が遠くなるかと思いきや割とすぐできた感じではある。
あと&lt;code&gt;glyphs.ps1&lt;/code&gt;を直接上書きするパワースタイルなので、なんか後から差し込めるようにしたい気はする。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2021-07-11-terminal/icons.png&quot; title=&quot;きれいなアイコンたち&quot; alt=&quot;きれいなアイコンたち&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;全く関係ないが最近マイ Iris がやたらとチャタリングするようになてムカつくぜぇぇぇ...
ホコリが接点に侵入してるんやと思うんやけど、掃除しても掃除しても数日で再発する。
でもファミコンのカートリッジスタイルでフーッ！！すると割と改善する...そんな日々。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 11 Jul 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-07-01-i-want-to-change-codepoint.html</guid><link>https://krymtkts.github.io/posts/2021-07-01-i-want-to-change-codepoint.html</link><title>Terminal-Icons のアイコングリフのコードポイントを変えたい</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;2021 年 5 月から、法律による上限スレスレの時間外＆休日労働だったため、すっかりブログを認めるのを忘れていた。
なのでこの記事は 6 月分のつもりで書いている(言い訳)。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;さて、先月に現時点自分史上最高の Migu フォントを生み出したわけだが、実用において完全に気になるポイントがないわけではない。
その実、前から抱えていた幾つかの課題がそれなのだけど。&lt;/p&gt;
&lt;p&gt;fontmerger を使って日本語フォントにパッチする場合、漢字が割り当てられているコードポイントにアイコングリフが割り当てられないように、コードポイントをずらす機能がついている。
当然の如く、わたしの Migu を作るためのパッチでもコードポイントをずらしている。&lt;/p&gt;
&lt;p&gt;するとですね、&lt;a href=&quot;https://github.com/devblackops/Terminal-Icons/&quot; title=&quot;devblackops/Terminal-Icons&quot;&gt;devblackops/Terminal-Icons&lt;/a&gt;は &lt;a href=&quot;https://github.com/devblackops/Terminal-Icons/blob/eeb5ce85d4a1882b5155bd6f06859a4b6f4b44d8/psakeFile.ps1#L28&quot; title=&quot;https://www.nerdfonts.com/cheat-sheet から自動生成した標準のコードポイント&quot;&gt;https://www.nerdfonts.com/cheat-sheet から自動生成した標準のコードポイント&lt;/a&gt; で以てフィアルやディレクトリのアイコンを表示するので...わたしの Migu だと豆腐になるアイコンがちらほらいるわけですね。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2021-07-01-terminal/icon-tofu.png&quot; title=&quot;豆腐アイコン&quot; alt=&quot;豆腐アイコン&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;偶然にも、「栗」がアイコンに割り当てられてしまっているところもあったり。この動機づけはシンクロニシティやろ！&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2021-07-01-terminal/stop-is-chestnut.png&quot; title=&quot;停止は栗&quot; alt=&quot;停止は栗&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;前まではアイコンがぶっ壊れ気味の Migu を使っていたので、割れ窓理論的に気にならなかった豆腐が、最近妙に気になってきたわけだ。&lt;/p&gt;
&lt;p&gt;Terminal-Icons のドキュメントやコードを見ても、先述の自動生成したコードポイント表(&lt;a href=&quot;https://github.com/devblackops/Terminal-Icons/blob/main/Terminal-Icons/Data/glyphs.ps1&quot; title=&quot;Terminal-Icons/glyphs.ps1&quot;&gt;Terminal-Icons/glyphs.ps1&lt;/a&gt;)を差し替えたりできるような仕組みはないようなので、一旦はこのスクリプト自体にパッチを当てる方向で考えよかなと考え中。&lt;/p&gt;
&lt;p&gt;4000 行近くあるとはいえ、その中から普段使うアイコンに絞れば数は少ないと思うから、とりま手でﾎﾟﾘﾎﾟﾘコードポイントを変えようかなと(さっきのキャプチャだけでも 3 つ豆腐並んでてヒット率高すぎ感はあるが)。&lt;/p&gt;
&lt;p&gt;とはいえ英語圏じゃない人のフォントはわたしと同じ問題を抱えてるかもしれないので、なんかグリフのコードポイント変えさせてくれや～、という機能をプルリしてもいいかもしれない。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Thu, 01 Jul 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-05-30-maybe-completed-refining-migu-nerd-font.html</guid><link>https://krymtkts.github.io/posts/2021-05-30-maybe-completed-refining-migu-nerd-font.html</link><title>Migu Nerd Font の改善が完了したっぽい</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;(2021-05-16 に書いたまま投稿するのを忘れていた)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2021-05-07-i-want-to-resize-migu-icon.html&quot; title=&quot;以前&quot;&gt;以前&lt;/a&gt;の続き。まだやってる。&lt;/p&gt;
&lt;p&gt;横も縦も微妙にサイズが合わないのであれば、強制的に矯正するしかない！ということでまた fontmerger に機能追加した。&lt;a href=&quot;https://fontforge.org/docs/scripting/python/fontforge.html#fontforge.contour.boundingBox&quot; title=&quot;contour.boundingBox&quot;&gt;contour.boundingBox&lt;/a&gt;は結局やめた。今のコードでもフォント設定を分ければ実現が容易だったからだ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;フォントごとの &lt;code&gt;scale&lt;/code&gt; オプションを x,y 軸で 2 つのオプション(&lt;code&gt;scale_x&lt;/code&gt;, &lt;code&gt;scale_y&lt;/code&gt;)に分割&lt;/li&gt;&lt;li&gt;narrow 幅に矯正する &lt;code&gt;force_narrow&lt;/code&gt; オプションを追加&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/fontmerger/commit/690830d0842a21445d7ca4e3aa367e1bbf859c31&quot; title=&quot;Split scale option to x and y scale. Add force_narrow option that for… · krymtkts/fontmerger@690830d&quot;&gt;Split scale option to x and y scale. Add force_narrow option that for… · krymtkts/fontmerger@690830d&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;コードは愚直に書いただけで Cognitive Complexy が 16 を突破してしまったが、期待の通りのフォント変換ができた模様。
これにより残念だった Powerline の隙間・見切れ問題が解決したものと思う。これで現時点では完璧や...という Migu になったので当分は使用を確かめてみようと思う。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2021-05-16-terminal/mypowerline.png&quot; title=&quot;現在のpowerline&quot; alt=&quot;現在のpowerline&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;お亡くなりになられた fontmerger を Python3 化して動かす&lt;/label&gt;&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;最新の Migu に対して fontmerger で Nerd font patch する&lt;/label&gt;&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;&lt;/label&gt;&lt;code&gt;0xE0B0&lt;/code&gt; を始めとした Cascadia でだけうまく表示されるグリフを Migu に移植する&lt;ul&gt;
&lt;li&gt;そして効果なし！&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;Nerd Fonts の font-patcher で Migu にパッチしてみる&lt;/label&gt;&lt;ul&gt;
&lt;li&gt;フォントが使い物にならなくなった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;Migu のチャーミングな部分を M+に移植&lt;/label&gt;&lt;ul&gt;
&lt;li&gt;縦横比の違いから縦長に...&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;font-merger がパッチするグリフのみ narrow 幅にしてみる&lt;/label&gt;&lt;ul&gt;
&lt;li&gt;おしい！右よりフォントが残念&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;font-merger の scale オプションを x,y で分割、強制 narrow 幅オプション追加&lt;/label&gt;&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;完璧な Migu の完成！&lt;/label&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;完&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 30 May 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-05-07-i-want-to-resize-migu-icon.html</guid><link>https://krymtkts.github.io/posts/2021-05-07-i-want-to-resize-migu-icon.html</link><title>Migu Nerd Font のアイコンフォントを narrow にしたい</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2021-04-11-consideration-of-difference-between-cascadia-and-migu.html&quot; title=&quot;以前&quot;&gt;以前&lt;/a&gt;、Nerd Fonts の&lt;code&gt;font-patcher&lt;/code&gt;で Migu に Narrow サイズの Symbol グリフぶちこみゃええやんけ、まで来てた。
その後を記す。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;Nerd-Fonts&quot; href=&quot;#Nerd-Fonts&quot;&gt;Nerd Fonts&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Nerd Font の font-patcher を試す。事前にパッチ済みの M+を見ると完璧なので期待に胸が高ぶる。実行してみると Python モジュールに Windows のライブラリが含まれていたので WSL2 内の Ubuntu では実行できなかった。Windows で実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;fontforge &lt;span class=&quot;hljs-literal&quot;&gt;-script&lt;/span&gt; font&lt;span class=&quot;hljs-literal&quot;&gt;-patcher&lt;/span&gt; migu&lt;span class=&quot;hljs-literal&quot;&gt;-1m-regular&lt;/span&gt;.ttf &lt;span class=&quot;hljs-literal&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-l&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--careful&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--progressbars&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-out&lt;/span&gt; patched
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;結果、全然アカン... &lt;code&gt;-s, --mono, --use-single-width-glyphs&lt;/code&gt;オプションを有効にすると全グリフが single-width になってしまい日本語フォントとして使いものにならなくなる。&lt;/p&gt;
&lt;p&gt;逆にこの完璧な M+が惚れ惚れする出来なので、こちらに半濁音を移植するだけでいい気がしてきた。&lt;/p&gt;
&lt;h3 &gt;&lt;a name=&quot;font-merger-&quot; href=&quot;#font-merger-&quot;&gt;font-merger 再び&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;コードポイントがわからないので、取得するための関数を PowerShell で作る。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;UC&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;CmdletBinding&lt;/span&gt;()]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt; (&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;Parameter&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;Mandatory&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;,&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;Position&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;ValueFromPipeline&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;,&lt;br /&gt;            &lt;span class=&quot;hljs-type&quot;&gt;ValueFromPipelineByPropertyName&lt;/span&gt; = &lt;span class=&quot;hljs-variable&quot;&gt;$true&lt;/span&gt;)]&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;ValidateNotNullOrEmpty&lt;/span&gt;()]&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;[]]&lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;process&lt;/span&gt; {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$c&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt;) {&lt;br /&gt;            [&lt;span class=&quot;hljs-type&quot;&gt;Convert&lt;/span&gt;]::ToInt32(&lt;span class=&quot;hljs-variable&quot;&gt;$c&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-as&lt;/span&gt; [&lt;span class=&quot;hljs-built_in&quot;&gt;char&lt;/span&gt;]).ToString(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;x&amp;quot;&lt;/span&gt;)&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;がぎぐげござじずぜぞだぢづでどばぱびぴぶぷべぺぼぽゔ&amp;#x27;&lt;/span&gt;+&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;+&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;+&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ゞガギグゲゴザジズゼゾダヂヅデドバパビピブプベペボポヴヷヸヹヺ&amp;#x27;&lt;/span&gt;).ToCharArray() | UC
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで置き換えたい文字(Migu のチャーミングな濁音半濁音たち)のコードポイントを取れるよにした。
特定のコードポイントの移植といえば font-merger 使えるやん！というところではあるが、ほしいコードポイントは連続せず細切れになっているので、これを 1 個ずつ設定に書くのはめんどい...
ということで font-merger の改造をした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/fontmerger/commit/33c775ef4f1fd47f90b6359f5ae74529552a87a6&quot; title=&quot;Add codepoint option to copy glyph from specific code points. · krymtkts/fontmerger@33c775e&quot;&gt;Add codepoint option to copy glyph from specific code points. · krymtkts/fontmerger@33c775e&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;/usr/bin/fontforge -script fontmerger/__init__.py -x migu-1m-regular -o patched --suffix=migu -- ./source/M+1mNerdFontCompleteWindowsCompatible.ttf
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コードポイントを個別に指定できるようにしまして実行したところ、なんかそれっぽく半濁点が反映されてる。
いや待てよ...微妙に縦長になってしまった...これは M+と Migu でフォントの縦横比が異なるせいやろな。&lt;/p&gt;
&lt;p&gt;もう FontForge のスクリプティング真面目にやってくしか残された将来はない気がしてきた。😰&lt;/p&gt;
&lt;h3 &gt;&lt;a name=&quot;font-merger-&quot; href=&quot;#font-merger-&quot;&gt;font-merger 再び 再び&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Nerd Fonts の font-patcher を読んでいるときに気づいたのが、&lt;code&gt;--mono&lt;/code&gt; オプションを有効にしている場合すべての glyph に narrow 幅を設定するようになっていたこと。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ryanoasis/nerd-fonts/blob/master/font-patcher#L71-L74&quot; title=&quot;nerd-fonts/font-patcher at master · ryanoasis/nerd-fonts · GitHub&quot;&gt;nerd-fonts/font-patcher at master · ryanoasis/nerd-fonts · GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;日本語フォントの場合 wide 幅を書き換えてしまうから先述の通り Nerf Fonts はえらいことになってしまっていたので、これをパッチするグリフにのみ適用すれば良いという力技に気づく。
ということで更に font-merger を改造した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/fontmerger/commit/25ed2b1dfd547d6599417793fb679ea9fdbe4548&quot; title=&quot;Adds mono command line option that forces glyph to be single width. · krymtkts/fontmerger@25ed2b1&quot;&gt;Adds mono command line option that forces glyph to be single width. · krymtkts/fontmerger@25ed2b1&lt;/a&gt;&lt;/p&gt;
&lt;h3 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;現状&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;これにより全ての追加したアイコングリフが narrow 幅になることで、漸く Windows Terminal でもﾐﾆﾐﾆアイコンフォントにならずに表示できるようになった。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2021-05-07-terminal/mypowerline.png&quot; title=&quot;現在のpowerline。左向き三角が残念&quot; alt=&quot;現在のpowerline。左向き三角が残念&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;しかしご覧の通り、右に寄るべきフォントの見た目が非常に残念なので、今後もちょいちょいいじらねばならない。完成はいつになるのか...😪
(幅 500 以上になってるためずれる)&lt;/p&gt;
&lt;p&gt;なんとなく、次は Powerline グリフの narrow 幅を大きく超過するものを左右の align をつけて変形しないといけない気がしている。
この辺の頂点の xmax, ymax からどないか計算できんかな →
&lt;a href=&quot;https://fontforge.org/docs/scripting/python/fontforge.html#fontforge.contour.boundingBox&quot; title=&quot;fontforge — FontForge 20201107 documentation&quot;&gt;fontforge — FontForge 20201107 documentation&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;お亡くなりになられた fontmerger を Python3 化して動かす&lt;/label&gt;&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;最新の Migu に対して fontmerger で Nerd font patch する&lt;/label&gt;&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;&lt;/label&gt;&lt;code&gt;0xE0B0&lt;/code&gt; を始めとした Cascadia でだけうまく表示されるグリフを Migu に移植する&lt;ul&gt;
&lt;li&gt;そして効果なし！&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;Nerd Fonts の font-patcher で Migu にパッチしてみる&lt;/label&gt;&lt;ul&gt;
&lt;li&gt;フォントが使い物にならなくなった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;Migu のチャーミングな部分を M+に移植&lt;/label&gt;&lt;ul&gt;
&lt;li&gt;縦横比の違いから縦長に...&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;font-merger がパッチするグリフのみ narrow 幅にしてみる&lt;/label&gt;&lt;ul&gt;
&lt;li&gt;おしい！右よりフォントが残念&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled  aria-label=&quot;Checkbox&quot; /&gt;完璧な Migu の完成！&lt;/label&gt;&lt;ul&gt;
&lt;li&gt;To Be Continued...&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;</description><pubDate>Fri, 07 May 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-05-06-simple-way-to-update-pwsh-special-module.html</guid><link>https://krymtkts.github.io/posts/2021-05-06-simple-way-to-update-pwsh-special-module.html</link><title>PowerShell の特殊なモジュールを更新する方法</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;code&gt;PSReadLine&lt;/code&gt; のような特殊な PowerShell モジュールを更新する術として、以下の方法を使うようにしている。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;管理者権限で起動したコマンドプロンプトから&lt;/li&gt;&lt;li&gt;非対話モードで&lt;/li&gt;&lt;li&gt;PSReadline を読み込んでるプロファイルを読み込まずに&lt;/li&gt;&lt;li&gt;プレリリース許可＆全ユーザ＆サイドバイサイド でインストール&lt;/li&gt;&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bat&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;REM 、かつ、-NonInteractive でPowerShell Coreを実行&lt;/span&gt;&lt;br /&gt;pwsh -NonInteractive -NoProfile -Command &amp;quot;Install-Module PSReadLine -AllowPrerelease -Scope AllUsers -Force&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;Remove-Module&lt;/code&gt; さえちゃんとできてたら更新できると思うんやけど、プロファイルとの組み合わせで意図せず&lt;code&gt;Import-Module&lt;/code&gt;してしまい、しょっちゅうエラーしてしまうので上記手順が楽。
ほんとは pwsh 内からいい感じに処理できればよいのだけどトラシューの時間をこんなとこに割きたくない関係で、更新の都度初手一発でうまくいく手順をやりがち。&lt;/p&gt;
&lt;p&gt;エラーになりがちな奴ら。ワイの profile が依存してる関係でエラーになりがち。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PSReadLine&lt;/li&gt;&lt;li&gt;PowerShellGet&lt;/li&gt;&lt;li&gt;posh-git&lt;/li&gt;&lt;li&gt;Pester&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_pwsh?view=powershell-7.1&quot; title=&quot;about_Pwsh - PowerShell | Microsoft Docs&quot;&gt;about_Pwsh - PowerShell | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Thu, 06 May 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-04-11-consideration-of-difference-between-cascadia-and-migu.html</guid><link>https://krymtkts.github.io/posts/2021-04-11-consideration-of-difference-between-cascadia-and-migu.html</link><title>Cascadia Code PL と Migu Nerd Font の違い</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;注意: アイコンフォントのコピペを多用しているので、対応していないフォントを使われている豆腐が見えます。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;TL-DR&quot; href=&quot;#TL-DR&quot;&gt;TL;DR&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;これはズブのフォント素人による try&amp;amp;error なので大いに間違っている可能性もある。&lt;/p&gt;
&lt;p&gt;結論から言うとまだ納得の行く改造版 Migu の作成には至っていない。&lt;/p&gt;
&lt;p&gt;Cascadia も Hack も Narrow な Powerline グリフが埋め込まれているっぽい。
ここに来て Migu に直接 Narrow な Powerline グリフを埋め込んだらええやんけ、という Nerd Fonts 回帰案が浮上した(うまく行った試しないのだけど)。&lt;/p&gt;
&lt;p&gt;To be Continued...&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;経緯&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;長年 Migu を愛用している。&lt;/p&gt;
&lt;p&gt;Migu の良さはそのスリムでシンプルな見栄えだけでなく、Proportional と Monospace で同じ字体を使えることだ。
しかし最近の開発環境で使うにはアイコンフォントが同梱されないことで不便を感じることが多い。特に Powerline を使っているとアイコンフォントは必須。
ということで 5 年ほど前から &lt;a href=&quot;https://github.com/iij/fontmerger&quot; title=&quot;iij/fontmerger&quot;&gt;iij/fontmerger&lt;/a&gt; を使って Nerd fonts などを追加した自作フォントを使っている。&lt;/p&gt;
&lt;p&gt;しかしこれがここ 1,2 年くらいで Windows Terminal を使い始めたことで納得いかない点が出てきた。
&amp;quot;Ambiguous&amp;quot;なフォントについては全部 Narrow サイズになる ≒ Certain なフォントについてはサイズが適用される？だと？&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/microsoft/terminal/pull/2928/commits&quot; title=&quot;TermControl: force all ambiguous glyphs to be narrow by DHowett-MSFT · Pull Request #2928 · microsoft/terminal&quot;&gt;TermControl: force all ambiguous glyphs to be narrow by DHowett-MSFT · Pull Request #2928 · microsoft/terminal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Windows Terminal とともに提供される &lt;a href=&quot;https://github.com/microsoft/cascadia-code&quot; title=&quot;Cascadia&quot;&gt;Cascadia&lt;/a&gt; に関してはどうもこの問題が発生しない。&lt;strong&gt;Powerline グリフに関しては完璧なのだ&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;フォント素人のわたしはこの時こう考えた。&lt;/p&gt;
&lt;p&gt;改造 Migu と Cascadia でコードポイントは同じだけどフォントを切り替えるだけで表示サイズが異なってくる。
→ つまり Cascadia フォントでは、コードポイント&lt;code&gt;0xE0B0&lt;/code&gt;とかになんかの情報を入れ込んでるのではないか？と...！&lt;/p&gt;
&lt;p&gt;グリフのサイズを目視確認するための一覧用コード。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Helper function to show Unicode character&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;U&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;&lt;br /&gt;    (&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hljs-variable&quot;&gt;$Code&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; ((&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-le&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Code&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;-and&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$Code&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-le&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;xFFFF)) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; [&lt;span class=&quot;hljs-built_in&quot;&gt;char&lt;/span&gt;] &lt;span class=&quot;hljs-variable&quot;&gt;$Code&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; ((&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;x10000 &lt;span class=&quot;hljs-operator&quot;&gt;-le&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$Code&lt;/span&gt;) &lt;span class=&quot;hljs-operator&quot;&gt;-and&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$Code&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-le&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;x10FFFF)) {&lt;br /&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; [&lt;span class=&quot;hljs-built_in&quot;&gt;char&lt;/span&gt;]::ConvertFromUtf32(&lt;span class=&quot;hljs-variable&quot;&gt;$Code&lt;/span&gt;)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Invalid character code &lt;span class=&quot;hljs-variable&quot;&gt;$Code&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 数値は[Convert]::ToInt32(&amp;#x27;0xE080&amp;#x27;, 16)でHEX変換する&lt;/span&gt;&lt;br /&gt;((&lt;span class=&quot;hljs-number&quot;&gt;170&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;61278&lt;/span&gt;) | %{U &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;}) &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;全然わからない...クソむずすぎる。でも特定のグリフを移植するだけなら、元々改造 Migu を作るのに使っていた fontmerger が利用できる。とおもてたら DEPRECATED になっておった、そら Python2 やからな...&lt;/p&gt;
&lt;p&gt;とりあえず最終目標までの段階的目標を立てた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;お亡くなりになられた fontmerger を Python3 化して動かす&lt;/li&gt;&lt;li&gt;最新の Migu に対して fontmerger で Nerd font patch する&lt;/li&gt;&lt;li&gt;&lt;code&gt;0xE0B0&lt;/code&gt; を始めとした Cascadia でだけうまく表示されるグリフを Migu に移植する&lt;/li&gt;&lt;li&gt;完璧な Migu の完成！&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;2021-03-13&quot; href=&quot;#2021-03-13&quot;&gt;2021-03-13&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Cascadia を CLI で簡単に落としてくる方法はないものか？&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; https://github.com/microsoft/cascadia&lt;span class=&quot;hljs-literal&quot;&gt;-code&lt;/span&gt;/releases/download/v2102.&lt;span class=&quot;hljs-number&quot;&gt;25&lt;/span&gt;/CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-2102&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;25&lt;/span&gt;.zip &lt;span class=&quot;hljs-literal&quot;&gt;-OutFile&lt;/span&gt; CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-2102&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;25&lt;/span&gt;.zip&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Expand-Archive&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; .\CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-2102&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;25&lt;/span&gt;.zip &lt;span class=&quot;hljs-literal&quot;&gt;-DestinationPath&lt;/span&gt; CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-2102&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;25&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; .\CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-2102&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;25&lt;/span&gt;\
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;                                                                                                                   &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-03-13&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;27&lt;/span&gt;&lt;br /&gt; takatoshi  ~\.\CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-2102&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;25&lt;/span&gt;  ll&lt;br /&gt;&lt;br /&gt;        Directory: C:\Users\takatoshi\desktop\CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-2102&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;25&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Mode                LastWriteTime         Length Name&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                &lt;span class=&quot;hljs-literal&quot;&gt;-------------&lt;/span&gt;         &lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-03-13&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;24&lt;/span&gt;                  otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-03-13&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;24&lt;/span&gt;                  ttf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-03-13&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;24&lt;/span&gt;                  woff2&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;フォントの拡張子がわからなくなったのでおさらい。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;otf ... Open Type Font&lt;ul&gt;
&lt;li&gt;Adobe と MS で作った。MS 商標。今や一般的。リガチャ使うならこっちしか無理&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;ttf ... True Type Font&lt;ul&gt;
&lt;li&gt;Apple 作った。プラットフォーム互換がない&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;woff ... Web Open Font Format 2&lt;ul&gt;
&lt;li&gt;Web&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt; takatoshi  ~\.\CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-2102&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;25&lt;/span&gt;  ll .\otf\static\&lt;br /&gt;&lt;br /&gt;        Directory: C:\Users\takatoshi\desktop\CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-2102&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;25&lt;/span&gt;\otf\static&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Mode                LastWriteTime         Length Name&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                &lt;span class=&quot;hljs-literal&quot;&gt;-------------&lt;/span&gt;         &lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;161908&lt;/span&gt;   CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-Bold&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;150456&lt;/span&gt;   CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-ExtraLight&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;158652&lt;/span&gt;   CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-Light&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;158244&lt;/span&gt;   CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-Regular&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;161960&lt;/span&gt;   CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-SemiBold&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;159372&lt;/span&gt;   CascadiaCode&lt;span class=&quot;hljs-literal&quot;&gt;-SemiLight&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;185320&lt;/span&gt;   CascadiaCodePL&lt;span class=&quot;hljs-literal&quot;&gt;-Bold&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;175352&lt;/span&gt;   CascadiaCodePL&lt;span class=&quot;hljs-literal&quot;&gt;-ExtraLight&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;181752&lt;/span&gt;   CascadiaCodePL&lt;span class=&quot;hljs-literal&quot;&gt;-Light&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;181376&lt;/span&gt;   CascadiaCodePL&lt;span class=&quot;hljs-literal&quot;&gt;-Regular&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;185540&lt;/span&gt;   CascadiaCodePL&lt;span class=&quot;hljs-literal&quot;&gt;-SemiBold&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;182740&lt;/span&gt;   CascadiaCodePL&lt;span class=&quot;hljs-literal&quot;&gt;-SemiLight&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;145316&lt;/span&gt;   CascadiaMono&lt;span class=&quot;hljs-literal&quot;&gt;-Bold&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;133864&lt;/span&gt;   CascadiaMono&lt;span class=&quot;hljs-literal&quot;&gt;-ExtraLight&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;142060&lt;/span&gt;   CascadiaMono&lt;span class=&quot;hljs-literal&quot;&gt;-Light&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;141652&lt;/span&gt;   CascadiaMono&lt;span class=&quot;hljs-literal&quot;&gt;-Regular&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;145368&lt;/span&gt;   CascadiaMono&lt;span class=&quot;hljs-literal&quot;&gt;-SemiBold&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;142780&lt;/span&gt;   CascadiaMono&lt;span class=&quot;hljs-literal&quot;&gt;-SemiLight&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;168588&lt;/span&gt;   CascadiaMonoPL&lt;span class=&quot;hljs-literal&quot;&gt;-Bold&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;158620&lt;/span&gt;   CascadiaMonoPL&lt;span class=&quot;hljs-literal&quot;&gt;-ExtraLight&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;165020&lt;/span&gt;   CascadiaMonoPL&lt;span class=&quot;hljs-literal&quot;&gt;-Light&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;164644&lt;/span&gt;   CascadiaMonoPL&lt;span class=&quot;hljs-literal&quot;&gt;-Regular&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;168808&lt;/span&gt;   CascadiaMonoPL&lt;span class=&quot;hljs-literal&quot;&gt;-SemiBold&lt;/span&gt;.otf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-02-25&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;         &lt;span class=&quot;hljs-number&quot;&gt;166008&lt;/span&gt;   CascadiaMonoPL&lt;span class=&quot;hljs-literal&quot;&gt;-SemiLight&lt;/span&gt;.otf
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ここで対象になるのは MonoPL(monospace の PowerLine 版)。まだリガチャを受け入れるだけの心のゆとりができていない。&lt;/p&gt;
&lt;p&gt;次に [Migu][&lt;a href=&quot;https://mix-mplus-ipa.osdn.jp/migu/]&quot; title=&quot;undefined&quot;&gt;https://mix-mplus-ipa.osdn.jp/migu/]&lt;/a&gt; を落とす。OSDN のリダイレクトかまされ迂回方法がわからないので手で落とした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt; takatoshi  ~\desktop  &lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; .\migu&lt;span class=&quot;hljs-literal&quot;&gt;-1m-20200307&lt;/span&gt;\&lt;br /&gt; takatoshi  ~\.\migu&lt;span class=&quot;hljs-literal&quot;&gt;-1m-20200307&lt;/span&gt;  ll .\migu&lt;span class=&quot;hljs-literal&quot;&gt;-1m-20200307&lt;/span&gt;\&lt;br /&gt;&lt;br /&gt;        Directory: C:\Users\takatoshi\desktop\migu&lt;span class=&quot;hljs-literal&quot;&gt;-1m-20200307&lt;/span&gt;\migu&lt;span class=&quot;hljs-literal&quot;&gt;-1m-20200307&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Mode                LastWriteTime         Length Name&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                &lt;span class=&quot;hljs-literal&quot;&gt;-------------&lt;/span&gt;         &lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-03-13&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;39&lt;/span&gt;                  ipag00303&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-03-13&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;39&lt;/span&gt;                  mplus&lt;span class=&quot;hljs-literal&quot;&gt;-TESTFLIGHT-063a&lt;/span&gt;&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2020&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-03-07&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;3401580&lt;/span&gt;   migu&lt;span class=&quot;hljs-literal&quot;&gt;-1m-bold&lt;/span&gt;.ttf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2020&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-03-07&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;12&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;3144556&lt;/span&gt;   migu&lt;span class=&quot;hljs-literal&quot;&gt;-1m-regular&lt;/span&gt;.ttf&lt;br /&gt;la&lt;span class=&quot;hljs-literal&quot;&gt;---&lt;/span&gt;        &lt;span class=&quot;hljs-number&quot;&gt;2020&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-03-08&lt;/span&gt;     &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;           &lt;span class=&quot;hljs-number&quot;&gt;2344&lt;/span&gt;   migu&lt;span class=&quot;hljs-literal&quot;&gt;-README&lt;/span&gt;.txt
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;fontmerger のスクリプトがちょっと Windows では使いにくそうに見えたので、一旦 Ubuntu(WSL2)でやる。&lt;/p&gt;
&lt;p&gt;でも Ubuntu16LTS の fontforge は 2019 年までのやつで古かったので、一旦 WSL2 の Ubuntu を更新することにする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt update&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt upgrade&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; do-release-upgrade
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;途中で sshd_config が編集されとんぞ！？と言われて新しいのとローカルのどっち使うか選ばねばいけなかった。ここは新しい方を有効化。この流れで Ubuntu20LTS まで上げた。
Ubuntu20 では fontforge はデフォルトのパッケージではなくなったので、パッケージソースを追加する必要がある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://packages.ubuntu.com/focal/x11/fontforge&quot; title=&quot;Ubuntu – Details of package fontforge in focal&quot;&gt;Ubuntu – Details of package fontforge in focal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;universe にあるのがわかったので追加。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-add-repository universe&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt update&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt install fontforge
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;mkdir&lt;/span&gt; ./patched&lt;br /&gt;./bin/fontmerger --all -o patched --suffix=with-icons -- migu-1m-regular.ttf migu-1m-bold.ttf migu-1c-regular.ttf migu-1c-bold.ttf
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;結果、無反応。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;krymtkts@krymtkts-stealth:/mnt/c/Users/takatoshi/dev/github.com/krymtkts/fontmerger$ /usr/bin/fontforge -script fontmerger/__init__.py&lt;br /&gt; --all -o patched --suffix=with-icons -- migu-1m-regular.ttf migu-1m-bold.ttf migu-1c-regular.ttf migu-1c-bold.ttf&lt;br /&gt;Copyright (c) 2000-2020. See AUTHORS &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; Contributors.&lt;br /&gt; License GPLv3+: GNU GPL version 3 or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;&lt;br /&gt; with many parts BSD &amp;lt;http://fontforge.org/license.html&amp;gt;. Please &lt;span class=&quot;hljs-built_in&quot;&gt;read&lt;/span&gt; LICENSE.&lt;br /&gt; Version: 20190801&lt;br /&gt; Based on sources from 03:10 UTC  6-Mar-2020-ML-D-GDK3.&lt;br /&gt;  File &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;fontmerger/__init__.py&amp;quot;&lt;/span&gt;, line 103&lt;br /&gt;    except Exception, e:&lt;br /&gt;                    ^&lt;br /&gt;SyntaxError: invalid syntax&lt;br /&gt;Error &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; sys.excepthook:&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/usr/lib/python3.8/subprocess.py&amp;quot;&lt;/span&gt;, line 64, &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &amp;lt;module&amp;gt;&lt;br /&gt;    import msvcrt&lt;br /&gt;ModuleNotFoundError: No module named &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;msvcrt&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;During handling of the above exception, another exception occurred:&lt;br /&gt;&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/usr/lib/python3/dist-packages/apport_python_hook.py&amp;quot;&lt;/span&gt;, line 72, &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; apport_excepthook&lt;br /&gt;    from apport.fileutils import likely_packaged, get_recent_crashes&lt;br /&gt;  File &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/usr/lib/python3/dist-packages/apport/__init__.py&amp;quot;&lt;/span&gt;, line 5, &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &amp;lt;module&amp;gt;&lt;br /&gt;    from apport.report import Report&lt;br /&gt;  File &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/usr/lib/python3/dist-packages/apport/report.py&amp;quot;&lt;/span&gt;, line 12, &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &amp;lt;module&amp;gt;&lt;br /&gt;    import subprocess, tempfile, os.path, re, &lt;span class=&quot;hljs-built_in&quot;&gt;pwd&lt;/span&gt;, grp, os, &lt;span class=&quot;hljs-keyword&quot;&gt;time&lt;/span&gt;, io&lt;br /&gt;  File &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/usr/lib/python3.8/subprocess.py&amp;quot;&lt;/span&gt;, line 69, &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &amp;lt;module&amp;gt;&lt;br /&gt;    import _posixsubprocess&lt;br /&gt;ModuleNotFoundError: No module named &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;_posixsubprocess&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Original exception was:&lt;br /&gt;  File &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;fontmerger/__init__.py&amp;quot;&lt;/span&gt;, line 103&lt;br /&gt;    except Exception, e:&lt;br /&gt;                    ^&lt;br /&gt;SyntaxError: invalid syntax
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あー、Python2 の構文によるエラーね。解消して再実行してみる。引数も間違ってたし。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;krymtkts@krymtkts-stealth:/mnt/c/Users/takatoshi/dev/github.com/krymtkts/fontmerger$ /usr/bin/fontforge -script fontmerger/__init__.py --all -o patched --suffix=with-icons -- ./source/migu-1m-regular.ttf ./source/migu-1m-bold.ttf ./source/migu-1c-regular.ttf ./source/migu-1c-bold.ttf&lt;br /&gt;Copyright (c) 2000-2020. See AUTHORS &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; Contributors.&lt;br /&gt; License GPLv3+: GNU GPL version 3 or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;&lt;br /&gt; with many parts BSD &amp;lt;http://fontforge.org/license.html&amp;gt;. Please &lt;span class=&quot;hljs-built_in&quot;&gt;read&lt;/span&gt; LICENSE.&lt;br /&gt; Version: 20190801&lt;br /&gt; Based on sources from 03:10 UTC  6-Mar-2020-ML-D-GDK3.&lt;br /&gt;The following table(s) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; the font have been ignored by FontForge&lt;br /&gt;  Ignoring &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;EPAR&amp;#x27;&lt;/span&gt;&lt;br /&gt;The glyph named asterisk is mapped to U+F069.&lt;br /&gt;  But its name indicates it should be mapped to U+002A.&lt;br /&gt;The glyph named plus is mapped to U+F067.&lt;br /&gt;  But its name indicates it should be mapped to U+002B.&lt;br /&gt;The glyph named question is mapped to U+F128.&lt;br /&gt;  But its name indicates it should be mapped to U+003F.&lt;br /&gt;The glyph named minus is mapped to U+F068.&lt;br /&gt;  But its name indicates it should be mapped to U+2212.&lt;br /&gt;The glyph named heart is mapped to U+F004.&lt;br /&gt;  But its name indicates it should be mapped to U+2665.&lt;br /&gt;The glyph named home is mapped to U+F015.&lt;br /&gt;  But its name indicates it should be mapped to U+21B8.&lt;br /&gt;The glyph named check is mapped to U+F046.&lt;br /&gt;  But its name indicates it should be mapped to U+2713.&lt;br /&gt;The glyph named bell is mapped to U+F0A2.&lt;br /&gt;  But its name indicates it should be mapped to U+2407.&lt;br /&gt;The glyph named lessequal is mapped to U+F500.&lt;br /&gt;  But its name indicates it should be mapped to U+2264.&lt;br /&gt;The glyph named circle is mapped to U+F111.&lt;br /&gt;  But its name indicates it should be mapped to U+25CB.&lt;br /&gt;The glyph named smile is mapped to U+F118.&lt;br /&gt;  But its name indicates it should be mapped to U+263A.&lt;br /&gt;The glyph named frown is mapped to U+F119.&lt;br /&gt;  But its name indicates it should be mapped to U+2322.&lt;br /&gt;The glyph named bullseye is mapped to U+F140.&lt;br /&gt;  But its name indicates it should be mapped to U+25CE.&lt;br /&gt;The glyph named compass is mapped to U+F14E.&lt;br /&gt;  But its name indicates it should be mapped to U+263C.&lt;br /&gt;The glyph named female is mapped to U+F182.&lt;br /&gt;  But its name indicates it should be mapped to U+2640.&lt;br /&gt;The glyph named male is mapped to U+F183.&lt;br /&gt;  But its name indicates it should be mapped to U+2642.&lt;br /&gt;The glyph named sun is mapped to U+F185.&lt;br /&gt;  But its name indicates it should be mapped to U+263C.&lt;br /&gt;The glyph named venus is mapped to U+F221.&lt;br /&gt;  But its name indicates it should be mapped to U+2640.&lt;br /&gt;The glyph named slash is mapped to U+E016.&lt;br /&gt;  But its name indicates it should be mapped to U+002F.&lt;br /&gt;The glyph named pi is mapped to U+E02C.&lt;br /&gt;  But its name indicates it should be mapped to U+03C0.&lt;br /&gt;The glyph named ring is mapped to U+E03D.&lt;br /&gt;  But its name indicates it should be mapped to U+02DA.&lt;br /&gt;The glyph named infinity is mapped to U+E055.&lt;br /&gt;  But its name indicates it should be mapped to U+221E.&lt;br /&gt;The glyph named equal is mapped to U+E079.&lt;br /&gt;  But its name indicates it should be mapped to U+003D.&lt;br /&gt;The glyph named question is mapped to U+F02C.&lt;br /&gt;  But its name indicates it should be mapped to U+003F.&lt;br /&gt;The glyph named check is mapped to U+F03A.&lt;br /&gt;  But its name indicates it should be mapped to U+2713.&lt;br /&gt;The glyph named plus is mapped to U+F05D.&lt;br /&gt;  But its name indicates it should be mapped to U+002B.&lt;br /&gt;The glyph named x is mapped to U+F081.&lt;br /&gt;  But its name indicates it should be mapped to U+0078.&lt;br /&gt;The glyph named home is mapped to U+F08D.&lt;br /&gt;  But its name indicates it should be mapped to U+21B8.&lt;br /&gt;The glyph named ellipsis is mapped to U+F09A.&lt;br /&gt;  But its name indicates it should be mapped to U+2026.&lt;br /&gt;The glyph named bell is mapped to U+F0DE.&lt;br /&gt;  But its name indicates it should be mapped to U+2407.&lt;br /&gt;The following table(s) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; the font have been ignored by FontForge&lt;br /&gt;  Ignoring &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;EPAR&amp;#x27;&lt;/span&gt;&lt;br /&gt;The glyph named asterisk is mapped to U+F069.&lt;br /&gt;  But its name indicates it should be mapped to U+002A.&lt;br /&gt;The glyph named plus is mapped to U+F067.&lt;br /&gt;  But its name indicates it should be mapped to U+002B.&lt;br /&gt;The glyph named question is mapped to U+F128.&lt;br /&gt;  But its name indicates it should be mapped to U+003F.&lt;br /&gt;The glyph named minus is mapped to U+F068.&lt;br /&gt;  But its name indicates it should be mapped to U+2212.&lt;br /&gt;The glyph named heart is mapped to U+F004.&lt;br /&gt;  But its name indicates it should be mapped to U+2665.&lt;br /&gt;The glyph named home is mapped to U+F015.&lt;br /&gt;  But its name indicates it should be mapped to U+21B8.&lt;br /&gt;The glyph named check is mapped to U+F046.&lt;br /&gt;  But its name indicates it should be mapped to U+2713.&lt;br /&gt;The glyph named bell is mapped to U+F0A2.&lt;br /&gt;  But its name indicates it should be mapped to U+2407.&lt;br /&gt;The glyph named lessequal is mapped to U+F500.&lt;br /&gt;  But its name indicates it should be mapped to U+2264.&lt;br /&gt;The glyph named circle is mapped to U+F111.&lt;br /&gt;  But its name indicates it should be mapped to U+25CB.&lt;br /&gt;The glyph named smile is mapped to U+F118.&lt;br /&gt;  But its name indicates it should be mapped to U+263A.&lt;br /&gt;The glyph named frown is mapped to U+F119.&lt;br /&gt;  But its name indicates it should be mapped to U+2322.&lt;br /&gt;The glyph named bullseye is mapped to U+F140.&lt;br /&gt;  But its name indicates it should be mapped to U+25CE.&lt;br /&gt;The glyph named compass is mapped to U+F14E.&lt;br /&gt;  But its name indicates it should be mapped to U+263C.&lt;br /&gt;The glyph named female is mapped to U+F182.&lt;br /&gt;  But its name indicates it should be mapped to U+2640.&lt;br /&gt;The glyph named male is mapped to U+F183.&lt;br /&gt;  But its name indicates it should be mapped to U+2642.&lt;br /&gt;The glyph named sun is mapped to U+F185.&lt;br /&gt;  But its name indicates it should be mapped to U+263C.&lt;br /&gt;The glyph named venus is mapped to U+F221.&lt;br /&gt;  But its name indicates it should be mapped to U+2640.&lt;br /&gt;The glyph named slash is mapped to U+E016.&lt;br /&gt;  But its name indicates it should be mapped to U+002F.&lt;br /&gt;The glyph named pi is mapped to U+E02C.&lt;br /&gt;  But its name indicates it should be mapped to U+03C0.&lt;br /&gt;The glyph named ring is mapped to U+E03D.&lt;br /&gt;  But its name indicates it should be mapped to U+02DA.&lt;br /&gt;The glyph named infinity is mapped to U+E055.&lt;br /&gt;  But its name indicates it should be mapped to U+221E.&lt;br /&gt;The glyph named equal is mapped to U+E079.&lt;br /&gt;  But its name indicates it should be mapped to U+003D.&lt;br /&gt;The glyph named question is mapped to U+F02C.&lt;br /&gt;  But its name indicates it should be mapped to U+003F.&lt;br /&gt;The glyph named check is mapped to U+F03A.&lt;br /&gt;  But its name indicates it should be mapped to U+2713.&lt;br /&gt;The glyph named plus is mapped to U+F05D.&lt;br /&gt;  But its name indicates it should be mapped to U+002B.&lt;br /&gt;The glyph named x is mapped to U+F081.&lt;br /&gt;  But its name indicates it should be mapped to U+0078.&lt;br /&gt;The glyph named home is mapped to U+F08D.&lt;br /&gt;  But its name indicates it should be mapped to U+21B8.&lt;br /&gt;The glyph named ellipsis is mapped to U+F09A.&lt;br /&gt;  But its name indicates it should be mapped to U+2026.&lt;br /&gt;The glyph named bell is mapped to U+F0DE.&lt;br /&gt;  But its name indicates it should be mapped to U+2407.&lt;br /&gt;The following table(s) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; the font have been ignored by FontForge&lt;br /&gt;  Ignoring &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;EPAR&amp;#x27;&lt;/span&gt;&lt;br /&gt;The glyph named asterisk is mapped to U+F069.&lt;br /&gt;  But its name indicates it should be mapped to U+002A.&lt;br /&gt;The glyph named plus is mapped to U+F067.&lt;br /&gt;  But its name indicates it should be mapped to U+002B.&lt;br /&gt;The glyph named question is mapped to U+F128.&lt;br /&gt;  But its name indicates it should be mapped to U+003F.&lt;br /&gt;The glyph named minus is mapped to U+F068.&lt;br /&gt;  But its name indicates it should be mapped to U+2212.&lt;br /&gt;The glyph named heart is mapped to U+F004.&lt;br /&gt;  But its name indicates it should be mapped to U+2665.&lt;br /&gt;The glyph named home is mapped to U+F015.&lt;br /&gt;  But its name indicates it should be mapped to U+21B8.&lt;br /&gt;The glyph named check is mapped to U+F046.&lt;br /&gt;  But its name indicates it should be mapped to U+2713.&lt;br /&gt;The glyph named bell is mapped to U+F0A2.&lt;br /&gt;  But its name indicates it should be mapped to U+2407.&lt;br /&gt;The glyph named lessequal is mapped to U+F500.&lt;br /&gt;  But its name indicates it should be mapped to U+2264.&lt;br /&gt;The glyph named circle is mapped to U+F111.&lt;br /&gt;  But its name indicates it should be mapped to U+25CB.&lt;br /&gt;The glyph named smile is mapped to U+F118.&lt;br /&gt;  But its name indicates it should be mapped to U+263A.&lt;br /&gt;The glyph named frown is mapped to U+F119.&lt;br /&gt;  But its name indicates it should be mapped to U+2322.&lt;br /&gt;The glyph named bullseye is mapped to U+F140.&lt;br /&gt;  But its name indicates it should be mapped to U+25CE.&lt;br /&gt;The glyph named compass is mapped to U+F14E.&lt;br /&gt;  But its name indicates it should be mapped to U+263C.&lt;br /&gt;The glyph named female is mapped to U+F182.&lt;br /&gt;  But its name indicates it should be mapped to U+2640.&lt;br /&gt;The glyph named male is mapped to U+F183.&lt;br /&gt;  But its name indicates it should be mapped to U+2642.&lt;br /&gt;The glyph named sun is mapped to U+F185.&lt;br /&gt;  But its name indicates it should be mapped to U+263C.&lt;br /&gt;The glyph named venus is mapped to U+F221.&lt;br /&gt;  But its name indicates it should be mapped to U+2640.&lt;br /&gt;The glyph named slash is mapped to U+E016.&lt;br /&gt;  But its name indicates it should be mapped to U+002F.&lt;br /&gt;The glyph named pi is mapped to U+E02C.&lt;br /&gt;  But its name indicates it should be mapped to U+03C0.&lt;br /&gt;The glyph named ring is mapped to U+E03D.&lt;br /&gt;  But its name indicates it should be mapped to U+02DA.&lt;br /&gt;The glyph named infinity is mapped to U+E055.&lt;br /&gt;  But its name indicates it should be mapped to U+221E.&lt;br /&gt;The glyph named equal is mapped to U+E079.&lt;br /&gt;  But its name indicates it should be mapped to U+003D.&lt;br /&gt;The glyph named question is mapped to U+F02C.&lt;br /&gt;  But its name indicates it should be mapped to U+003F.&lt;br /&gt;The glyph named check is mapped to U+F03A.&lt;br /&gt;  But its name indicates it should be mapped to U+2713.&lt;br /&gt;The glyph named plus is mapped to U+F05D.&lt;br /&gt;  But its name indicates it should be mapped to U+002B.&lt;br /&gt;The glyph named x is mapped to U+F081.&lt;br /&gt;  But its name indicates it should be mapped to U+0078.&lt;br /&gt;The glyph named home is mapped to U+F08D.&lt;br /&gt;  But its name indicates it should be mapped to U+21B8.&lt;br /&gt;The glyph named ellipsis is mapped to U+F09A.&lt;br /&gt;  But its name indicates it should be mapped to U+2026.&lt;br /&gt;The glyph named bell is mapped to U+F0DE.&lt;br /&gt;  But its name indicates it should be mapped to U+2407.&lt;br /&gt;The following table(s) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; the font have been ignored by FontForge&lt;br /&gt;  Ignoring &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;EPAR&amp;#x27;&lt;/span&gt;&lt;br /&gt;The glyph named asterisk is mapped to U+F069.&lt;br /&gt;  But its name indicates it should be mapped to U+002A.&lt;br /&gt;The glyph named plus is mapped to U+F067.&lt;br /&gt;  But its name indicates it should be mapped to U+002B.&lt;br /&gt;The glyph named question is mapped to U+F128.&lt;br /&gt;  But its name indicates it should be mapped to U+003F.&lt;br /&gt;The glyph named minus is mapped to U+F068.&lt;br /&gt;  But its name indicates it should be mapped to U+2212.&lt;br /&gt;The glyph named heart is mapped to U+F004.&lt;br /&gt;  But its name indicates it should be mapped to U+2665.&lt;br /&gt;The glyph named home is mapped to U+F015.&lt;br /&gt;  But its name indicates it should be mapped to U+21B8.&lt;br /&gt;The glyph named check is mapped to U+F046.&lt;br /&gt;  But its name indicates it should be mapped to U+2713.&lt;br /&gt;The glyph named bell is mapped to U+F0A2.&lt;br /&gt;  But its name indicates it should be mapped to U+2407.&lt;br /&gt;The glyph named lessequal is mapped to U+F500.&lt;br /&gt;  But its name indicates it should be mapped to U+2264.&lt;br /&gt;The glyph named circle is mapped to U+F111.&lt;br /&gt;  But its name indicates it should be mapped to U+25CB.&lt;br /&gt;The glyph named smile is mapped to U+F118.&lt;br /&gt;  But its name indicates it should be mapped to U+263A.&lt;br /&gt;The glyph named frown is mapped to U+F119.&lt;br /&gt;  But its name indicates it should be mapped to U+2322.&lt;br /&gt;The glyph named bullseye is mapped to U+F140.&lt;br /&gt;  But its name indicates it should be mapped to U+25CE.&lt;br /&gt;The glyph named compass is mapped to U+F14E.&lt;br /&gt;  But its name indicates it should be mapped to U+263C.&lt;br /&gt;The glyph named female is mapped to U+F182.&lt;br /&gt;  But its name indicates it should be mapped to U+2640.&lt;br /&gt;The glyph named male is mapped to U+F183.&lt;br /&gt;  But its name indicates it should be mapped to U+2642.&lt;br /&gt;The glyph named sun is mapped to U+F185.&lt;br /&gt;  But its name indicates it should be mapped to U+263C.&lt;br /&gt;The glyph named venus is mapped to U+F221.&lt;br /&gt;  But its name indicates it should be mapped to U+2640.&lt;br /&gt;The glyph named slash is mapped to U+E016.&lt;br /&gt;  But its name indicates it should be mapped to U+002F.&lt;br /&gt;The glyph named pi is mapped to U+E02C.&lt;br /&gt;  But its name indicates it should be mapped to U+03C0.&lt;br /&gt;The glyph named ring is mapped to U+E03D.&lt;br /&gt;  But its name indicates it should be mapped to U+02DA.&lt;br /&gt;The glyph named infinity is mapped to U+E055.&lt;br /&gt;  But its name indicates it should be mapped to U+221E.&lt;br /&gt;The glyph named equal is mapped to U+E079.&lt;br /&gt;  But its name indicates it should be mapped to U+003D.&lt;br /&gt;The glyph named question is mapped to U+F02C.&lt;br /&gt;  But its name indicates it should be mapped to U+003F.&lt;br /&gt;The glyph named check is mapped to U+F03A.&lt;br /&gt;  But its name indicates it should be mapped to U+2713.&lt;br /&gt;The glyph named plus is mapped to U+F05D.&lt;br /&gt;  But its name indicates it should be mapped to U+002B.&lt;br /&gt;The glyph named x is mapped to U+F081.&lt;br /&gt;  But its name indicates it should be mapped to U+0078.&lt;br /&gt;The glyph named home is mapped to U+F08D.&lt;br /&gt;  But its name indicates it should be mapped to U+21B8.&lt;br /&gt;The glyph named ellipsis is mapped to U+F09A.&lt;br /&gt;  But its name indicates it should be mapped to U+2026.&lt;br /&gt;The glyph named bell is mapped to U+F0DE.&lt;br /&gt;  But its name indicates it should be mapped to U+2407.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;警告出るがフォントの生成完了。開いてみるも、いやフォントが壊れてるわ...なんでや？&lt;/p&gt;
&lt;p&gt;理由がわかった。fontmerger の実行後に出力先フォルダからフォントを移動するとプレビューできる。出力先フォルダに fontforge の謎のハンドルが残っている様子。&lt;/p&gt;
&lt;p&gt;fontmerger の Python3 化が完了した。&lt;a href=&quot;https://github.com/krymtkts/fontmerger&quot; title=&quot;GitHub - krymtkts/fontmerger: FontForge script for to merge any fonts&quot;&gt;GitHub - krymtkts/fontmerger: FontForge script for to merge any fonts&lt;/a&gt;&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2021-04-10&quot; href=&quot;#2021-04-10&quot;&gt;2021-04-10&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Cascadia からコピる範囲を決める。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt; takatoshi  ~\.\.\.\fontmerger   master ≣ +&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; ~&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-6&lt;/span&gt; !  [&lt;span class=&quot;hljs-type&quot;&gt;Convert&lt;/span&gt;]::ToInt32(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0xE0A0&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;57504&lt;/span&gt;&lt;br /&gt; takatoshi  ~\.\.\.\fontmerger   master ≣ +&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; ~&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-6&lt;/span&gt; !  [&lt;span class=&quot;hljs-type&quot;&gt;Convert&lt;/span&gt;]::ToInt32(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0xE0D4&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;57556&lt;/span&gt;                                                                                                             &lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-04-10&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;17&lt;/span&gt;&lt;br /&gt; takatoshi  ~\.\.\.\fontmerger   master ≣ +&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; ~&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-6&lt;/span&gt; !  ((&lt;span class=&quot;hljs-number&quot;&gt;57504&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;57556&lt;/span&gt;) | %{U &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;}) &lt;span class=&quot;hljs-operator&quot;&gt;-join&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cascadia には Powerline の拡張グリフくらいしか入っていないので Powerline の部分を抜き出して Migu にコピーする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;/usr/bin/fontforge -script fontmerger/__init__.py --all -o patched --suffix=cascadia -- ./source/migu-1m-regular.ttf ./source/migu-1m-bold.ttf ./source/migu-1c-regular.ttf ./source/migu-1c-bold.ttf
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;結果は Cascadia からコピーした領域は以前 Ambiguous なままだった...なんでだろう。以下が追加の Cascadia からコピる設定。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;cascadia-powerline&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Cascadia Powerline Symbols&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Powerline symbols copied from Cascadia Code. https://github.com/microsoft/cascadia-code&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;filename&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;./fonts/cascadia/CascadiaCodePL-Regular.otf&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;unicode_range&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;E0A0&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;E0D4&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コピっても解消しないのか...と思ってた矢先、フォカのフォントを参考に調べていて &lt;a href=&quot;https://github.com/yuru7/HackGen&quot; title=&quot;GitHub - yuru7/HackGen: HackGen is Japanese programming font which is a composed of Hack and GenJyuu-Gothic.&quot;&gt;GitHub - yuru7/HackGen: HackGen is Japanese programming font which is a composed of Hack and GenJyuu-Gothic.&lt;/a&gt; なるフォントを見つけた。&lt;/p&gt;
&lt;p&gt;あれ、このフォント Powerline グリフが Windows Terminal でも崩れないし、見た目も結構好みでこれちょっとよいかも...と浮気しそうになるも、やはり字幅の広さが気に入らず Migu に返り咲くワイ。&lt;/p&gt;
&lt;p&gt;それはそうと Powerline グリフが崩れないのはなんでか？と思ってみてたところ、これ Symbol フォントが Narrow スペースなのね。Cascadia もそう。つまり問題なのはフォント幅じゃね？と気づく。
更に々々、Nerd Fonts から提供されている Hack を使うと、PowerShell モジュールの Terminal-Icons で表示されるファイルアイコンすらも小さくならずに表示できるではないかい！これやろ答え。&lt;/p&gt;
&lt;p&gt;数年前に試してうまくいったことがないのが心配のタネだが、ここは原点回帰して Nerd Fonts の font-patcher で Migu に Narrow スペースでパッチしてみるか～という気持ちになった。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;現状&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ただ単に Migu の最新版にパッチしただけの状態になっているのだが、途中経過をまとめておかないと着手する時加齢に忘れてて辛いので一旦状況をまとめた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;お亡くなりになられた fontmerger を Python3 化して動かす&lt;/label&gt;&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;最新の Migu に対して fontmerger で Nerd font patch する&lt;/label&gt;&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled checked aria-label=&quot;Checkbox&quot; /&gt;&lt;/label&gt;&lt;code&gt;0xE0B0&lt;/code&gt; を始めとした Cascadia でだけうまく表示されるグリフを Migu に移植する&lt;ul&gt;
&lt;li&gt;そして効果なし！&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled  aria-label=&quot;Checkbox&quot; /&gt;Nerd Fonts の font-patcher で Migu にパッチしてみる &amp;lt;- &lt;/label&gt;&lt;strong&gt;NEW!!!&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;label class=&quot;checkbox&quot;&gt;&lt;input type=&quot;checkbox&quot; name=&quot;checkbox&quot; class=&quot;checkbox&quot; disabled  aria-label=&quot;Checkbox&quot; /&gt;完璧な Migu の完成！&lt;/label&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;俺たちの戦いはこれからだ！😭😭😭&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 11 Apr 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-03-06-fix-publish-failure-to-powershell-gallery.html</guid><link>https://krymtkts.github.io/posts/2021-03-06-fix-publish-failure-to-powershell-gallery.html</link><title>PSGallery への公開つまづき 2021</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今年のはじめに&lt;a href=&quot;https://github.com/krymtkts/Get-GzipContent&quot; title=&quot;krymtkts/Get-GzipContent: Get-Content for gzip files.&quot;&gt;krymtkts/Get-GzipContent: Get-Content for gzip files.&lt;/a&gt;の更新を行った際に、PoweShell Gallery への公開で手間取った。その 2 ヶ月遅れの記録である。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PowerShellGetv2/issues/303#issuecomment-433139506&quot; title=&quot;Publish-Module throws error &amp;quot;Failed to generate the compressed file for module &amp;#39;Microsoft (R) Build Engine version 15.7.179.6572 for .NET Core&amp;#39;&amp;quot; · Issue #303 · PowerShell/PowerShellGetv2&quot;&gt;Publish-Module throws error &amp;quot;Failed to generate the compressed file for module &amp;#39;Microsoft (R) Build Engine version 15.7.179.6572 for .NET Core&amp;#39;&amp;quot; · Issue #303 · PowerShell/PowerShellGetv2&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; https://dist.nuget.org/win&lt;span class=&quot;hljs-literal&quot;&gt;-x86-commandline&lt;/span&gt;/latest/nuget.exe &lt;span class=&quot;hljs-literal&quot;&gt;-OutFile&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$env:LOCALAPPDATA&lt;/span&gt;\Microsoft\Windows\PowerShell\PowerShellGet\NuGet.exe&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;いやまあこれで直ったんやけど、わからなさすぎてこの記事も見た。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://sqldbawithabeard.com/2019/11/26/fixing-the-failed-to-generate-the-compressed-file-for-module-cprogram-filesdotnetdotnet-exe-error-when-deploying-to-the-powershell-gallery-using-azure-devops/&quot; title=&quot;Fixing the ‘Failed to generate the compressed file for module ‘C:\Program Files\dotnet\dotnet.exe’ error when deploying to the PowerShell Gallery using Azure DevOps | SQL DBA with A Beard&quot;&gt;Fixing the ‘Failed to generate the compressed file for module ‘C:\Program Files\dotnet\dotnet.exe’ error when deploying to the PowerShell Gallery using Azure DevOps | SQL DBA with A Beard&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これは一時しのぎなので最終的に目指すのは配置している&lt;code&gt;nuget.exe&lt;/code&gt;を消し去っても動くようになることだ。とはいえまた次公開するときまで使うときがないので試すのめんどくせええ＆次試そうと思っても忘れる...ということで一旦 Chocolatey で NuGet を入れておいて保険とした。でもこれ自体も本来バイナリ不要で動いてたことからしたら蛇足のはずやねんけどな、Issue に進捗なく Close されてるからわからん。まあ日記にも書いたからエラーしたときにきっと振り返れる、未来のワイ。&lt;/p&gt;
&lt;p&gt;あと年に数回しか PowerShell Gallery に公開しないとやり方とか色々忘れるのだけど、一番忘れるのが API キーの寿命が短く設定してあって切れてるということ。今回期限切れの API キーを再有効化できるってのを知ったので、それはそれで良。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/ja-jp/powershell/scripting/gallery/how-to/managing-profile/creating-apikeys?view=powershell-7.1#editing-and-deleting-existing-api-keys&quot; title=&quot;API キーの管理 - PowerShell | Microsoft Docs&quot;&gt;API キーの管理 - PowerShell | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 06 Mar 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-02-12-various-stories-about-starting-to-use-nodist.html</guid><link>https://krymtkts.github.io/posts/2021-02-12-various-stories-about-starting-to-use-nodist.html</link><title>色々あって Nodist を使い始めた話</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;重い腰を上げて、&lt;a href=&quot;https://github.com/krymtkts/mccall-bot&quot; title=&quot;Slackbot のマッコールさん&quot;&gt;Slackbot のマッコールさん&lt;/a&gt;の Typo を直す気になった。
タイポの修正と追加のセンテンスを登録して、いざ deploy しようとしたら、Serverless Framework がエラーを吐くようになっていた。↓ らしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/serverless/serverless/issues/8794&quot; title=&quot;Unable to deploy to Serverless due to &amp;#39;empty zip&amp;#39; · Issue #8794 · serverless/serverless&quot;&gt;Unable to deploy to Serverless due to &amp;#39;empty zip&amp;#39; · Issue #8794 · serverless/serverless&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;aws-cdk の方も同様のバグがあるらしいけど、あっちは直してくれてるみたい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-cdk/issues/12536&quot; title=&quot;lambda: corrupt zip archive asset produced when using node v15.6 · Issue #12536 · aws/aws-cdk&quot;&gt;lambda: corrupt zip archive asset produced when using node v15.6 · Issue #12536 · aws/aws-cdk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;残念ながら Serverless Framework の方は直してないっぽなので、Node.js のバージョンを 15 から 14 に落とす必要が出てきた。この時リアルタイムで友人に &lt;a href=&quot;https://github.com/nullivex/nodist&quot; title=&quot;nodist&quot;&gt;nodist&lt;/a&gt; を教えてもらったので、これを使って複数の系を利用できるようにした。&lt;/p&gt;
&lt;p&gt;&lt;del&gt;(というか Chocolatey で Node.js の v15 を uninstall して v14 入れようとしてもなんかエラーになって、ログ見たら「新しい版いるから失敗するね！」てあって「はぁ!?」と調べたら&lt;code&gt;choco uninstall nodejs&lt;/code&gt;は仕事してくれへんらしい。古き良き Chocolatey 流儀はやめろ。で日頃使ってた node modules も全部吹っ飛んで災難やで...)&lt;/del&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;choco install nodist &lt;span class=&quot;hljs-literal&quot;&gt;-y&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# RapidEE で PATH に `C:\Program Files (x86)\Nodist\bin` を追加した&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# nodist と一緒に install される系は古い&lt;/span&gt;&lt;br /&gt;nodist list&lt;br /&gt;  (x64)&lt;br /&gt;&amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;11.13&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 15 系と 14 系の最新を入れる&lt;/span&gt;&lt;br /&gt;nodist add &lt;span class=&quot;hljs-number&quot;&gt;15.8&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;nodist add &lt;span class=&quot;hljs-number&quot;&gt;14.15&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 14 系を選択&lt;/span&gt;&lt;br /&gt;nodist &lt;span class=&quot;hljs-number&quot;&gt;14.15&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# npm も古い&lt;/span&gt;&lt;br /&gt;nodist npm list&lt;br /&gt;&amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;6.9&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 選択中の node と合わせる&lt;/span&gt;&lt;br /&gt;nodist npm match
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://nodejs.org/ja/download/releases/&quot; title=&quot;Node.js のリリース一覧&quot;&gt;Node.js のリリース一覧&lt;/a&gt;から node と npm の対応を見て選んでってやってもいいけど、そんなんめんどすぎるので &lt;code&gt;nodist npm match&lt;/code&gt; の一度ではないかと考える。
もし、厳密に指定のバージョン使いたいとかあったら加初環境をコンテナに構築したりすればいいし、そもそも nodist を使ってローカル PC のグローバル node をこねくったりしてないはず。&lt;/p&gt;
&lt;p&gt;ちょっとおもしろいのが、node/npm の version を変えても install した node_modules は同じものを使えるところ。 v14.15.5 で入れたモジュールが v15.8.0 でも見れた。何度も同じモジュールをインストールしなくていいのは楽やけど、バージョン互換性の厳しいモジュールは使うのが難しいのでは。&lt;/p&gt;
&lt;p&gt;node、npm、モジュールの実態はそれぞれ、&lt;code&gt;$env:NODIST_PREFIX/v-x64&lt;/code&gt;(32bit が&lt;code&gt;$env:NODIST_PREFIX/v&lt;/code&gt;?) &lt;code&gt;$env:NODIST_PREFIX/npmv&lt;/code&gt; &lt;code&gt;$env:NODIST_PREFIX/bin/node_modules&lt;/code&gt; 配下にインストールされる様子。&lt;/p&gt;
&lt;p&gt;nodist、どうも 2019 年を最後にメンテが止まっている様子(単にマジで変更がないのかも知れん)。現時点でこいつが最後 &lt;a href=&quot;https://github.com/nullivex/nodist/commit/bb099ba3723027469bf46e3159f51171b5dd4b59&quot; title=&quot;Fix deprecated use of Tar.Extract in npm.js, release 0.9.1 · nullivex/nodist@bb099ba&quot;&gt;Fix deprecated use of Tar.Extract in npm.js, release 0.9.1 · nullivex/nodist@bb099ba&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;とはいえ便利なので不都合ない限り利用してみるつもり。&lt;/p&gt;
&lt;p&gt;と色々やったことでようやくマッコールさん Bot の最新版を deploy できるようになったとさ。めでたし x2。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Fri, 12 Feb 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-02-01-go-map-key-tips.html</guid><link>https://krymtkts.github.io/posts/2021-02-01-go-map-key-tips.html</link><title>go の map のキーの Tips</title><description>&lt;div class=&quot;section&quot;&gt;&lt;ul&gt;
&lt;li&gt;知ってた&lt;ul&gt;
&lt;li&gt;&lt;code&gt;map&lt;/code&gt;のキーには&lt;code&gt;struct&lt;/code&gt;が使える&lt;/li&gt;&lt;li&gt;キーがポインタやポインタを含む&lt;code&gt;struct&lt;/code&gt;の場合、ポインタの指す値が同じでもポインタ値自体が比較されるため異なるキーとなる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;知らなかった&lt;ul&gt;
&lt;li&gt;&lt;code&gt;interface&lt;/code&gt;もキーにできる&lt;ul&gt;
&lt;li&gt;キーを追加するときにポインタを使ってないこと&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;time.Time&lt;/code&gt;はキーにつこたらあかん&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://go.googlesource.com/go/+/go1.15.6/src/time/time.go#147&quot; title=&quot;src/time/time.go - go - Git at Google&quot;&gt;src/time/time.go - go - Git at Google&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://pkg.go.dev/time#Time&quot; title=&quot;time · pkg.go.dev&quot;&gt;time · pkg.go.dev&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;blockquote&gt;
&lt;p&gt;Note that the Go == operator compares not just the time instant but also the Location and the monotonic clock reading. Therefore, Time values should not be used as map or database keys without first guaranteeing that the identical Location has been set for all values, which can be achieved through use of the UTC or Local method, and that the monotonic clock reading has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u) to t == u, since t.Equal uses the most accurate comparison available and correctly handles the case when only one of its arguments has a monotonic clock reading.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;UT では一致しちゃいバグを見つけられなかった...😥&lt;/li&gt;&lt;li&gt;まだわかってないのが、&lt;code&gt;Location&lt;/code&gt;が必ず同じになるようにしてた＆年月日だけの情報しか持ってなかったのにずれとんのかい！？というところ&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://play.golang.org/p/Rd5OJ2S37AT&quot; title=&quot;コード&quot;&gt;コード&lt;/a&gt;。このコードでは&lt;code&gt;time.Time&lt;/code&gt;のキーのズレは再現しないけど。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; main&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; (&lt;br /&gt;&amp;emsp;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;emsp;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;time&amp;quot;&lt;/span&gt;&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Key &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; KeyA &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {&lt;br /&gt;&amp;emsp;s &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; KeyB &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {&lt;br /&gt;&amp;emsp;s &lt;span class=&quot;hljs-type&quot;&gt;string&lt;/span&gt;&lt;br /&gt;&amp;emsp;i &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; KeyC &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {&lt;br /&gt;&amp;emsp;t time.Time&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; KeyD &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {&lt;br /&gt;&amp;emsp;a *KeyA&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;checkInterfaceKey&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&amp;emsp;m := &lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[Key]&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;{}&lt;br /&gt;&amp;emsp;m[KeyA{&lt;br /&gt;&amp;emsp;&amp;emsp;s: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;,&lt;br /&gt;&amp;emsp;}] = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&amp;emsp;m[KeyA{&lt;br /&gt;&amp;emsp;&amp;emsp;s: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;,&lt;br /&gt;&amp;emsp;}] = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&amp;emsp;m[KeyA{&lt;br /&gt;&amp;emsp;&amp;emsp;s: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;A2&amp;quot;&lt;/span&gt;,&lt;br /&gt;&amp;emsp;}] = &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;br /&gt;&amp;emsp;m[KeyB{&lt;br /&gt;&amp;emsp;&amp;emsp;s: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;B1&amp;quot;&lt;/span&gt;,&lt;br /&gt;&amp;emsp;&amp;emsp;i: &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,&lt;br /&gt;&amp;emsp;}] = &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;&lt;br /&gt;&amp;emsp;m[KeyB{&lt;br /&gt;&amp;emsp;&amp;emsp;s: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;B1&amp;quot;&lt;/span&gt;,&lt;br /&gt;&amp;emsp;&amp;emsp;i: &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,&lt;br /&gt;&amp;emsp;}] = &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;&lt;br /&gt;&amp;emsp;m[KeyB{&lt;br /&gt;&amp;emsp;&amp;emsp;s: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;B1&amp;quot;&lt;/span&gt;,&lt;br /&gt;&amp;emsp;&amp;emsp;i: &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;,&lt;br /&gt;&amp;emsp;}] = &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;&lt;br /&gt;&amp;emsp;fmt.Printf(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;%v\n&amp;quot;&lt;/span&gt;, m)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&amp;emsp;location := &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Asia/Tokyo&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;emsp;loc, err := time.LoadLocation(location)&lt;br /&gt;&amp;emsp;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {&lt;br /&gt;&amp;emsp;&amp;emsp;loc = time.FixedZone(location, &lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;*&lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt;*&lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt;)&lt;br /&gt;&amp;emsp;}&lt;br /&gt;&amp;emsp;time.Local = loc&lt;br /&gt;&amp;emsp;fmt.Printf(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;%v\n&amp;quot;&lt;/span&gt;, loc)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;checkPointerIncludedKey&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&amp;emsp;m := &lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[Key]&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;{}&lt;br /&gt;&amp;emsp;m[KeyC{&lt;br /&gt;&amp;emsp;&amp;emsp;t: time.Date(&lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, time.Local),&lt;br /&gt;&amp;emsp;}] = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&amp;emsp;m[KeyC{&lt;br /&gt;&amp;emsp;&amp;emsp;t: time.Date(&lt;span class=&quot;hljs-number&quot;&gt;2021&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, time.Local),&lt;br /&gt;&amp;emsp;}] = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&amp;emsp;m[KeyD{&lt;br /&gt;&amp;emsp;&amp;emsp;a: &amp;amp;KeyA{&lt;br /&gt;&amp;emsp;&amp;emsp;&amp;emsp;s: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;D1&amp;quot;&lt;/span&gt;,&lt;br /&gt;&amp;emsp;&amp;emsp;},&lt;br /&gt;&amp;emsp;}] = &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;br /&gt;&amp;emsp;m[KeyD{&lt;br /&gt;&amp;emsp;&amp;emsp;a: &amp;amp;KeyA{&lt;br /&gt;&amp;emsp;&amp;emsp;&amp;emsp;s: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;D1&amp;quot;&lt;/span&gt;,&lt;br /&gt;&amp;emsp;&amp;emsp;},&lt;br /&gt;&amp;emsp;}] = &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;&lt;br /&gt;&amp;emsp;fmt.Printf(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;%v\n&amp;quot;&lt;/span&gt;, m)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;&amp;emsp;checkInterfaceKey()&lt;br /&gt;&amp;emsp;checkPointerIncludedKey()&lt;br /&gt;}&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description><pubDate>Mon, 01 Feb 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-01-30-beware-to-update-aws-tools.html</guid><link>https://krymtkts.github.io/posts/2021-01-30-beware-to-update-aws-tools.html</link><title>AWS.Tools.Installer で入れたモジュールの更新は気をつけろよ</title><description>&lt;div class=&quot;section&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Install-Package&lt;/span&gt;: C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\PowerShellGet\&lt;span class=&quot;hljs-number&quot;&gt;2.2&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;\PSModule.psm1:&lt;span class=&quot;hljs-number&quot;&gt;13069&lt;/span&gt;&lt;br /&gt; Line |&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;13069&lt;/span&gt; |  …           &lt;span class=&quot;hljs-variable&quot;&gt;$sid&lt;/span&gt; = PackageManagement\&lt;span class=&quot;hljs-built_in&quot;&gt;Install-Package&lt;/span&gt; @PSBoundParameters&lt;br /&gt;      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;      | Unable to find repository &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;C:\Users\takatoshi\AppData\Local\Temp\xeqcnbnp.pgl&amp;#x27;&lt;/span&gt;. Use &lt;span class=&quot;hljs-built_in&quot;&gt;Get-PSRepository&lt;/span&gt; to see all available repositories.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;普段 PowerShell Module を一括更新しているのだけど、変なエラーが出るよになった。&lt;/p&gt;
&lt;p&gt;一括更新は、 &lt;code&gt;Get-InstalledModule | Update-Module -AllowPrerelease&lt;/code&gt; で。&lt;/p&gt;
&lt;p&gt;ちょうど最近、 &lt;a href=&quot;https://github.com/PowerShell/PowerShellGetv2/issues/303&quot; title=&quot;Publish-Module うまくいかない問題&quot;&gt;Publish-Module うまくいかない問題&lt;/a&gt; を解消したり Win10 の更新したりしてたので、そのへんかなーと思い NuGet の Provider の登録し直しとか色々やっても直らず 😥&lt;/p&gt;
&lt;p&gt;初心に帰って、↑ のログを見てみたら「何やねんこの謎 repo」というのに気づき、 改めて&lt;code&gt;Get-InstalledModule&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-PowerShell&quot;&gt; ⚡ takatoshi  ~  &lt;span class=&quot;hljs-built_in&quot;&gt;Get-InstalledModule&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Version              Name                                Repository           Description&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;              &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                                &lt;span class=&quot;hljs-literal&quot;&gt;----------&lt;/span&gt;           &lt;span class=&quot;hljs-literal&quot;&gt;-----------&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;4.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;7.0&lt;/span&gt;              AWS.Tools.Amplify                   C:\Users\takatoshi\… The Amplify module of AWS Tools &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell lets developers and administrators manage AWS Amplify from the PowerShell scripting environment. &lt;span class=&quot;hljs-keyword&quot;&gt;In&lt;/span&gt; order to manage each AWS service, install th…&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;4.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;7.0&lt;/span&gt;              AWS.Tools.CloudFormation            C:\Users\takatoshi\… The CloudFormation module of AWS Tools &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell lets developers and administrators manage AWS CloudFormation from the PowerShell scripting environment. &lt;span class=&quot;hljs-keyword&quot;&gt;In&lt;/span&gt; order to manage each AWS servi…&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;4.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;7.0&lt;/span&gt;              AWS.Tools.Common                    C:\Users\takatoshi\… The AWS Tools &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell lets developers and administrators manage their AWS services from the PowerShell scripting environment. &lt;span class=&quot;hljs-keyword&quot;&gt;In&lt;/span&gt; order to manage each AWS service, install the correspon…&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;4.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;7.0&lt;/span&gt;              AWS.Tools.EC2                       C:\Users\takatoshi\… The EC2 module of AWS Tools &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell lets developers and administrators manage Amazon Elastic Compute Cloud (EC2) from the PowerShell scripting environment. &lt;span class=&quot;hljs-keyword&quot;&gt;In&lt;/span&gt; order to manage each AWS …&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;4.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;7.0&lt;/span&gt;              AWS.Tools.IdentityManagement        C:\Users\takatoshi\… The IdentityManagement module of AWS Tools &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell lets developers and administrators manage AWS Identity and Access Management from the PowerShell scripting environment. &lt;span class=&quot;hljs-keyword&quot;&gt;In&lt;/span&gt; order to m…&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;              AWS.Tools.Installer                 PSGallery            The AWS.Tools.Installer module makes it easier to install, update and uninstall other AWS.Tools modules (see https://www.powershellgallery.com/packages/AWS.Tools.Common/).…&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;4.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;7.0&lt;/span&gt;              AWS.Tools.Lambda                    C:\Users\takatoshi\… The Lambda module of AWS Tools &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell lets developers and administrators manage AWS Lambda from the PowerShell scripting environment. &lt;span class=&quot;hljs-keyword&quot;&gt;In&lt;/span&gt; order to manage each AWS service, install the …&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;4.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;7.0&lt;/span&gt;              AWS.Tools.S3                        C:\Users\takatoshi\… The S3 module of AWS Tools &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell lets developers and administrators manage Amazon Simple Storage Service (S3) from the PowerShell scripting environment. &lt;span class=&quot;hljs-keyword&quot;&gt;In&lt;/span&gt; order to manage each AWS s…&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;4.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;7.0&lt;/span&gt;              AWS.Tools.SecretsManager            C:\Users\takatoshi\… The SecretsManager module of AWS Tools &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell lets developers and administrators manage AWS Secrets Manager from the PowerShell scripting environment. &lt;span class=&quot;hljs-keyword&quot;&gt;In&lt;/span&gt; order to manage each AWS serv…&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;0.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;                ClipboardText                       PSGallery            Support &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; text&lt;span class=&quot;hljs-literal&quot;&gt;-based&lt;/span&gt; clipboard operations &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell Core (cross&lt;span class=&quot;hljs-literal&quot;&gt;-platform&lt;/span&gt;) and older versions of Windows PowerShell&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1.3&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;                Configuration                       PSGallery            A module &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; storing and reading configuration values, with full &lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Data&lt;/span&gt; serialization, automatic configuration &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; modules and scripts, etc.&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1.2010&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0.201211&lt;/span&gt;      DockerCompletion                    PSGallery            Docker command completion &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell.&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1.27&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0.200908&lt;/span&gt;        DockerComposeCompletion             PSGallery            Docker Compose command completion &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell.&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;0.16&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;2.190903&lt;/span&gt;        DockerMachineCompletion             PSGallery            Docker Machine command completion &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; PowerShell.&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;0.2&lt;/span&gt;                  MavenAutoCompletion                 PSGallery            Maven Auto Completion provides a simple auto completion of Maven &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt; to PowerShell.&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;3.75&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-beta&lt;/span&gt;          &lt;span class=&quot;hljs-built_in&quot;&gt;oh&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;                          PSGallery            A prompt theme engine &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; any shell&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1.4&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;                PackageManagement                   PSGallery            PackageManagement (a.k.a. OneGet) is a new way to discover and install software packages from around the web.…&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;5.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-rc1&lt;/span&gt;            Pester                              PSGallery            Pester provides a framework &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; running BDD style Tests to execute and validate PowerShell commands inside of PowerShell and offers a powerful &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; of Mocking Functions that allow tests to mim…&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;                poco                                PSGallery            Interactive filtering command based on peco&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-beta3&lt;/span&gt;          posh&lt;span class=&quot;hljs-literal&quot;&gt;-git&lt;/span&gt;                            PSGallery            Provides prompt with Git status summary information and tab completion &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; Git commands, parameters, remotes and branch names.&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;0.16&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;               PowerShellForGitHub                 PSGallery            PowerShell wrapper &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; GitHub API&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;3.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-beta10&lt;/span&gt;         PowerShellGet                       PSGallery            PowerShell module with commands &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; discovering, installing, updating and publishing the PowerShell artifacts like Modules, DSC Resources, Role Capabilities and Scripts.&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;4.9&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;                psake                               PSGallery            psake is a build automation tool written &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; PowerShell.&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;2.2&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-beta1&lt;/span&gt;          PSReadLine                          PSGallery            Great command line editing &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; the PowerShell console host&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1.19&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;               PSScriptAnalyzer                    PSGallery            PSScriptAnalyzer provides script analysis and checks &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; potential code defects &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; the scripts by applying a &lt;span class=&quot;hljs-built_in&quot;&gt;group&lt;/span&gt; of built&lt;span class=&quot;hljs-operator&quot;&gt;-in&lt;/span&gt; or customized rules on the scripts being analyzed.&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;0.2&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;                Terminal&lt;span class=&quot;hljs-literal&quot;&gt;-Icons&lt;/span&gt;                      PSGallery            PowerShell module to add file icons to terminal based on file extension&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;2.2&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;                &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItemColor&lt;/span&gt;                  PSGallery            &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItemColor&lt;/span&gt; provides colored versions of &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; Cmdlet and &lt;span class=&quot;hljs-built_in&quot;&gt;Get-ChildItem&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Format-Wide&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;ls&lt;/span&gt; equivalent)&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;0.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;                &lt;span class=&quot;hljs-built_in&quot;&gt;Get-GzipContent&lt;/span&gt;                     PSGallery            Gets the content of the gzip archive at the specified location.&lt;br /&gt;&lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;1.10&lt;/span&gt;             GoogleCloud                         PSGallery            PowerShell cmdlets &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the Google Cloud Platform.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ﾌｷﾞｬｰ、AWS.Tools.Installer で入れたモジュールは全て repo が一時ファイルになっとるやんけ！😇&lt;/p&gt;
&lt;p&gt;これは事案ですね。ということでとりま暫定対処として Repository が PSGallery のやつだけにした。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-InstalledModule&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Property&lt;/span&gt; Repository &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Update-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-AllowPrerelease&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-tools-for-powershell/issues?q=is%3Aissue+is%3Aopen+unable+to+find+repository&quot; title=&quot;AWS Tools の GitHub&quot;&gt;AWS Tools の GitHub&lt;/a&gt; を見てみても誰も同じような話はしてないし、みんな真面目に&lt;code&gt;Update-AWSToolsModule&lt;/code&gt;と&lt;code&gt;Update-Module&lt;/code&gt;使い分けれてんねな～エライ！というのに気づいた一日であった。&lt;/p&gt;
&lt;p&gt;ﾁｬﾝﾁｬﾝ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 30 Jan 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2021-01-04-planning.html</guid><link>https://krymtkts.github.io/posts/2021-01-04-planning.html</link><title>2021</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;年始めに抱負を明文化しておくのと年末振り返りしやすいから例年通りやっとく。
なんか定量的なやつと定性的なやつがごっちゃになっとるけど、ええんや。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;テーマ: 自分を大事に&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;これは仕事と自己学習の両方でだ。&lt;/p&gt;
&lt;p&gt;仕事の方は、年末年始ずっと働き詰めだった。土日以外で完全な休みは今日 2020-01-04 となってしまった。もちろん家族への負担も大きかったし、年末年始でやろうと思っていた勉強だったり久しぶりにゲームやっちゃうかな？といった Fun な部分も全て蔑ろにしてしまった。
何でもかんでも「ワイがやらなあかんねや」と意気込むのは良いのだが、そこで得られるものとは如何に？刮目せなあかん。
数年前にエッセンシャル思考を読んだあと、立ち振舞を改めたときの状況に似ている。同じ轍を踏んでもーたわけでみっともない話や。&lt;/p&gt;
&lt;p&gt;わたしが働くのは、楽しくプログラムを書いて自分を高め、かつ日銭を稼ぐことのできる都合が良い仕事だからだ。自身の人生を蔑ろにしたいわけではない。ここを改めて強調していきたい。&lt;/p&gt;
&lt;p&gt;自己学習においても同様、WFH 歴もあと数ヶ月で 1 年となるけど、家のことをやる時間だけが増殖して、本を読む機会を失ってしまった。このように自分の考えを文章にまとめる機会すら少なくなっていた。これはよろしくない。
新しい技術などは極力仕事で取り組めるように取りなしているが、そこから溢れるものは私生活で掬うしかない。
学習習慣を日常生活に浸透させることでこの状況を打破したい。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2021-&quot; href=&quot;#2021-&quot;&gt;2021 年の目標&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;継続するテーマと新しい奴ら。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;NEW!&lt;/strong&gt; 住みたい場所を決める&lt;ul&gt;
&lt;li&gt;長年田舎に住みたいと思っているのだけど、昨年色々あって目当てだったところは住むのが難しそうになった。とりあえず今年はふんわりとでも候補地を固めるのが目標。&lt;/li&gt;&lt;li&gt;現職は WFH やからいいけどもし転職したら...とか考えると成約ばかりにで嫌気がさすが、そこは縛りゲーばりに割り切ってフルリモートの仕事しか選ばん所存。&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;strong&gt;NEW!&lt;/strong&gt; 仕事上の掃除&lt;ul&gt;
&lt;li&gt;&lt;code&gt;組織とビジネスは潰す、ひとつずつ、一ドルずつ、一人ずつ - ロバート・マッコール&lt;/code&gt;&lt;/li&gt;&lt;li&gt;壊れたままの〇〇&lt;ul&gt;
&lt;li&gt;CI パイプライン直す&lt;/li&gt;&lt;li&gt;テスト直す&lt;/li&gt;&lt;li&gt;チーム直す&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;これはまず家を建てる前に土台を固めるのと同じことなので、この障害を取り除かんとアプリをもりもり書くのも難しい&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;昇給&lt;ul&gt;
&lt;li&gt;やってることが間違っていなけれ場評価は勝手についてくるのだが、金額はついてこないので、ここは要相談やな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;積ん読の消化&lt;ul&gt;
&lt;li&gt;月に 1 冊を消化する&lt;/li&gt;&lt;li&gt;いま SNS 殆どやってないけど、Chrome のサジェストや RSS のフィードを読む時間増えてるので、そこを読書に置き換える&lt;/li&gt;&lt;li&gt;手の届くとこに読んでる本数冊を置くとか？&lt;/li&gt;&lt;li&gt;いま昼飯時間も仕事してるからそれを単純に読書に置き換えるのも良い&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;OSS へのコントリビューション&lt;ul&gt;
&lt;li&gt;気が向いたら。とりあえず今は身の回りのこと優先なので低く。&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;自作ツールの更新&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/Get-GzipContent&quot; title=&quot;krymtkts/Get-GzipContent: Get-Content for gzip files.&quot;&gt;krymtkts/Get-GzipContent: Get-Content for gzip files.&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt; ファイルに対応させる(最近できてへんのに気づいた)&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/mccall-bot&quot; title=&quot;mccall-bot&quot;&gt;mccall-bot&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;Typo 修正、マルチチャンネル対応したい...&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;ギター練習を 30 分/週 3 回&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aristidesinstruments.com/guitar/h-08&quot; title=&quot;真に求めていたスペックのギター&quot;&gt;真に求めていたスペックのギター&lt;/a&gt;が現れたのだけど、スキルのほうが劣化しすぎて...一から出直すため&lt;/li&gt;&lt;li&gt;バンド練習は COVID19 のこともあるし当面無理かな&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://krymtkts.github.io/&quot; title=&quot;このブログ&quot;&gt;このブログ&lt;/a&gt;を毎月更新する&lt;ul&gt;
&lt;li&gt;いつも未達なので&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;strong&gt;NEW!&lt;/strong&gt; 日頃使ってるスニペット的なのを Gist に登録していく&lt;ul&gt;
&lt;li&gt;Evernote に書いたりローカルに残してるよりも、こっちのほうが良さそうやから&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;</description><pubDate>Mon, 04 Jan 2021 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2020-12-27-ns-record-of-route53-hosted-zone.html</guid><link>https://krymtkts.github.io/posts/2020-12-27-ns-record-of-route53-hosted-zone.html</link><title>Rote53 ホストゾーンの NS レコード</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;これで 12 月だいぶ躓いたので書いとくわ。思い出じゃ。&lt;/p&gt;
&lt;p&gt;NS レコードは Simple Routing しかサポートしてへん。まずそれは AWS Management Console でわかる。
これを AWSPowerShell のパラメータでどうやんのかがわからんかった。ワタシが阿呆やからに違いない。&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/krymtkts/7774bb65f2f0351697a47383aefe9ec9.js&quot;&gt;&lt;/script&gt;&lt;p&gt;はまったところ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/reference/route53/change-resource-record-sets.html&quot; title=&quot;change-resource-record-sets — AWS CLI 1.18.203 Command Reference&quot;&gt;change-resource-record-sets — AWS CLI 1.18.203 Command Reference&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SetIdentifier -&amp;gt; (string)&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Resource record sets that have a routing policy other than simple: An identifier that differentiates among multiple resource record sets that have the same combination of name and type, such as multiple weighted resource record sets named acme.example.com that have a type of A. In a group of resource record sets that have the same name and type, the value of SetIdentifier must be unique for each resource record set.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;For information about routing policies, see Choosing a Routing Policy in the Amazon Route 53 Developer Guide .&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Alias レコードのパラメータからコピペしてたので&lt;code&gt;SetIdentifier&lt;/code&gt;を残したままにしてしまっていた。NS レコードは Simple Routing のみを許可するのでエラーになるのね。↓&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;  &lt;span class=&quot;hljs-number&quot;&gt;52&lt;/span&gt; |  &lt;span class=&quot;hljs-built_in&quot;&gt;Edit-R53ResourceRecordSet&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-HostedZoneId&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$ParentHostedZone&lt;/span&gt;.Id &lt;span class=&quot;hljs-literal&quot;&gt;-ChangeB&lt;/span&gt; …&lt;br /&gt;     |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;     | Invalid request: Expected exactly one of [&lt;span class=&quot;hljs-type&quot;&gt;Weight&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;Region&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;Failover&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;GeoLocation&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;MultiValueAnswer&lt;/span&gt;], but found none &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; Change with [&lt;span class=&quot;hljs-type&quot;&gt;Action&lt;/span&gt;=&lt;span class=&quot;hljs-type&quot;&gt;CREATE&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;Name&lt;/span&gt;=&lt;span class=&quot;hljs-type&quot;&gt;test.testtest.com&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;Type&lt;/span&gt;=&lt;span class=&quot;hljs-type&quot;&gt;NS&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;SetIdentifier&lt;/span&gt;=&lt;span class=&quot;hljs-type&quot;&gt;nandeyanen&lt;/span&gt;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;わかりにくぅ！&lt;/p&gt;
&lt;p&gt;おわり 😭&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 27 Dec 2020 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2020-12-26-retrospective2020.html</guid><link>https://krymtkts.github.io/posts/2020-12-26-retrospective2020.html</link><title>振り返り 2020 年</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;2020 年を振り返る。&lt;/p&gt;
&lt;p&gt;2020 年は自分の人生の中でも全く予想のつかない年であったと同時に、停滞感を感ずる年でもあった。以下ダイジェスト。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一人でサブシステム&lt;/li&gt;&lt;li&gt;COVID-19 流行からのフルリモートワーク&lt;/li&gt;&lt;li&gt;チームメンバのクビ&lt;/li&gt;&lt;li&gt;フラストレーションの多い下半期&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;一人でサブシステム&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ほとんど偶然の流れでサーバーレスな ETL を一人で作る機会を得た。&lt;/p&gt;
&lt;p&gt;すぐに作って初夏までにリリース的な感じのやつでやった。サービスの見込みが「ほんまにそんなにユーザとれんのか？おお？」的なきな臭い感じだったので極力維持費をかけないようにサーバーレスに。そしたら案の定、年末までほとんど利用されることなかったんでこの選択は我ながら良いとおもた。サブシステム単体の原価が 1 日 40 円程度とめちゃくちゃ安い、ものすごく利益率がいいので、使ってもらえれば儲かる。
結果的に Go on AWS Step Functions &amp;amp; AWS Lambda を組み合わせて作った。その際に Aurora Serverless やら Cognito やら使ったことないサービスを利用でけたこと、IaC 大前提でイチから権限の設計だったりできたのはかなりいい経験になったなーとおもとる。
というか今年のハイライトはここちゃうか...という気もしなくない。裁量という面においては。&lt;/p&gt;
&lt;p&gt;もちろんヘマこいたところもいっぱいあるんやけど、それすら次に活かそうという気持ちになれるやつらでヒジョーにポジティブに考えれていた時期。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;運用用途で 1 日のデータ量の集計を Aurora Serverless に保持するようにしたが、これは結果的に要らなかった&lt;ul&gt;
&lt;li&gt;DynamoDB にエントリを作っといて、後でからスクリプトなり最近増えた SQL のサポートで良かったんじゃないか、的な。そうすれば維持費ももっと抑えれた&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;Cognito むずすぎ&lt;ul&gt;
&lt;li&gt;S3 へのアクセス制御を Cognito で行った。結果的にバケツへアクセスする一時クリデンシャルを作成する形にしたが、これはどうも OAuth2 仕様だと機器間認証を使うべきだったらしい。わからん&lt;/li&gt;&lt;li&gt;こんなの？&lt;a href=&quot;https://medium.com/faun/setting-up-a-machine-to-machine-authentication-system-with-amazon-cognito-4c8e2de41c2e&quot; title=&quot;Machine-to-machine authentication with Amazon Cognito | FAUN&quot;&gt;Machine-to-machine authentication with Amazon Cognito | FAUN&lt;/a&gt;&lt;/li&gt;&lt;li&gt;あと秒間の initiate auth 上限がしょぼくて同時ログイン多いと使えない。AWS SA の方にも Auth0 にしとけって言われてしまう始末。とはいえ料金的にこっちのが安くて選んだ&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;Go の熟れてなかった感&lt;ul&gt;
&lt;li&gt;複数エンドポイント作るのにオレオレディレクトリ構造で作ったのでややこしい形に&lt;ul&gt;
&lt;li&gt;すぐ良くないのがわかったので次の Go 経験で&lt;a href=&quot;https://github.com/golang-standards/project-layout&quot; title=&quot;golang-standards/project-layout: Standard Go Project Layout&quot;&gt;golang-standards/project-layout: Standard Go Project Layout&lt;/a&gt; を速攻取り込んで改善した&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;JSON＆ファイルストリーム操作がいまいち&lt;ul&gt;
&lt;li&gt;aws-go-sdk で S3 から gzip された JSON 取り込むのにパイプを使ってうまく空間計算量を減らしたが、まだちょっとイケてない部分が残ってて極端にファイルサイズが大きいと死にうる。これをもっとうまくできたろうと思う&lt;/li&gt;&lt;li&gt;JSON のパースエラーを親切にする方法はこわかったので、次の経験で活かした&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;channel や独自の型は相性が良かったのか難なく。後のデスマーチプロジェクトでもそれが活きた&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;Aurora Serverless Data API の使いこなし&lt;ul&gt;
&lt;li&gt;接続時に最大 1 分くらい応答がないけど Data API ではタイムアウト時間を延ばせず(標準 50 秒くらい)、そのエラーハンドリングが下手くそだった。結果的にリリース後相当経ってからの対応になったが error 型でリトライ可能エラーとか切り分けた&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;COVID-19-&quot; href=&quot;#COVID-19-&quot;&gt;COVID-19 流行からのフルリモートワーク&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;これは IT 系ならどこもそうだろうと思うが、ついにフルリモートワークになった。もともと子守で週に数回在宅勤務時間を設けていたが、フルリモートとなるとその労働体験は全く異なる。&lt;/p&gt;
&lt;p&gt;通勤時間 2 時間がまるっとなくなった分かなり楽になったが、逆に駆けつけ 3 杯だったり、思考しながら歩いたりといった息抜きのタイミングがなくなった。家庭へのサポートの負担がより増えたことで読書や自習の時間も確保しにくく、それこそ自身の学びのスタイルを再構築する程度には追い詰められたのかなと思う。もちろん自走できるエンジニアにとしては労働体験は向上したのだけど。&lt;/p&gt;
&lt;p&gt;半年以上フルリモートワークなのだけど、この状況に合わせた最良の方法は、まだ模索中。&lt;/p&gt;
&lt;p&gt;少しずつ習慣化していたワークアウトは、こういった状況だと有無の効果がわかりやすかった(メンタル面の安定において)。でも引っ越し後機会を取れていなくバランスを崩している。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;チームメンバのクビ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;これは自身の労働体験では一番悪い出来事だった。1 年半ほどずっと同じチームメンバとして働いてきて、コンテキストの共有もできていたし、ようやくチーム開発が回りだすなという状況だったが、いなくなってしまった。優秀な方で、鼓を打てば響くがごとく(個人的には)よいチームワークやと感じていただけに非常に残念だったし、前職チームリーダ時代にメンバのおじさまエンジニアの年俸 150 万をふっとばしてしまった経験と同列くらいで、自分の至らなさを悔やみ続ける事件になった。
チーム開発がしたかったけど、これは当面できなくなってしまった。これが結局フラストレーションを溜め始める 1 要素になったのは間違いない。
その後を埋める形で？優秀なメンバを得れたのだけど、自律性といった意味では前任者が天才的だったのと、1 年半の間の積み重ねが灰燼に帰したこともあって傷心チックな状態は今も続いている。&lt;/p&gt;
&lt;p&gt;その中で唯一救われたのは、件の方がエンジニアとしてのキャリアを見定めて次の活動をすでに始めている点。これだけは本当に良かった。幸多からんことを。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;フラストレーションの多い下半期&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;チーム開発 ≒ わたしのなかではコラボレーションができない仕事というのは、自分の出力以上のものが期待できないのと同時に学びや気づきも自発的なもの以外にないという面白くない状態でであって、これが半年間の間続いたことで相当に気分が参ってしまった。この下半期の間続いていたデスマーチ的な案件も、参加メンバは多いのに情報連携の齟齬がこれでもかというくらいにあって、まあ色々疲れてしまった。件の方もこのプロジェクトに参加中にいなくなったにもかかわらず、開発者は補充されなかったのでけっきょくワイ一人で開発してたよーな気分。
この間にでかい会社のリクルータが面談の話を持ってきたので挑んでみたが、これまた全然だめだった。知識もメンタルも準備大事。&lt;/p&gt;
&lt;p&gt;苛々する時期だったが、年の瀬には曲りなりにもアプリケーションは本番稼働し、面談で感じた自分の至らなさから改めて自身のエッセンシャルな選択肢を掘り起こす事ができたので、プラスマイナス 0 くらいの経験になったのではないか？とは思っている。
今振り返ると、ETL の失敗経験からこのデスマーチに取り組んだ改善点は相当数あって、そういった進歩を楽しめていなかった点でもわたし自身気分が落ちてたんやろなーというのが明らかや。&lt;/p&gt;
&lt;p&gt;このデスマーチの裏では別の Fury Road が残ってて、年末年始も働くのだ。でも全然気持ちのしんどさが違う。&lt;/p&gt;
&lt;p&gt;※デスマーチゝいうてるけど肉体的な労働負荷は全然大したことない。偏に 8 時間と少ししか働けない自身の限られた時間内でやるべきでないしょうもないことに時間を浪費してしまっていたり、そういったところがデスなマーチなのだ。アドレナリンジャンキーになれていたらもっと追い込んで働けたろうに。リモートワークではそこまで中毒できないんちゃうかな？&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2020-&quot; href=&quot;#2020-&quot;&gt;2020 年目標と成果&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;年初に以下の目標を羅列した。その結果は次の通り。惨憺たる結果。まず目標が多い、多すぎるわ。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;家庭&lt;ul&gt;
&lt;li&gt;⭕️ 引越&lt;ul&gt;
&lt;li&gt;時期はかなりずれ込んだが完了&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;🔺 親族&lt;ul&gt;
&lt;li&gt;半分完了的な形。およそ 5 年後に延期&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;仕事&lt;ul&gt;
&lt;li&gt;⭕️ リモートワーク&lt;ul&gt;
&lt;li&gt;意図せずフルリモート化した&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;🔺 昇給&lt;ul&gt;
&lt;li&gt;源泉がまだだが年間 40~50 万 UP 程度で期待のとおりでなかった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;⭕️ リード的な活動&lt;ul&gt;
&lt;li&gt;できていたが、件のメンバ離脱でちょっと空回り気味&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;自分のこと&lt;ul&gt;
&lt;li&gt;❌ 積ん読の消化&lt;ul&gt;
&lt;li&gt;無理すぎた&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;🔺 OSS へのコントリビューション&lt;ul&gt;
&lt;li&gt;おしい&lt;ul&gt;
&lt;li&gt;ドキュメント修正やフォーマットだけの PR で 3 回だけ&lt;/li&gt;&lt;li&gt;Terminal-Icons の Issue にコメントして助けたのが 1 回&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;❌ 自作ツールの更新&lt;ul&gt;
&lt;li&gt;ほぼなしか。TODO はあるけど&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;❌ 音楽活動&lt;ul&gt;
&lt;li&gt;これも全然できず。というか COVID-19 で無理んなった&lt;/li&gt;&lt;li&gt;下期は忙しくて死ぬほどギターが下手くそになった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;❌ &lt;a href=&quot;https://krymtkts.github.io/&quot; title=&quot;このブログ&quot;&gt;このブログ&lt;/a&gt;を毎月更新する&lt;ul&gt;
&lt;li&gt;途中から落とした...&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;自分のことが後回しになるのは年を経るとよくあることやと思うけど、ちょっとひどい。
今年溜め込んだ知識というか、使い回せるスクリプトもあるので、年末年始の落ち着いた時期にそういう宝物を Gist にガンガン登録していこう。&lt;/p&gt;
&lt;p&gt;おわり。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 26 Dec 2020 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2020-11-01-terminal-icons-not-work-case.html</guid><link>https://krymtkts.github.io/posts/2020-11-01-terminal-icons-not-work-case.html</link><title>Terminal-Icons が動かなくなるケース</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;9 月&amp;amp;10 月と文字起こしするのをサボった 😪&lt;/p&gt;
&lt;p&gt;肉親の不幸やトラブルがあったりで気乗りしなかったのもあるが、お仕事の方で WFH になって以降最高潮に忙しさのピークを迎えていたというのもある。この辺はチームビルディングぽい要素大いにあったのでまたなんかまとめたい所存 🤔&lt;/p&gt;
&lt;p&gt;この間、OSS 活動も特に何のアクションもなく過ごしたが、ただ無為に過ごしたわけではない(と言い聞かせたい)のでなんか貢献したぽいことをネタに記事に残そうと思う。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;先日&lt;a href=&quot;https://devblogs.microsoft.com/commandline/windows-terminal-tips-and-tricks/&quot; title=&quot;Windows Terminal Tips and Tricks | Windows Command Line&quot;&gt;Windows Terminal Tips and Tricks | Windows Command Line&lt;/a&gt;を見てたら、愛すべき oh my posh の紹介の後に &lt;a href=&quot;https://github.com/devblackops/Terminal-Icons&quot; title=&quot;Terminal-Icons: A PowerShell module to show file and folder icons in the terminal&quot;&gt;Terminal-Icons: A PowerShell module to show file and folder icons in the terminal&lt;/a&gt; が紹介されていた。
なんじゃこりゃー即導入せねばなるまいな、という感じで導入してみたのだが、初回は&lt;code&gt;Get-ChildItem&lt;/code&gt;の結果に可愛らしいアイコンフォントが付与されるのに、2 回目以降は普通の見た目に戻ってしまい、なんでや...とトラシューしてみた。&lt;/p&gt;
&lt;p&gt;わかったのは、一緒に使っていた &lt;a href=&quot;https://github.com/joonro/Get-ChildItemColor&quot; title=&quot;Get-ChildItemColor: Add coloring to the output of Get-ChildItem Cmdlet of PowerShell.&quot;&gt;Get-ChildItemColor: Add coloring to the output of Get-ChildItem Cmdlet of PowerShell.&lt;/a&gt; の実行後に、Terminal-Icons のアイコンフォントが反映されなくなること。
試しに &lt;code&gt;Remove-Module Get-ChildItemColor&lt;/code&gt; すればあ～ら不思議、アイコンが復活するのである。&lt;/p&gt;
&lt;p&gt;Terminal-Icons では&lt;code&gt;format.ps1xml&lt;/code&gt; で表示内容の改変を行っているのだけど、&lt;code&gt;Get-ChildItemColor&lt;/code&gt;も色の改変をしてるし、競合してるのだろう。詳しくは追っていくのがめんどくて競合できないという結論だけだした。↓ の Issue で同じく困ってる人がいたので共有してあげた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/devblackops/Terminal-Icons/issues/12&quot; title=&quot;No icons after installation. · Issue #12 · devblackops/Terminal-Icons · GitHub&quot;&gt;No icons after installation. · Issue #12 · devblackops/Terminal-Icons · GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 01 Nov 2020 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2020-08-31-how-do-i-manage-todos.html</guid><link>https://krymtkts.github.io/posts/2020-08-31-how-do-i-manage-todos.html</link><title>TODO の管理どないしてまっか？</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;最近、TODO 管理のやり方を変えたので記しておく。&lt;/p&gt;
&lt;p&gt;いろんなタスク管理術がある。昔は Remember the Milk 使ってみたり、Evernote に TODO リスト書いたり。最近では Google Tasks 使ってみたり。へーしゃ内では Getting Things Done が優勢なんかな。
とはいえ結局の所いずれの手段もわたしにはうまく使いこなせず、結局日報的なものに落ちつていた、もう 7 年以上？日報のようなお仕事日記をつけている。&lt;/p&gt;
&lt;p&gt;ところが、そのスタイルに狂いが生じだしたのが、COVID-19 流行による出社自粛 →WFH を始めてからだ。&lt;/p&gt;
&lt;p&gt;WFH になってかなり仕事とプライベートの距離感が急接近。結果どういうわけか仕事と私生活の両方において、タスクの消化をそれまでの様にできない状態になりつつあった。7,8 割くらいのパフォが出たらいい感じ。実際はもっと悪い。&lt;/p&gt;
&lt;p&gt;思うに、往復 2 時間の通勤時間でコンテキストスイッチを緩やかに行っていたり、処理すべきタスクの組み換えとかを行っていたのだろう。歩く時間も 30 分はあったし。
スキマ時間がなくなったことで、ギアが上がりきらないままタスク消化を急いで空回りでもしてたのだろうか。
もともと仕事の日記にはプライベートのタスクを書かずに続けていたのだけど、とりあえずコンテキストスイッチを抑えるために、仕事と私生活のタスクを一括管理しようと考えた。とはいえお仕事日記は自身の振り返りのためにも使っていて、あまり私生活のノイジー？な内容を書いていくのもどうかなと。
そんな時ちょうど Chrome のサジェスト記事で &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=davraamides.todotxt-mode&quot; title=&quot;todotxt-mode - Visual Studio Marketplace&quot;&gt;todotxt-mode - Visual Studio Marketplace&lt;/a&gt; の存在を知ったので、&lt;a href=&quot;https://github.com/todotxt/todo.txt&quot; title=&quot;todo.txt&quot;&gt;todo.txt&lt;/a&gt; で、単純にタスクの管理だけを一括管理することにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/todotxt/todo.txt&quot; title=&quot;todo.txt&quot;&gt;todo.txt&lt;/a&gt;はシンプルにフォーマットが決まっているのがありがたい。また詳細を note に切り出せるのでタスク自体をシンプルに保てるのが気に入っている。&lt;/p&gt;
&lt;p&gt;複数の端末でこの「TODO を記したプレーンテキスト」を同期する必要があるが、これについては現状 &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=GustavoASC.google-drive-vscode&quot; title=&quot;Google Drive™ for VSCode - Visual Studio Marketplace&quot;&gt;Google Drive™ for VSCode - Visual Studio Marketplace&lt;/a&gt; を使っている。
Upload したファイルが上書きじゃなく、都度新しいファイルになるのがかなり気に食わないけど、生のテキストファイルが使えることを優先してのチョイスだ。&lt;/p&gt;
&lt;p&gt;今の所はゆるく todo.txt のフォーマットの一部(priority, context, due ぐらいしか使えてない)だけ運用している。
数年来のタスク管理を変える機会なので慣れないことも多いが、折角の変化の機会なので楽しんで模索してみたい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Mon, 31 Aug 2020 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2020-07-31-partial-decode-uniqid.html</guid><link>https://krymtkts.github.io/posts/2020-07-31-partial-decode-uniqid.html</link><title>PHP の uniqid をデコードする</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;なんか一意っぽい値を PHP で生成する場合の楽な手段として、 &lt;code&gt;uniqid&lt;/code&gt; がある。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/php/php-src/blob/91fbd12d5736b3cc9fc6bc2545e877dd65be1f6c/ext/standard/uniqid.c&quot; title=&quot;php-src/uniqid.c at 91fbd12d5736b3cc9fc6bc2545e877dd65be1f6c · php/php-src&quot;&gt;php-src/uniqid.c at 91fbd12d5736b3cc9fc6bc2545e877dd65be1f6c · php/php-src&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;prefix を除いた先頭 8 桁が unixtime を 16 進数で出してるだけっぽいので、こいつが何時生成されたのかを知りたい時に、以下の手順が踏める。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/ja/function.uniqid.php#95001&quot; title=&quot;PHP: uniqid - Manual&quot;&gt;PHP: uniqid - Manual&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;ここのコメントのまま使える。&lt;code&gt;more_entropy&lt;/code&gt;が有効な値で試す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// &amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;5ef4f46e0e40f9.59913527&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$d&lt;/span&gt; = &lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;date&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;r&amp;quot;&lt;/span&gt;,&lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;hexdec&lt;/span&gt;(&lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;substr&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;)));&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;echo&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$d&lt;/span&gt; . PHP_EOL);&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// Thu, 25 Jun 2020 19:01:02 +0000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;しかし手前は PHP をインストールしてなくて repl を持ってない(↑ の Repl.it でやった)ので、これを PowerShell でやる！(ついでに JST)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/10781697/convert-unix-time-with-powershell&quot; title=&quot;epoch - Convert Unix time with PowerShell - Stack Overflow&quot;&gt;epoch - Convert Unix time with PowerShell - Stack Overflow&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;5ef4f46e0e40f9.59913527&amp;quot;&lt;/span&gt;;&lt;br /&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Date&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;1970-1-1&amp;#x27;&lt;/span&gt;).AddSeconds([&lt;span class=&quot;hljs-type&quot;&gt;System.Convert&lt;/span&gt;]::ToInt32(&lt;span class=&quot;hljs-variable&quot;&gt;$s&lt;/span&gt;.Substring(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;), &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;)).ToLocalTime()&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 2020年6月26日 04:01:02&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ちょっとした小技が必要だったので覚書しておく。
無駄に PHP のコードを読んでしまった...😂&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Fri, 31 Jul 2020 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2020-06-29-contextual-sfn-example.html</guid><link>https://krymtkts.github.io/posts/2020-06-29-contextual-sfn-example.html</link><title>Step Functions のステートをまたいでパラメータを伝播するパターン</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;2020-04-30-context-like-sfn&quot; title=&quot;前の記事&quot;&gt;前の記事&lt;/a&gt;で記したアイデアの実装例を残しておいた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/contextual-sfn&quot; title=&quot;krymtkts/contextual-sfn: Example for passing parameters across states.&quot;&gt;krymtkts/contextual-sfn: Example for passing parameters across states.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;現時点で実際にお仕事で使っているパターンなのだけど、前述の通りペイロードが大幅に大きくなると問題になり得るので、より良くするすべはないものかと考え中。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;おさらい&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;StateMachine の構成。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Task&lt;/li&gt;&lt;li&gt;Map&lt;/li&gt;&lt;li&gt;Reduce&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;のステートがあるとする。Task は文字列、配列 A、配列 B を Output する。これらのデータについては以下の通りとする。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文字列(&lt;code&gt;t&lt;/code&gt;)は、フロー全体に渡って使用したいデータ。&lt;/li&gt;&lt;li&gt;配列 A(&lt;code&gt;ia&lt;/code&gt;) は、1 つ目の Map タスクで分散したいデータ。&lt;/li&gt;&lt;li&gt;配列 B(&lt;code&gt;sa&lt;/code&gt;) は、2 つ目の Map タスクで分散したいデータ。&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;このパターンを実装した背景としては以下の通り。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Map と Reduce で使いたいデータを Aurora Serverless から取得する必要がある&lt;/li&gt;&lt;li&gt;普段停止しているクラスタは結構起動に時間がかかる&lt;/li&gt;&lt;li&gt;Map では Reduce のパラメータも利用したい&lt;/li&gt;&lt;li&gt;フローの最初に全部取ってしまおう！&lt;/li&gt;&lt;/ul&gt;
&lt;h5 &gt;&lt;a name=&quot;1-Task&quot; href=&quot;#1-Task&quot;&gt;1. Task&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;Lambda からの出力がこんなのだとする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;t&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;nanigashi&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;ia&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;sa&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;A&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;B&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;C&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;D&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;E&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;ResultPath&lt;/code&gt;を&lt;code&gt;$.data&lt;/code&gt;にしておくと Task1 ステートの出力は ↓ になる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;t&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;nanigashi&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;ia&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;sa&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;A&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;B&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;C&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;D&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;E&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;YAML はこう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;Entrypoint:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Task&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Resource:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;Fn::GetAtt:&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;task&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;Arn&lt;/span&gt;]&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ResultPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$.data&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Next:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Map&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 &gt;&lt;a name=&quot;2-Map&quot; href=&quot;#2-Map&quot;&gt;2. Map&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ItemsPath&lt;/code&gt; に &lt;code&gt;$.data.ia&lt;/code&gt; を指定し、配列 A でイテレーションする&lt;/li&gt;&lt;li&gt;&lt;code&gt;Parameters&lt;/code&gt; に Lambda へ渡したいパラメータを指定する。以下の通り&lt;ul&gt;
&lt;li&gt;マッピングの各要素は&lt;code&gt;$$.Map.Item.Value&lt;/code&gt;&lt;/li&gt;&lt;li&gt;追加で渡したいパラメータを &lt;code&gt;$.data.t&lt;/code&gt;, &lt;code&gt;$.data.sa&lt;/code&gt;&lt;/li&gt;&lt;li&gt;パラメータ名末尾の&lt;code&gt;.$&lt;/code&gt;忘れがち&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;OutputPath&lt;/code&gt; に前のタスクの出力 &lt;code&gt;$.data&lt;/code&gt; を指定すれば、同じパラメータを次のステートに回せる&lt;/li&gt;&lt;li&gt;ここではマッピングの出力は無視するとして、&lt;code&gt;ResultPath&lt;/code&gt;に&lt;code&gt;$.null&lt;/code&gt;など&lt;code&gt;OutputPath&lt;/code&gt;に含まれないパスを指定する&lt;/li&gt;&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;Map:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Map&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;MaxConcurrency:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Parameters:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;k.$:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$$.Map.Item.Value&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;t.$:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$.data.t&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;a.$:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$.data.sa&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ItemsPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$.data.ia&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ResultPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$.null&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;OutputPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$.data&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Iterator:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;StartAt:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;MapTask&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;States:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;MapTask:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Task&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Resource:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;!GetAtt&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;map&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;Arn&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;End:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Next:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Reduce&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 &gt;&lt;a name=&quot;3-Reduce&quot; href=&quot;#3-Reduce&quot;&gt;3. Reduce&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ItemsPath&lt;/code&gt; に &lt;code&gt;$.sa&lt;/code&gt; を指定し、配列 B でイテレーションする&lt;/li&gt;&lt;li&gt;&lt;code&gt;Parameters&lt;/code&gt; に Lambda へ渡したいパラメータを指定する。以下の通り&lt;ul&gt;
&lt;li&gt;マッピングの各要素は&lt;code&gt;$$.Map.Item.Value&lt;/code&gt;&lt;/li&gt;&lt;li&gt;追加で渡したいパラメータを &lt;code&gt;$.data.t&lt;/code&gt;&lt;/li&gt;&lt;li&gt;パラメータ名末尾の&lt;code&gt;.$&lt;/code&gt;忘れがち(2 回目)&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;出力を制御したい場合は、Map 同様に&lt;code&gt;OutputPath&lt;/code&gt;、&lt;code&gt;ResultPath&lt;/code&gt;を指定仕分ける&lt;/li&gt;&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;Reduce:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Map&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Parameters:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;k.$:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$$.Map.Item.Value&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-string&quot;&gt;t.$:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$.t&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ItemsPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$.sa&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ResultPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$.null&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;OutputPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;$.t&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Iterator:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;StartAt:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ReduceTask&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;States:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;ReduceTask:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Task&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Resource:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;!GetAtt&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;reduce&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;Arn&lt;/span&gt;]&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;End:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;End:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;まとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;こういう例、ググっても見つからずあまり使われないパターンかも知れない。
必要だった＆実現できたので制限を理解した上で、容量用法守って使えれば良いかな。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Mon, 29 Jun 2020 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2020-05-09-try-to-elm-handson.html</guid><link>https://krymtkts.github.io/posts/2020-05-09-try-to-elm-handson.html</link><title>Elm のハンズオンを試した</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;会社の勉強会で Elm のハンズオンをしてみた。それだけ。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;Elm-&quot; href=&quot;#Elm-&quot;&gt;Elm とわたし&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;いつ頃 Elm を知ったのだろう。なんか前職ですごい H 本の輪読会をした 2015 年らへんか、2016 年とかそのあたりに知ったような気がする。&lt;/p&gt;
&lt;p&gt;爆発炎上中の新製品開発(Backbone.js なのに誰も使えてなくてやばい製品だった)のヘルプに入ってちょっとした頃。フロントエンドを全然知らなかったので一通り新しめの情報をさらってて、その中に Elm を見つけたような気がしている。&lt;/p&gt;
&lt;p&gt;最近までずっと Elm と付き合うことなく来た&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;が、ちょうどへーしゃにてフロントエンド刷新の機運があると聞き、Elm 一択ですね！と押し込むためにも開催してみた。今思えばこいつ何様やねん 🤔&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;勉強会について&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/mather/elm-handson&quot; title=&quot;mather/elm-handson: ハンズオン資料&quot;&gt;mather/elm-handson: ハンズオン資料&lt;/a&gt; を流用させていただいた。めちゃくちゃやりやすかったですありがとうございました。&lt;/p&gt;
&lt;p&gt;カンペ用にわたしは回答例みたいなのを fork して添えさせていただいた。&lt;a href=&quot;https://github.com/krymtkts/elm-handson&quot; title=&quot;krymtkts/elm-handson: ハンズオン資料&quot;&gt;krymtkts/elm-handson: ハンズオン資料&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;元々はデータストアがあって、CRUD 操作ができて、みたいなバックエンドも含めたやつをやろうとしてた。
のだけど、わたしに Elm でハンズオンを作りきるパワーもなく、「う、めんどくせえ！」となり、またインターネッツで探してみるもめぼしいものを見つけられなかった。&lt;/p&gt;
&lt;p&gt;やはり導入部ということもあり、もっとシンプルにできるものはないか－と探していたところ、前述のハンズオンにたどり着いたのだ。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;やってみた感想&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;へーしゃのフロントエンドに Elm を採用するのには至らなそうだけど、他のエンジニアに興味を持ってもらえり静的型付け＆関数型言語のパワーを知ってもらったのは良かった。Message を足したり型変えたらめちゃくちゃ親切なコンパイルエラーになるやでー、が結構ウケた印象。
現行が複雑怪奇な PHP(Smarty)や jQuery でメンテも苦痛なところに、Elm が爽やかな風を送り込んでくれたのだから、そりゃエンジニアの認識が変わるのも必然やで。&lt;/p&gt;
&lt;p&gt;最終的に CRUD ある画面のハンズオンを目指す。遊び用 AWS 垢が支給されてるし、Amplify で Sample 探すか。
まだ何回か企画してるので、刺激を与えていきたい所存。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.jp/dp/4863542224/&quot; title=&quot;基礎からわかる Elm&quot;&gt;基礎からわかる Elm&lt;/a&gt;はもちろん読んでるで。ポチってからかなり待ったけど、無事出版され、読むことができてホッとした。 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Sat, 09 May 2020 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2020-04-30-context-like-sfn.html</guid><link>https://krymtkts.github.io/posts/2020-04-30-context-like-sfn.html</link><title>Step Functions のステートをまたいでパラメータを伝播する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;仕事でシンプルなバッチを組む必要があり、ちょうどワークフローみたいな感じだったので Step Functions で Lambda をつないで作っている。&lt;/p&gt;
&lt;p&gt;3 つ Lambda が登場するのだけど、1 つ目の Lambda の Output を 2 つ目 3 つ目で使いたい。
でも、こいつらが Map ステートなのもあり Output でつなぐのはちょっと違う。
代わりに &lt;code&gt;ResultPath&lt;/code&gt;, &lt;code&gt;OutputPath&lt;/code&gt;, &lt;code&gt;ItemPath&lt;/code&gt;, &lt;code&gt;Parameters&lt;/code&gt; の組み合わせれば、Lambda の Output にない後続のステートにつなげるのがわかったのでメモしておく。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;参考資料&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/input-output-example.html&quot; title=&quot;InputPath、ResultPath、および OutputPath 例 - AWS Step Functions&quot;&gt;InputPath、ResultPath、および OutputPath 例 - AWS Step Functions&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;これは読んでもナンノコッチャよくわからんかった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://dev.classmethod.jp/articles/step-functions-parameters/&quot; title=&quot;Step Functions の入出力処理の制御パラメータ（InputPath、 Parameters、ResultPath および OutputPath）を理解するために参照したドキュメント | Developers.IO&quot;&gt;Step Functions の入出力処理の制御パラメータ（InputPath、 Parameters、ResultPath および OutputPath）を理解するために参照したドキュメント | Developers.IO&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;流石のクラスメソッドさん、わかりやすかった&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;構成&lt;/a&gt;&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;Task&lt;/li&gt;&lt;li&gt;Map&lt;/li&gt;&lt;li&gt;Map&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;のステートがあるとする。Task は文字列、配列 A、配列 B を Output する。これらのデータについては以下の通りとする。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文字列は、StateMachine 全体に渡って使用したいデータ。&lt;/li&gt;&lt;li&gt;配列 A は、1 つ目の Map タスクで分散したいデータ。&lt;/li&gt;&lt;li&gt;配列 B は、2 つ目の Map タスクで分散したいデータ。&lt;/li&gt;&lt;/ul&gt;
&lt;h5 &gt;&lt;a name=&quot;1-Task1&quot; href=&quot;#1-Task1&quot;&gt;1. Task1&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;Lambda からの出力がこんなのだとする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;nanigashi&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;arrayA&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;arrayB&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;A&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;B&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;C&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;D&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;E&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;ResultPath&lt;/code&gt;を&lt;code&gt;$.key&lt;/code&gt;にしておくと Task1 ステートの出力は ↓ になる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;key&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;nanigashi&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;arrayA&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;arrayB&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;A&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;B&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;C&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;D&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;E&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 &gt;&lt;a name=&quot;2-Map1&quot; href=&quot;#2-Map1&quot;&gt;2. Map1&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ItemPath&lt;/code&gt; に &lt;code&gt;$.key.arrayA&lt;/code&gt; を指定し、配列 A でイテレーションする&lt;/li&gt;&lt;li&gt;&lt;code&gt;Parameters&lt;/code&gt; に Lambda へ渡したいパラメータを指定する。以下の通り&lt;ul&gt;
&lt;li&gt;マッピングの各要素は&lt;code&gt;$$.Map.Item.Value&lt;/code&gt;&lt;/li&gt;&lt;li&gt;追加で渡したいパラメータを &lt;code&gt;$.key.string&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;code&gt;OutputPath&lt;/code&gt; に前のタスクの出力 &lt;code&gt;$.key&lt;/code&gt; を指定する&lt;/li&gt;&lt;li&gt;マッピング処理の出力は無視したいので、&lt;code&gt;ResultPath&lt;/code&gt;に&lt;code&gt;$.null&lt;/code&gt;など&lt;code&gt;OutputPath&lt;/code&gt;に含まれないパスを指定する&lt;/li&gt;&lt;/ul&gt;
&lt;h5 &gt;&lt;a name=&quot;3-Map2&quot; href=&quot;#3-Map2&quot;&gt;3. Map2&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ItemPath&lt;/code&gt; に &lt;code&gt;$.arrayB&lt;/code&gt; を指定し、配列 B でイテレーションする&lt;/li&gt;&lt;li&gt;&lt;code&gt;Parameters&lt;/code&gt; に Lambda へ渡したいパラメータを指定する。以下の通り&lt;ul&gt;
&lt;li&gt;マッピングの各要素は&lt;code&gt;$$.Map.Item.Value&lt;/code&gt;&lt;/li&gt;&lt;li&gt;追加で渡したいパラメータを &lt;code&gt;$.key.string&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;出力を制御したい場合は、Map1 同様に&lt;code&gt;OutputPath&lt;/code&gt;、&lt;code&gt;ResultPath&lt;/code&gt;を指定仕分ける&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;これで Task1 の出力を Map1 をまたいで Map2 で利用できる。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;まとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;これで最初の Lambda の Output を加工せずそのまま後ろ 2 つの Lambda まで伝播できた。やったね 😂
文章だけじゃわからなさすぎる気がしてきた...今度サンプルコードを起こすことにする。&lt;/p&gt;
&lt;p&gt;ただし懸念点として以下の気になる 2 点も備えており、どうしたもんかなと言う感じでもある 🤔&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;伝播したい回数だけ階層化しないといけないのではないか&lt;ul&gt;
&lt;li&gt;出力を無視するためにはセクションを切り分けないといけなくなってるから&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;可変長のパラメータを伝播する場合、ペイロードの上限値に注意しないといけない&lt;ul&gt;
&lt;li&gt;ダブルクォートは&lt;code&gt;\&lt;/code&gt;エスケープされるようだし計算が大変&lt;/li&gt;&lt;li&gt;だからセクションを切り分けるしかなくなってる&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;出力無視することさえできたら階層化いらんなー 🤔&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Thu, 30 Apr 2020 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2020-03-31-oh-my-posh-theme.html</guid><link>https://krymtkts.github.io/posts/2020-03-31-oh-my-posh-theme.html</link><title>My own oh-my-posh theme</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;oh-my-posh の話。
ご存じない？ &lt;a href=&quot;https://github.com/JanDeDobbeleer/oh-my-posh&quot; title=&quot;JanDeDobbeleer/oh-my-posh: A prompt theming engine for Powershell&quot;&gt;JanDeDobbeleer/oh-my-posh: A prompt theming engine for Powershell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;元々、Agnoster のシンボルを変えるだけで使ってた。&lt;/p&gt;
&lt;p&gt;が、最近になって諸々の不満点 ↓ を解決したくなって、自分用のテーマを作ろうと思ったのがきっかけ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;コマンドを打った時間を出したくなった&lt;ul&gt;
&lt;li&gt;分割して Terminal を使うことが多いので仕事で CLI を使ったときにどこがいちばん最後に使ったかわかりやすくしたい&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;階層が深いディレクトリで仕事することが多く working directory の短縮表示をもっと短くしたかった&lt;ul&gt;
&lt;li&gt;デフォルトの&lt;code&gt;..&lt;/code&gt;を&lt;code&gt;.&lt;/code&gt;にする(ほんとは頭文字にしたいが)&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;Windows10 のいつの Version からか忘れたが一部の絵文字の表示が化ける(管理者権限には 💪 を使ってた)&lt;ul&gt;
&lt;li&gt;⚡ に戻す&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;作ったのはこれ。&lt;a href=&quot;https://gist.github.com/krymtkts/6f7e365fd1683d6edeb7e531f725d280&quot; title=&quot;My own oh-my-posh theme.&quot;&gt;My own oh-my-posh theme.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;oh-my-posh のテーマを作るのはかんたん。その作り方を以下に記す。&lt;/p&gt;
&lt;h3 &gt;&lt;a name=&quot;How-to-make-it&quot; href=&quot;#How-to-make-it&quot;&gt;How to make it&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;テンプレを生成してくれる機能とかはない。そのため theme の PS モジュールは手で配置することになる。ちなみに export されている function たちは以下の通りである。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/JanDeDobbeleer/oh-my-posh/blob/master/oh-my-posh.psd1#L48&quot; title=&quot;oh-my-posh/oh-my-posh.psd1 at master · JanDeDobbeleer/oh-my-posh&quot;&gt;oh-my-posh/oh-my-posh.psd1 at master · JanDeDobbeleer/oh-my-posh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ユーザ定義のテーマは &lt;code&gt;$ThemeSettings.MyThemesLocation&lt;/code&gt; に配置する(&lt;code&gt;Get-ThemesLocation&lt;/code&gt;でも同じ様子)。フォルダがなければ合わせて作成する。&lt;/p&gt;
&lt;p&gt;元ファイルはいまあるテーマからコピって作るのが手っ取り早い。わたしは&lt;a href=&quot;https://github.com/JanDeDobbeleer/oh-my-posh/blob/master/Themes/Agnoster.psm1&quot; title=&quot;Agnoster.psm1&quot;&gt;Agnoster.psm1&lt;/a&gt;から作成した。
今あるテーマの配置フォルダを知るには&lt;code&gt;Get-Theme&lt;/code&gt;を実行すれば良い。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Theme&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Name                  &lt;span class=&quot;hljs-built_in&quot;&gt;Type&lt;/span&gt;     Location&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;                  &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;     &lt;span class=&quot;hljs-literal&quot;&gt;--------&lt;/span&gt;&lt;br /&gt;krymtkts              User     C:\Users\takatoshi\OneDrive\Documents\PowerShell\PoshThemes\krymtkts.psm1&lt;br /&gt;Agnoster              Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\Agnoster.psm1&lt;br /&gt;Avit                  Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\Avit.psm1&lt;br /&gt;Darkblood             Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\Darkblood.psm1&lt;br /&gt;Fish                  Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\Fish.psm1&lt;br /&gt;Honukai               Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\Honukai.psm1&lt;br /&gt;Paradox               Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\Paradox.psm1&lt;br /&gt;Powerlevel10k&lt;span class=&quot;hljs-literal&quot;&gt;-Classic&lt;/span&gt; Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\Powerlevel10k&lt;span class=&quot;hljs-literal&quot;&gt;-Classic&lt;/span&gt;.psm1&lt;br /&gt;Powerlevel10k&lt;span class=&quot;hljs-literal&quot;&gt;-Lean&lt;/span&gt;    Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\Powerlevel10k&lt;span class=&quot;hljs-literal&quot;&gt;-Lean&lt;/span&gt;.psm1&lt;br /&gt;PowerLine             Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\PowerLine.psm1&lt;br /&gt;pure                  Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\pure.psm1&lt;br /&gt;robbyrussell          Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\robbyrussell.psm1&lt;br /&gt;Sorin                 Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\Sorin.psm1&lt;br /&gt;tehrob                Defaults C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\oh&lt;span class=&quot;hljs-literal&quot;&gt;-my-posh&lt;/span&gt;\&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;399&lt;/span&gt;\Themes\tehrob.psm1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Agnoster とわたしのテーマの差分は次の通り。&lt;code&gt;Compare-Object&lt;/code&gt;だと差分が見にくいことこの上なし！誰得 😂 なので wsl の bash から diff した。PowerSheller 失格だね(&lt;code&gt;Compare-Object&lt;/code&gt;がひどいのよ)。&lt;/p&gt;
&lt;p&gt;Unified diff でみたらこの通り。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ diff ./Modules/oh-my-posh/2.0.399/Themes/Agnoster.psm1 ./PoshThemes/krymtkts.psm1 -u
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;--- ./Modules/oh-my-posh/2.0.399/Themes/Agnoster.psm1   2020-03-13 13:22:52.000000000 +0900&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;+++ ./PoshThemes/krymtkts.psm1  2020-02-24 16:03:51.912063800 +0900&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -11,12 +11,27 @@&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     $lastColor = $sl.Colors.PromptBackgroundColor&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    $prompt = Write-Prompt -Object $sl.PromptSymbols.StartSymbol -ForegroundColor $sl.Colors.SessionInfoForegroundColor -BackgroundColor $sl.Colors.SessionInfoBackgroundColor&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $now = Get-Date -UFormat &amp;#x27;%Y-%m-%d %R&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $backwardSymbol = &amp;quot;$($sl.PromptSymbols.SegmentBackwardSymbol)&amp;quot;&lt;/span&gt;&lt;br /&gt;     #check the last command state and indicate if failed&lt;br /&gt;     If ($lastCommandFailed) {&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        $prompt += Write-Prompt -Object &amp;quot;$($sl.PromptSymbols.FailedCommandSymbol) &amp;quot; -ForegroundColor $sl.Colors.CommandFailedIconForegroundColor -BackgroundColor $sl.Colors.SessionInfoBackgroundColor&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        $rightText = &amp;quot; $($sl.PromptSymbols.FailedCommandSymbol) $now &amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        $rightLength = $rightText.Length + $backwardSymbol.Length + 1 # care the symbol size blur.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        $foregroundColor = $ThemeSettings.Colors.CommandFailedIconForegroundColor&lt;/span&gt;&lt;br /&gt;     }&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    else {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        $rightText = &amp;quot; $now &amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        $rightLength = $rightText.Length + $backwardSymbol.Length&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        $foregroundColor = $ThemeSettings.Colors.PromptForegroundColor&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $prompt += Set-CursorUp -lines 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $prompt += Set-CursorForRightBlockWrite -textLength $rightLength&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $prompt += Write-Prompt $backwardSymbol -ForegroundColor $sl.Colors.PromptBackgroundColor -BackgroundColor $sl.Colors.SessionInfoBackgroundColor&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $prompt += Write-Prompt $rightText -ForegroundColor $foregroundColor -BackgroundColor $sl.Colors.PromptBackgroundColor&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    # Write the prompt&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $prompt += Set-Newline&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+    $prompt += Write-Prompt -Object $sl.PromptSymbols.StartSymbol -ForegroundColor $sl.Colors.SessionInfoForegroundColor -BackgroundColor $sl.Colors.SessionInfoBackgroundColor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     #check for elevated prompt&lt;br /&gt;     If (Test-Administrator) {&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -24,9 +39,8 @@&lt;/span&gt;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     $user = $sl.CurrentUser&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-    $computer = $sl.CurrentHostname&lt;/span&gt;&lt;br /&gt;     if (Test-NotDefaultUser($user)) {&lt;br /&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-        $prompt += Write-Prompt -Object &amp;quot;$user@$computer &amp;quot; -ForegroundColor $sl.Colors.SessionInfoForegroundColor -BackgroundColor $sl.Colors.SessionInfoBackgroundColor&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+        $prompt += Write-Prompt -Object &amp;quot;$user &amp;quot; -ForegroundColor $sl.Colors.SessionInfoForegroundColor -BackgroundColor $sl.Colors.SessionInfoBackgroundColor&lt;/span&gt;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     if (Test-VirtualEnv) {&lt;br /&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@@ -63,7 +77,11 @@&lt;/span&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; $sl = $global:ThemeSettings #local settings&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+$sl.PromptSymbols.ElevatedSymbol = [char]::ConvertFromUtf32(0x26A1)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+$sl.PromptSymbols.FailedCommandSymbol = [char]::ConvertFromUtf32(0x274C)&lt;/span&gt;&lt;br /&gt; $sl.PromptSymbols.SegmentForwardSymbol = [char]::ConvertFromUtf32(0xE0B0)&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+$sl.PromptSymbols.SegmentBackwardSymbol = [char]::ConvertFromUtf32(0xe0b2)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-addition&quot;&gt;+$sl.PromptSymbols.TruncatedFolderSymbol = &amp;#x27;.&amp;#x27;&lt;/span&gt;&lt;br /&gt; $sl.Colors.PromptForegroundColor = [ConsoleColor]::White&lt;br /&gt; $sl.Colors.PromptSymbolColor = [ConsoleColor]::White&lt;br /&gt; $sl.Colors.PromptHighlightColor = [ConsoleColor]::DarkBlue
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ちょっと実行時間のあたりが Cmder で出した場合にずれてしまうことがあって、微妙に余白をとってたりする。
でもこれでだいたい Cmder で見ても Windows Terminal でみても美しく出力される様になっている。
Windows Terminal ではシンボルフォントがめちゃくちゃ小さくなってしまうバグが有るのでまだ 100%最高とはいけないけど(&lt;a href=&quot;https://github.com/microsoft/terminal/issues/900&quot; title=&quot;Certain &amp;quot;emoji&amp;quot; are still half-sized · Issue #900 · microsoft/terminal&quot;&gt;Certain &amp;quot;emoji&amp;quot; are still half-sized · Issue #900 · microsoft/terminal&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;余談だが、こんかい自作テーマの作成にあたり、既存テーマの PS モジュールにフォーマットの崩れを見つけたので PR 送ったら受け入れてもらえた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/JanDeDobbeleer/oh-my-posh/pull/211&quot; title=&quot;Format some themes. by krymtkts · Pull Request #211 · JanDeDobbeleer/oh-my-posh&quot;&gt;Format some themes. by krymtkts · Pull Request #211 · JanDeDobbeleer/oh-my-posh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;自分の気に入っている OSS に PR を受けれてもらえるのはちょっとした感動があるな 😚&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Tue, 31 Mar 2020 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2020-02-22-maven-auto-completion-0.2.html</guid><link>https://krymtkts.github.io/posts/2020-02-22-maven-auto-completion-0.2.html</link><title>MavenAutoCompletion v0.2</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;およそ 1 年の時を経て、MavenAutoCompletion を更新した。とても小さな更新だ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/MavenAutoCompletion/0.2&quot; title=&quot;PowerShell Gallery | MavenAutoCompletion 0.2&quot;&gt;PowerShell Gallery | MavenAutoCompletion 0.2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この 3 連休はひとりで暇なので、しょうもない更新をするのも億劫でない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2019-04-02-pubslish-first-module-to-powershell-gallery.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;やった PSGallery への公開でのミスは、スクリプトを作成していたおかげもあり、1 年ぶりでもミスらなかった。&lt;/p&gt;
&lt;p&gt;ただ...色々イケてないところも見つかっている。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;このモジュール、公開するものをサブディレクトリへコピペして公開しているのだけど、これってもともとそのディレクトリで開発してたらいい話&lt;/li&gt;&lt;li&gt;補完の定義が大量なので 1 ファイルの見通しが悪くなってる&lt;ul&gt;
&lt;li&gt;更に非推奨にしたい補完候補の説明を追加できない構造&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;対応するの忘れてる非推奨タグ残したままになってる&lt;ul&gt;
&lt;li&gt;&lt;code&gt;�x��: &amp;lt;licenseUrl&amp;gt; element will be deprecated, please consider switching to specifying the license in the package. Learn more: https://aka.ms/deprecateLicenseUrl.&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;とりあえず Issue を作っといて、忘れていても暇なときに課題を解消していけるように準備しておくかあ 😅&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 22 Feb 2020 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2020-01-29-plannning.html</guid><link>https://krymtkts.github.io/posts/2020-01-29-plannning.html</link><title>2020</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;書こう書こうと思って書けていなかった。
明文化する必要もないのかもしれんが、改めて書くことによって再認識したい、というのがこのポストの目的。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2020-&quot; href=&quot;#2020-&quot;&gt;2020 年の目標&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;大きく分けて 3 つ。家庭、仕事、自分のことだ。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;家庭&lt;/a&gt;&lt;/h5&gt;&lt;ol&gt;
&lt;li&gt;引越&lt;ul&gt;
&lt;li&gt;候補地の選定は終えている&lt;/li&gt;&lt;li&gt;永続的に住む場所ではないので次の候補も頭に浮かべておく&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;親族&lt;ul&gt;
&lt;li&gt;10 年来の、シンプルにいってくだらないが制御不可能な、問題があるため今年上半期に対応を決める&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ol&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;仕事&lt;/a&gt;&lt;/h5&gt;&lt;ol&gt;
&lt;li&gt;リモートワーク&lt;ul&gt;
&lt;li&gt;現状 5 営業日中、固定の曜日で 2 時間だけ&lt;/li&gt;&lt;li&gt;子供の送り迎えの関係もあり、春から毎日 4 時間は事務所、残りはリモートにする&lt;/li&gt;&lt;li&gt;比較的コントローラブルな部分なので必ず達成する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;昇給&lt;ul&gt;
&lt;li&gt;職位はないが Job Rank みたいな給与の等級はあって、それは前年上がったので、今年は金額的な上昇に注力する&lt;ul&gt;
&lt;li&gt;金額に注力するのは、ランクアップ時の昇給額が大したことなく、今のランクで継続的に(相対的に)良い評価を刻み続けることで上がるらしいため(へーしゃの場合)&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;リード的な活動&lt;ul&gt;
&lt;li&gt;主に CI/CD といった DevOps プラクティス, Serverless Architecture 面で貢献したい。ここに書く内容でもないが意思表明として&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ol&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;自分のこと&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;これが一番ないがしろになりがち、継続的にケアする方法も同時進行で考えたい。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;積ん読の消化&lt;ul&gt;
&lt;li&gt;月に 1 冊を消化する&lt;ul&gt;
&lt;li&gt;積ん読はもう何冊あるかわからないが、減らしていく習慣を今年確立する&lt;/li&gt;&lt;li&gt;とりあえず 1 月は、witcher① で攻略済み&lt;/li&gt;&lt;li&gt;これは自身の可能性を広げるためなので、最も優先する&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;OSS へのコントリビューション&lt;ul&gt;
&lt;li&gt;今年 5 回は PR や Issue でコントリビューションしたい&lt;/li&gt;&lt;li&gt;1 回目は AWS Docs への PR で攻略済み&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;自作ツールの更新&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/MavenAutoCompletion&quot; title=&quot;MavenAutoCompletion&quot;&gt;MavenAutoCompletion&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/krymtkts/mccall-bot&quot; title=&quot;mccall-bot&quot;&gt;mccall-bot&lt;/a&gt;&lt;/li&gt;&lt;li&gt;他、気が向いたら&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;音楽活動&lt;ul&gt;
&lt;li&gt;ギター練習を 30 分/週 3 回&lt;/li&gt;&lt;li&gt;バンド練習を年 4 回&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://krymtkts.github.io/&quot; title=&quot;このブログ&quot;&gt;このブログ&lt;/a&gt;を毎月更新する&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;4 は他より優先度が低く、かつ制御不可能な部分が多いためハードルが下がりがち。なのでかならず達成したいところ。&lt;/p&gt;
&lt;p&gt;5 は去年落とした目標なので今年こそは(それでもこのポスト時点でギリギリ 😂)&lt;/p&gt;
&lt;p&gt;救いのない社会だが、自分・家族の人生にいい影響をもたらそう。エッセンシャル思考とマッコーリズムの実践だ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Wed, 29 Jan 2020 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-12-29-retrospective2019.html</guid><link>https://krymtkts.github.io/posts/2019-12-29-retrospective2019.html</link><title>振り返り 2019 年</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;ことし 2019 年も残すところあと僅か。2019 年の自身の成長などを振り返ろう。&lt;/p&gt;
&lt;p&gt;短くまとめると、2019 年は新しいことを始めた年になった。&lt;/p&gt;
&lt;p&gt;転職し、未体験の事業領域の企業で働き始めた。
会社の後押しもあって積極的に未経験の技術を取り入れ、部分的ではあるが在宅ワークもしてみた。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;前職は、実にチョロいかいしゃだったので、6 年ほどの在職中に入社前の 8 割ほど昇給できたのはこの会社のおかげ(前々職がリーマンのあおりもあって給料安すぎたのだけど)。
しかしながら、従業員に対する評価や報酬については不誠実極まりなかったし、自分の思い描くエンジニア像に必要な経験を積めなくなったのは一番痛かった。
やる気と実力を以て希望さえすれば挑戦させてくれる、入社時にあったような腕を磨ける環境が失われていくのは、1 度ならずこの会社を最後の会社にできそうだと心に思った自分には辛いものがあった。これは過去の話だけど。&lt;/p&gt;
&lt;p&gt;転職して今の会社に入れたのもよかった。適切な判断を下すのにインフラ、クラウドの知識を求められ、わたしの技術スタックのうすーいところを絶妙に攻め立ててくれる。
おかげで徐々にではあるが弱いところを克服できている。
また強みである積極性と吸収スピードの高さが上手く活かせて、CI/CD の補填、未体験だったのにサーバーレスアーキテクチャや Python を選ばせてくれたり。
カンファレンスに積極的に参加して、社内に情報を持ち帰ったり、やりたかったことが色々でき始めた。
会社での評価も今のところは順調で、現場での自身の成長スピードを増幅できていると感じる。&lt;/p&gt;
&lt;p&gt;心配事があるとしたら、前職の 1 年目年末もこんなのだったので、同じ轍を踏みたくないなというところか 😅&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;自分でも御しきれていなかったのは、在宅ワークの部分。
今は子供の面倒を見る機会を平日は週に 1 回設けて、その日を早く帰って在宅ワークの日としている。
在宅中の仕事の進め方と家族との関わり方の両立が難しくて、まだ納得の行く形になっていない。そりゃ家族からしたら、家にいるのだから色々やってほしいことができてしまうし、このままだと単純に自身の過重労働だなあと思っている。
こういった我が家のパターンだと、在宅ワークよりもちょっとカフェとかで仕事するとかがよいのか。
通勤時間を削る＆家族とも連絡を断つ、という手段がいるのかも、ただしそれは元々わたしの考えていた在宅ワークの動機と違うけど。
この辺は来年 2020 年になってからも、また別の手段を検討していきたい。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;最後に今年密かに目標としていた、1 年間毎月投稿を書く、について。
どこにも宣言してなかったけどブログを継続するという習慣づくりのためにこの目標を据えた。
結果は未達。11 月が現職の障害対応で気持ちに余裕がなかったため。まあ投稿の数は平均月 2 のペースになってたので、この点は目をつぶろう 🙈&lt;/p&gt;
&lt;p&gt;来年も目標をゆるくだが設定して邁進したく。もっと情報に触れて、コードを書いて、という生活に昇華しよう。&lt;/p&gt;
&lt;p&gt;(きょうの投稿には 1 文字もコードがなかったけど、特例日 😆)&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 29 Dec 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-10-14-how-to-handle-waiter-of-boto3.html</guid><link>https://krymtkts.github.io/posts/2019-10-14-how-to-handle-waiter-of-boto3.html</link><title>boto3 の Waiter さんとの戯れ</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;こないだの仕事。AWS Certificate Manager で証明書をごにょごにょするアプリを書いた。&lt;/p&gt;
&lt;p&gt;Python で書いたので AWS のリソースを操作するのに &lt;a href=&quot;https://boto3.amazonaws.com/v1/documentation/api/latest/index.html&quot; title=&quot;Boto3&quot;&gt;Boto3&lt;/a&gt; というライブラリを利用した。証明書を発行したあと検証済みになるまでの待受処理が&lt;code&gt;Waiter&lt;/code&gt;という機能で提供されていたり、非常に便利で大変お世話になっている。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/acm.html#ACM.Waiter.CertificateValidated&quot; title=&quot;ACM.Waiter.CertificateValidated — Boto 3 Docs 1.9.248 documentation&quot;&gt;ACM.Waiter.CertificateValidated — Boto 3 Docs 1.9.248 documentation&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;ただ、一つバグらせてしまったところがあった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Waiter&lt;/code&gt;さんは AWS のリソースを操作する API をラップしているだけ&lt;sup&gt;&lt;a id=&quot;footnote-ref-1&quot; href=&quot;#footnote-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;なので、API がエラーを発生させた場合と待受処理がタイムアウトした場合のどちらとも、&lt;code&gt;WaiterError&lt;/code&gt;を発生させる。つまり単純にキャッチするだけの例外処理では違いに気づけないのだ 😱&lt;/p&gt;
&lt;p&gt;どのようにハンドリングするか？&lt;code&gt;WaiterError&lt;/code&gt;さんの属性を調べてあげれば良い。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dir&lt;/code&gt;したら&lt;code&gt;last_response&lt;/code&gt;なる属性があったのでそいつを見たら、もとのエラーが何だったのかは分かる形にはなってた。&lt;/p&gt;
&lt;p&gt;エラーの場合、&lt;code&gt;WaiterError.last_response[&amp;#39;Error&amp;#39;]&lt;/code&gt;にエラー情報が格納される。&lt;code&gt;Waiter&lt;/code&gt;さんがリトライ回数の上限に達して&lt;code&gt;WaiterError&lt;/code&gt;をぶん投げてきた場合は、&lt;code&gt;last_response&lt;/code&gt;には&lt;code&gt;Waiter&lt;/code&gt;さんが内包する API の戻り値が架空されるので、それをもとにエラー処理すれば良いのがわかった。以下イメージ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;{&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Error&amp;#x27;&lt;/span&gt;: {&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Message&amp;#x27;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Could not find certificate arn:aws:acm:ap-northeast-1:xxxxxxxxxxxx:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx in account xxxxxxxxxxxx.&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Code&amp;#x27;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ResourceNotFoundException&amp;#x27;&lt;/span&gt;}, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ResponseMetadata&amp;#x27;&lt;/span&gt;: {&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;RequestId&amp;#x27;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;HTTPStatusCode&amp;#x27;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;400&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;HTTPHeaders&amp;#x27;&lt;/span&gt;: {&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x-amzn-requestid&amp;#x27;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;content-type&amp;#x27;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;application/x-amz-json-1.1&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;content-length&amp;#x27;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;191&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;date&amp;#x27;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Fri, 11 Oct 2019 03:51:10 GMT&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;connection&amp;#x27;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;close&amp;#x27;&lt;/span&gt;}, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;RetryAttempts&amp;#x27;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;}}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;👍&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;h2 id=&quot;footnote-label&quot; class=&quot;sr-only&quot;&gt;&lt;hr /&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;footnote-1&quot;&gt;
&lt;p&gt;証明書の検証済みを待つ&lt;code&gt;ACM.Waiter.CertificateValidated&lt;/code&gt;の場合は&lt;code&gt;ACM.Client.describe_certificate()&lt;/code&gt;をラップしている。 &lt;a href=&quot;#footnote-ref-1&quot; data-footnote-backref aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/div&gt;</description><pubDate>Mon, 14 Oct 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-10-13-docker-toolbox-with-powershell.html</guid><link>https://krymtkts.github.io/posts/2019-10-13-docker-toolbox-with-powershell.html</link><title>PowerShell で Docker Toolbox を使う</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;へーしゃはちょっといけてなくて、秘伝の古い VM をコンテナ化しない&lt;del&gt;できない&lt;/del&gt;まま使っている。&lt;/p&gt;
&lt;p&gt;加えて社内は Windows ユーザと Mac ユーザがごちゃまぜなので VM が VirtualBox のため、Windows ユーザであるわたしは Docker on Windows を使えず。&lt;/p&gt;
&lt;p&gt;Docker Toolbox を日常使いしているのだが、&lt;code&gt;docker&lt;/code&gt;に&lt;code&gt;docker-compose&lt;/code&gt;に&lt;code&gt;docker-machine&lt;/code&gt;まで現れたらコマンドやオプションが覚えきれないのが現状である 😭&lt;/p&gt;
&lt;p&gt;これらを PowerShell で楽ちんに使おう。いますぐ以下のモジュールを PSGallery からゲットしよう。これらを発見したときは狂喜乱舞した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/DockerCompletion/1.1903.0.190723&quot; title=&quot;PowerShell Gallery | DockerCompletion 1.1903.0.190723&quot;&gt;PowerShell Gallery | DockerCompletion 1.1903.0.190723&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/DockerComposeCompletion/1.24.0.190329&quot; title=&quot;PowerShell Gallery | DockerComposeCompletion 1.24.0.190329&quot;&gt;PowerShell Gallery | DockerComposeCompletion 1.24.0.190329&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/DockerMachineCompletion/0.16.2.190903&quot; title=&quot;PowerShell Gallery | DockerMachineCompletion 0.16.2.190903&quot;&gt;PowerShell Gallery | DockerMachineCompletion 0.16.2.190903&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;以下、雑なインストール例。もちろん PowerShell Guys(勝手にそう呼んでいる)なら自前の Profile に追記しよう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Install-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; DockerCompletion,DockerComposeCompletion,DockerMachineCompletion&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Import-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; DockerCompletion,DockerComposeCompletion,DockerMachineCompletion
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで&lt;code&gt;docker-machine start&lt;/code&gt;に始まり&lt;code&gt;docker&lt;/code&gt;やら&lt;code&gt;docker-compose&lt;/code&gt;でのイメージ・コンテナの名前補完とか諸々できるようになる。世の中、すごいモジュールを作る方がいるもんやねえ 🤔&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 13 Oct 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-09-22-limitaion-of-remove-certificates.html</guid><link>https://krymtkts.github.io/posts/2019-09-22-limitaion-of-remove-certificates.html</link><title>ALBのListenerから証明書を削除するときの制限</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;タイトルの通り。&lt;/p&gt;
&lt;p&gt;仕事中にわかっただけで2つある。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ALBのListenerに登録された証明書を一度にまとめて消せる上限は10件ぽい&lt;/li&gt;&lt;li&gt;ALBのListenerから証明書を消したあと、証明書に関連づいたリソースが消えるまで待たないといけない&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;上記はPython(boto3)からAWSのリソースを操作した際のもの。boto3はpipでインストールできる最新のv1.9.233。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;1-ALB-Listener-10-&quot; href=&quot;#1-ALB-Listener-10-&quot;&gt;1. ALBのListenerに登録された証明書を一度にまとめて消せる上限は10件ぽい&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ドキュメントには書かれてない気がする。少なくとも&lt;a href=&quot;https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/elbv2.html#ElasticLoadBalancingv2.Client.remove_listener_certificates&quot; title=&quot;boto3&quot;&gt;boto3&lt;/a&gt;と&lt;a href=&quot;https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_RemoveListenerCertificates.html&quot; title=&quot;ELBのAPIリファレンス&quot;&gt;ELBのAPIリファレンス&lt;/a&gt;のどちらにも記載がない。&lt;/p&gt;
&lt;p&gt;問い合わせして聞いてないねんけど、書いてあったら教えてほしい🤔&lt;/p&gt;
&lt;p&gt;以下はListener Certificatesの上限25件全部を一気に消そうとしたときのログ。センシティブな部分は削ってある。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Traceback (most recent call last):&lt;br /&gt;  File &amp;quot;C:\workspace\alb-batch\albbatch\elbapi.py&amp;quot;, line 102, in remove_cerificates&lt;br /&gt;    Certificates=params)&lt;br /&gt;  File &amp;quot;C:\Users\takatoshi_kuriyama\.virtualenvs\alb-batch-J4EQQ8Xf\lib\site-packages\botocore\client.py&amp;quot;, line 357, in _api_call&lt;br /&gt;    return self._make_api_call(operation_name, kwargs)&lt;br /&gt;  File &amp;quot;C:\Users\takatoshi_kuriyama\.virtualenvs\alb-batch-J4EQQ8Xf\lib\site-packages\botocore\client.py&amp;quot;, line 661, in _make_api_call&lt;br /&gt;    raise error_class(parsed_response, operation_name)&lt;br /&gt;botocore.exceptions.ClientError: An error occurred (ValidationError) when calling the RemoveListenerCertificates operation: Up to &amp;#x27;10&amp;#x27; certificate ARNs can be specified, but &amp;#x27;25&amp;#x27; were specified
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;2-ALB-Listener-&quot; href=&quot;#2-ALB-Listener-&quot;&gt;2. ALBのListenerから証明書を消したあと、証明書に関連づいたリソースが消えるまで待たないといけない&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ACMで証明書を削除する場合、その証明書が他のAWSリソースに関連付けられていると&lt;code&gt;ResourceInUseException&lt;/code&gt;(boto3では&lt;code&gt;ClientError&lt;/code&gt;)で削除できない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/acm.html#ACM.Client.delete_certificate&quot; title=&quot;ACM.Client.delete_certificate&quot;&gt;ACM.Client.delete_certificate&lt;/a&gt; から抜粋。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You cannot delete an ACM certificate that is being used by another AWS service. To delete a certificate that is in use, the certificate association must first be removed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;なのでまず関連付けられたLoad BalancerのListenerなどから証明書を取り除いた後、かつ証明書の情報からもその関連付けが取り除かれたことを確認しないと安全に削除できない😱&lt;/p&gt;
&lt;p&gt;どうすればよいかというと、ACMの&lt;code&gt;DescribeCertificate&lt;/code&gt;のレスポンスに含まれる&lt;code&gt;InUseBy&lt;/code&gt;リストの中が空になってたら、それらの関連付けが取り除かれた状態なので安全に削除できる。&lt;/p&gt;
&lt;p&gt;ACMで提供されてる&lt;code&gt;Waiter&lt;/code&gt;は検証待ちのみで、それ用にはないみたいなので、以下のように手動で待ち合わせする...🤔&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;wait_until_certificate_unused&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;self, arn: &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;&lt;/span&gt;):&lt;br /&gt;    cert = &lt;span class=&quot;hljs-variable language_&quot;&gt;self&lt;/span&gt;.acm_client.describe_certificate(CertificateArn=arn)&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(cert[&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;InUseBy&amp;#x27;&lt;/span&gt;]) &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;:&lt;br /&gt;        time.sleep(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;        cert = &lt;span class=&quot;hljs-variable language_&quot;&gt;self&lt;/span&gt;.acm_client.describe_certificate(CertificateArn=arn)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;めんどくせえええええ、こんなsnipetレベルのモノは&lt;code&gt;Waiter&lt;/code&gt;作って欲しいわ😭&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 22 Sep 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-09-01-aws-lambda-cloud-front-and-serverless.html</guid><link>https://krymtkts.github.io/posts/2019-09-01-aws-lambda-cloud-front-and-serverless.html</link><title>Serverless FrameworkでAWS LambdaとCloudFront</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;AWS Lambdaって書くのはホント簡単。&lt;/p&gt;
&lt;p&gt;でも手動でデプロイするのはほんまに勘弁してほしいわ...って感じだったのでAWS強メンの同僚に相談してみたところ、&lt;a href=&quot;https://serverless.com/framework/&quot; title=&quot;Serverless Framework&quot;&gt;Serverless Framework&lt;/a&gt;ってのがいい具合に抽象化してくれてるので試しに使ってみては？と助言いただけた。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;使ってみた&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;事前にNodeが必要なことくらい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# global install&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; npm install &lt;span class=&quot;hljs-literal&quot;&gt;-g&lt;/span&gt; serverless&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# installed version&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; serverless &lt;span class=&quot;hljs-literal&quot;&gt;--version&lt;/span&gt;&lt;br /&gt;Framework Core: &lt;span class=&quot;hljs-number&quot;&gt;1.51&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;Plugin: &lt;span class=&quot;hljs-number&quot;&gt;1.3&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;SDK: &lt;span class=&quot;hljs-number&quot;&gt;2.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# generate boilerplate&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; serverless create &lt;span class=&quot;hljs-literal&quot;&gt;--template&lt;/span&gt; aws&lt;span class=&quot;hljs-literal&quot;&gt;-python3&lt;/span&gt;&lt;br /&gt;Serverless: Generating boilerplate...&lt;br /&gt; _______                             __&lt;br /&gt;|   _   .&lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;.&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;.&lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt;.&lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt;.&lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;.&lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;|  .&lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;.&lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;.&lt;span class=&quot;hljs-literal&quot;&gt;-----&lt;/span&gt;.&lt;br /&gt;|   |___|  &lt;span class=&quot;hljs-literal&quot;&gt;-__&lt;/span&gt;|   _|  |  |  &lt;span class=&quot;hljs-literal&quot;&gt;-__&lt;/span&gt;|   _|  |  &lt;span class=&quot;hljs-literal&quot;&gt;-__&lt;/span&gt;|__ &lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt;|__ &lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt;|&lt;br /&gt;|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|&lt;br /&gt;|   |   |             The Serverless Application Framework&lt;br /&gt;|       |                           serverless.com, v1.&lt;span class=&quot;hljs-number&quot;&gt;51.0&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-------&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&lt;br /&gt;&lt;br /&gt;Serverless: Successfully generated boilerplate for template: &amp;quot;aws-python3&amp;quot;&lt;br /&gt;Serverless: NOTE: Please update the &amp;quot;service&amp;quot; property in serverless.yml with your service name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで生成された関数に処理を書くだけ。あ～らかんたん😁&lt;/p&gt;
&lt;p&gt;デプロイも超簡単なので、これならCDに組み込むのも楽そう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# deploy&lt;/span&gt;&lt;br /&gt;serverless deploy &lt;span class=&quot;hljs-literal&quot;&gt;-v&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# deploy to specific stage&lt;/span&gt;&lt;br /&gt;serverless deploy &lt;span class=&quot;hljs-literal&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--stage&lt;/span&gt; dev
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;CloudFront-&quot; href=&quot;#CloudFront-&quot;&gt;CloudFrontを添えて&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;今回の仕事ではちょっと特殊な事情でCloudFrontを経由してLambdaのエンドポイントURLへリクエストする必要があった。&lt;/p&gt;
&lt;p&gt;プラグインを使えばかんたんに記述することもできる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Droplr/serverless-api-cloudfront&quot; title=&quot;Droplr/serverless-api-cloudfront: Serverless Plugin - CloudFront distribution in front of your API Gateway&quot;&gt;Droplr/serverless-api-cloudfront: Serverless Plugin - CloudFront distribution in front of your API Gateway&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;が、かんたんに記述できる＝かんたんな内容しかいじれない、のため片手落ちな点が多かった。諸々のパラメータの指定ができなくて細かな指定をする場合は結局&lt;code&gt;resources&lt;/code&gt;セクションに自力でCloudFormationを書くことになった。&lt;/p&gt;
&lt;p&gt;以下はresourceセクションのサンプル。&lt;code&gt;DomainName&lt;/code&gt;の解決は以下のStackoverflowからヒントを得た。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/50931730/deploying-lambda-api-gateway-cloudfront-through-serverless-framework-at-a-ti&quot; title=&quot;amazon web services - Deploying Lambda + API-gateway + CloudFront through serverless framework at a time - Stack Overflow&quot;&gt;amazon web services - Deploying Lambda + API-gateway + CloudFront through serverless framework at a time - Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;Resources:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;LambdaDistribution:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;Type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;AWS::CloudFront::Distribution&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;Properties:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;DistributionConfig:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Comment:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;managed by serverless framewrok&amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;HttpVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;http2&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;PriceClass:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PriceClass_All&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Origins:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;Id:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ApiGateway&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;DomainName:&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;!Join&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;!Ref&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ApiGatewayRestApi&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;execute-api&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;!Ref&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;AWS::Region&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;amazonaws.com&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;OriginPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;CustomOriginConfig:&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;HTTPPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;HTTPSPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;OriginProtocolPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;https-only&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;OriginReadTimeout:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;OriginSSLProtocols:&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;SSLv3&amp;quot;&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;TLSv1&amp;quot;&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;TLSv1.1&amp;quot;&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;TLSv1.2&amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;DefaultCacheBehavior:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;AllowedMethods:&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;HEAD&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DELETE&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;POST&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;GET&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;OPTIONS&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PUT&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PATCH&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;Compress:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;DefaultTTL:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;MaxTTL:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;MinTTL:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;ForwardedValues:&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;Cookies:&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;Forward:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;none&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;Headers:&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;x-api-key&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;QueryString:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;TargetOriginId:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ApiGateway&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;ViewerProtocolPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;redirect-to-https&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ちなみにLambda@Edgeにはまだ対応していないみたいでプラグインの利用が必須となっている様子。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/serverless/serverless/issues/3944&quot; title=&quot;Support for Lambda@Edge · Issue #3944 · serverless/serverless&quot;&gt;Support for Lambda@Edge · Issue #3944 · serverless/serverless&lt;/a&gt;&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;感想&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;AWSだけにベンダーロックインせずServeless Computingの開発ができるよーな抽象化層を提供するようなCLIのイメージ。&lt;/p&gt;
&lt;p&gt;誕生は数年前でまだまだ新し目のため、web上には新旧の情報が玉石混交の状態であるからして、細かなYAMLの記述内容の確認なんかは&lt;a href=&quot;https://serverless.com/framework/docs/&quot; title=&quot;Serverless Framework Documentation&quot;&gt;Serverless Framework Documentation&lt;/a&gt;を参考にし、大まかな書き方はそのへんのブログなどから引っこ抜いてくるのが良いと思われる。&lt;/p&gt;
&lt;p&gt;まだ1プロダクトでしか使ってないけど、いい感触を得た。YAMLの記述内容は、AWSの場合でいうとresourcesはまんまCloudFormationなので、そのへんの知識があれば使いこなせそう。SaaSのやつはまだ使ってないので感触なし。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-code-sls-code-&quot; href=&quot;#-code-sls-code-&quot;&gt;おまけ: &lt;code&gt;sls&lt;/code&gt;というコマンド名&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ばかみたいな話なんやけど、Serverless Frameworkの短縮形コマンド&lt;code&gt;sls&lt;/code&gt;はPowerShellで言うところの&lt;code&gt;Select-String&lt;/code&gt;コマンドレットにエイリアスされてるので使えねえｗ&lt;/p&gt;
&lt;p&gt;ではアデュー😘&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 01 Sep 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-08-11-test-lambda-with-pwsh.html</guid><link>https://krymtkts.github.io/posts/2019-08-11-test-lambda-with-pwsh.html</link><title>AWS LambdaをPowershellでテスト実行する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;へーしゃの支援によりGoogle Cloud Next Tokyo 2019へ参加できた。&lt;/p&gt;
&lt;p&gt;とても有意義な時間を過ごせたのでブログをしたためたかったのだけど、日が経つにつれ仕事もメモもとっ散らかってしまい清書もできず、現時点でのブログへのまとめは断念中😫&lt;/p&gt;
&lt;p&gt;代わりに小ネタを投稿する。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;curl-Powershell&quot; href=&quot;#curl-Powershell&quot;&gt;curlの代わりのPowershell&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;最近仕事でAWS Lambdaを使う機会を得た。へーしゃはAWSもGCPもどっちでもアリだが、現状はAWS優勢。わたしはGCPがいいけど。
元々最初にCloud WatchとAWS Lambdaで作った方が良いのでは？という提案をしていたのだが、大した理由もなく却下。その後追加された機能がLambdaじゃないと実行環境を準備するのが難しいというのが判明して、棚からぼた餅なチャンス到来。&lt;/p&gt;
&lt;p&gt;本題に入ろう。今回作ったLambdaはAPI Gatewayと組み合わせてWeb APIとして利用する。&lt;/p&gt;
&lt;p&gt;そのためAPI Key(&lt;code&gt;x-api-key&lt;/code&gt;)をRequest Headerに付与してリクエストされる想定でいる(現時点で)。&lt;/p&gt;
&lt;p&gt;なのでブラウザなんかでテスト実行出来ないので、大抵のやつはcurlなんかでURLを叩く。しかしここはPowershellでやってみよう。&lt;/p&gt;
&lt;p&gt;Web-APIを叩くのなら&lt;code&gt;Invoke-WebRequest&lt;/code&gt;がよかろう。追加のヘッダーは&lt;code&gt;-Headers&lt;/code&gt;にhashtableとして渡せるのだ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-WebRequest&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Uri&lt;/span&gt; https://omae&lt;span class=&quot;hljs-literal&quot;&gt;-no-api-endpoint&lt;/span&gt;/helloworld &lt;span class=&quot;hljs-literal&quot;&gt;-Headers&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;{&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;x-api-key&amp;#x27;&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;omae-no-api-key!!!&amp;#x27;&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こうなる。そんだけ😉&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 11 Aug 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-07-28-have-a-good-day-with-poco.html</guid><link>https://krymtkts.github.io/posts/2019-07-28-have-a-good-day-with-poco.html</link><title>pocoで捗る日常生活</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2019-06-23-poco.html&quot; title=&quot;以前ちょっとだけ触れたpoco&quot;&gt;以前ちょっとだけ触れたpoco&lt;/a&gt;を使いだしてから、よく使うディレクトリへの移動とか、&lt;code&gt;PSReadline&lt;/code&gt;のHistoryからよく使うコマンドを引っ張り出すとかの、インタラクティブなコマンドが作りやすくとて捗っている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/krymtkts/f8af667c32b16fc28a815243b316c5be&quot; title=&quot;Gistにあげたプロファイル&quot;&gt;Gistにあげたプロファイル&lt;/a&gt;にまるっと書いているのだけど、ココではコメントも添えて書いておく。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-code-PSReadline-code-history-&quot; href=&quot;#-code-PSReadline-code-history-&quot;&gt;&lt;code&gt;PSReadline&lt;/code&gt;のhistoryを見る/実行する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;作った関数は以下の通り。似たようなモジュールはPSGalleryに何個かあるけど、pocoで書きたかったので自作した次第。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Show-ReadLineHistory&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-PSReadlineOption&lt;/span&gt;).HistorySavePath | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Unique&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Poco&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-CaseSensitive&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set-Alias&lt;/span&gt; pghy &lt;span class=&quot;hljs-built_in&quot;&gt;Show-ReadLineHistory&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Option&lt;/span&gt; AllScope&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Invoke-ReadLineHistory&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Show-ReadLineHistory&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-First&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-Expression&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set-Alias&lt;/span&gt; pihy &lt;span class=&quot;hljs-built_in&quot;&gt;Invoke-ReadLineHistory&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Option&lt;/span&gt; AllScope
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;途中で&lt;code&gt;Select-Object -Unique&lt;/code&gt;を挟んでいるのは、わたしがやたら同じコマンドを繰り返すので重複を省くため😅&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Select-Object -First 1&lt;/code&gt;はpoco自体の機能不足(選択機能がない)のを補うためである😭&lt;/p&gt;
&lt;p&gt;ちなみにPowerShellのHistoryが謎な件についてはソースはこの辺。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/yuta0801/items/ad0cf608144fb1546e54&quot; title=&quot;PowerShellの完全な履歴を取得する - Qiita&quot;&gt;PowerShellの完全な履歴を取得する - Qiita&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/44104043/how-can-i-see-the-command-history-across-all-powershell-sessions-in-windows-serv&quot; title=&quot;How can I see the command history across all PowerShell sessions in Windows Server 2016? - Stack Overflow&quot;&gt;How can I see the command history across all PowerShell sessions in Windows Server 2016? - Stack Overflow&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Get-History&lt;/code&gt;は現在のセッションの情報しか取らない。でも実は&lt;code&gt;(Get-PSREeadlineOption).HistorySavePath&lt;/code&gt;に保存されている、という話🤔&lt;/p&gt;
&lt;p&gt;&lt;code&gt;~\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt&lt;/code&gt;な感じでテキストファイルに保存されている。&lt;/p&gt;
&lt;p&gt;ちなみに本来の&lt;code&gt;Get-History&lt;/code&gt;実行結果のような履歴ごとにIDを振るのはやってない。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;お気に入りのディレクトリへ移動する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;これはパクリ。仕事で使うリポジトリはghqを使わないで決められたディレクトリへcloneすることを期待されてたりするので、そのときにこういう任意のディレクトリへの移動ができるやつが重宝してる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mattn.kaoriya.net/software/peco.htm&quot; title=&quot;Big Sky :: Windows のコマンドプロンプトを10倍便利にするコマンド「peco」&quot;&gt;Big Sky :: Windows のコマンドプロンプトを10倍便利にするコマンド「peco」&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;あと編集機能は未実装。わたしの用途では編集よりも削除機能のほうが良いかなと思ったりしてるところ🤔&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Set-SelectedLocation&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;(&lt;br /&gt;        [&lt;span class=&quot;hljs-type&quot;&gt;ValidateSet&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Add&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Move&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Edit&amp;quot;&lt;/span&gt;)]&lt;span class=&quot;hljs-variable&quot;&gt;$Mode&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Move&amp;quot;&lt;/span&gt;,&lt;br /&gt;        [&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;]&lt;span class=&quot;hljs-variable&quot;&gt;$Location&lt;/span&gt;&lt;br /&gt;    )&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$Mode&lt;/span&gt;) {&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Add&amp;quot;&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$Location&lt;/span&gt;) {&lt;br /&gt;                &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$Location&lt;/span&gt;&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-File&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Append&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Encoding&lt;/span&gt; UTF8 &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;~/.poco-cd&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Move&amp;quot;&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;~/.poco-cd&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Poco&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-CaseSensitive&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-First&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Location&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Edit&amp;quot;&lt;/span&gt; {&lt;br /&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Set-Alias&lt;/span&gt; pcd &lt;span class=&quot;hljs-built_in&quot;&gt;Set-SelectedLocation&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Option&lt;/span&gt; AllScope
&lt;/code&gt;&lt;/pre&gt;&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;雑なまとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;これらのツールをpocoの補完ツールとしてもうちと洗練してもいいかもしれんなあと思ったりしてる🤔&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 28 Jul 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-07-07-cement-the-cli-framework.html</guid><link>https://krymtkts.github.io/posts/2019-07-07-cement-the-cli-framework.html</link><title>CementというCLIフレームワーク</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;仕事で、なんかDBに通信しながらAWSのAPIをぶん殴ってゴニョゴニョするバックエンド処理を書く必要があって、Pythonで書くことになった。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://python-guideja.readthedocs.io/ja/latest/index.html&quot; title=&quot;Python ヒッチハイク・ガイド — The Hitchhiker&amp;#39;s Guide to Python&quot;&gt;Python ヒッチハイク・ガイド — The Hitchhiker&amp;#39;s Guide to Python&lt;/a&gt;を参考にCLIのフレームワークを見ていって、サンプル的に作ってみた感じや継続的にメンテされてることとかで&lt;a href=&quot;https://builtoncement.com/&quot; title=&quot;Cement Framework&quot;&gt;Cement Framework&lt;/a&gt;を採用することにした。&lt;/p&gt;
&lt;p&gt;簡潔に説明すると、CLIアプリケーション作成を容易にするためのフレームワーク。なんとAWS Elastic Beanstalkに使われてるらしい。&lt;/p&gt;
&lt;p&gt;数少ない日本語の資料。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://qiita.com/ma2saka/items/9aacc46e20b9886ec156&quot; title=&quot;自分が必要とする最低限の Cement の情報 - Qiita&quot;&gt;自分が必要とする最低限の Cement の情報 - Qiita&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;ほんとに少ないのでなんか自分用にメモを取ろうとこの記事をしたためた次第である。&lt;/p&gt;
&lt;p&gt;ボイラープレートでCLIのベースはできてしまうので、あとはその中身を書いていくだけ。ちょっとAPIドキュメントがわかりにくい気もするが、YAMLの設定ファイル読み込みやロギングなども拡張機能としてある。今の所はとてもよくできた使いやすいFWだと思っている。こんどコードの生成らへんの簡単な手順をまとめてみたい。&lt;/p&gt;
&lt;p&gt;すでに途中までCementをベースに開発しているのだけど、少し困った点がある。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;困った点&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/datafolklabs/cement/issues/549&quot; title=&quot;Cement not compatible with pipenv · Issue #549 · datafolklabs/cement&quot;&gt;Cement not compatible with pipenv · Issue #549 · datafolklabs/cement&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;バグでpipenvは&lt;code&gt;setup.py&lt;/code&gt;をインストール出来ないのでエラーで死ぬのだ😭わたしが考えた対策としてはイカのトーリである。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;開発環境&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pipenv install -r requirement.txt&lt;/code&gt;などを使いつつ開発&lt;/li&gt;&lt;li&gt;実行時には作業ディレクトリでスクリプト実行する感じ&lt;code&gt;python -m myapp.main&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;製品環境&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pip&lt;/code&gt;を使ったインストール及び&lt;code&gt;setup.py&lt;/code&gt;でモジュールをインストール&lt;/li&gt;&lt;li&gt;モジュール実行を行うのでどこでもok(なはず)&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;まだ開発途上なので、製品環境の想定がそのままうまくいくかはビミョーなところ🤔また試行錯誤しなくては。&lt;/p&gt;
&lt;p&gt;最近は[Poetry(&lt;a href=&quot;https://cocoatomo.github.io/poetry-ja/index.html)のほうがイケてると聞くし、はじめからPipenvを使わないようにしてたら良かった感はしなくはない😭&quot; title=&quot;undefined&quot;&gt;https://cocoatomo.github.io/poetry-ja/index.html)のほうがイケてると聞くし、はじめからPipenvを使わないようにしてたら良かった感はしなくはない😭&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 07 Jul 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-06-29-season-of-openssh-error.html</guid><link>https://krymtkts.github.io/posts/2019-06-29-season-of-openssh-error.html</link><title>またOpenSSHが動かなくなる季節がやってきた</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;アップデートの度に何かあるので、もはや風物詩と化したOpenSSHのエラー。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/2019-03-31-win-openssh-is-gone.html&quot; title=&quot;前回のエラー&quot;&gt;前回のエラー&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;きょうChocolateyでパッケージ更新したらWindowsのOpenSSHがアップデートされた様子。&lt;a href=&quot;https://github.com/PowerShell/Win32-OpenSSH/releases/tag/v8.0.0.0p1-Beta&quot; title=&quot;Release v8.0.0.0p1-Beta · PowerShell/Win32-OpenSSH&quot;&gt;Release v8.0.0.0p1-Beta · PowerShell/Win32-OpenSSH&lt;/a&gt;かな？&lt;/p&gt;
&lt;p&gt;それに伴い&lt;code&gt;ssh-agent&lt;/code&gt;サービスが消え去ってしまった。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Service&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ssh-agent&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Service&lt;/span&gt; : Cannot find any service with service name &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ssh-agent&amp;#x27;&lt;/span&gt;.&lt;br /&gt;At line:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; char:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;+ &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Service&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ssh-agent&amp;#x27;&lt;/span&gt;&lt;br /&gt;+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;+ CategoryInfo          : ObjectNotFound: (ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;:String) [&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Service&lt;/span&gt;], ServiceCommandException&lt;br /&gt;+ FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;単純に再インストールしても自動でサービス登録はされなかったのだけど、同梱されているファイルを見てみたところそれらしいスクリプト&lt;code&gt;install-sshd.ps1&lt;/code&gt;を発見した。Wikiにも記載がある。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/Win32-OpenSSH/wiki/Install-Win32-OpenSSH#install-win32-openssh-test-release&quot; title=&quot;Install Win32 OpenSSH · PowerShell/Win32-OpenSSH Wiki&quot;&gt;Install Win32 OpenSSH · PowerShell/Win32-OpenSSH Wiki&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;実行してみたところ無事にサービスが作成されたので一安心。サービス自動起動の設定をしておいて完了した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; .\&lt;span class=&quot;hljs-built_in&quot;&gt;install-sshd&lt;/span&gt;.ps1&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;SC&lt;/span&gt;] SetServiceObjectSecurity SUCCESS&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;SC&lt;/span&gt;] ChangeServiceConfig2 SUCCESS&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;SC&lt;/span&gt;] ChangeServiceConfig2 SUCCESS&lt;br /&gt;sshd and ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt; services successfully installed&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Service&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ssh-agent&amp;#x27;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Status   Name               DisplayName&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt;   &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;               &lt;span class=&quot;hljs-literal&quot;&gt;-----------&lt;/span&gt;&lt;br /&gt;Stopped  ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;          OpenSSH Authentication Agent&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Set-Service&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ssh-agent&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-startuptype&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;automatic&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ふう🙃&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 29 Jun 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-06-23-poco.html</guid><link>https://krymtkts.github.io/posts/2019-06-23-poco.html</link><title>Poco</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;5月以降outputのリズムが崩れております🤔&lt;/p&gt;
&lt;p&gt;時間の使い方の改善を目論み、ポモドーロを導入するなど。まだ効果の程は見えていないので今日はPowerShell版pecoのpocoを紹介する。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;peco&quot; href=&quot;#peco&quot;&gt;peco&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;まずpecoってなんじゃこらって感じでもあるのだが、linuxなどで使えるインクリメンタルなフィルタリングコマンドらしい。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://tm.root-n.com/unix:command:peco&quot; title=&quot;Unix :: コマンド / peco [Tipsというかメモ]&quot;&gt;Unix :: コマンド / peco [Tipsというかメモ]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;こんなに便利な機能なので、もちろんWindowsでも使えるようになってある &lt;a href=&quot;https://github.com/peco/peco&quot; title=&quot;peco/peco: Simplistic interactive filtering tool&quot;&gt;peco/peco: Simplistic interactive filtering tool&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ただ日常使いのシェルをPowerShellにしている身としては、単純なテキストの絞り込みじゃなくてオブジェクトを扱えるやつが望ましいわけで...&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;poco&quot; href=&quot;#poco&quot;&gt;poco&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;というふうに思ってたら普通にPowerShell Galleryにあったわ😲&lt;/p&gt;
&lt;p&gt;PowerShellの場合は&lt;a href=&quot;https://gist.github.com/yumura/8df37c22ae1b7942dec7&quot; title=&quot;powershell peco&quot;&gt;powershell peco&lt;/a&gt;というのがあって、それを使ったPSModuleがPSGalleryに上がっている...!!!これは使わない手はないぞよ🤔&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/poco/1.1.0&quot; title=&quot;PowerShell Gallery | poco 1.1.0&quot;&gt;PowerShell Gallery | poco 1.1.0&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/jasonmarcher/poco&quot; title=&quot;jasonmarcher/poco: Interactive pipeline filtering in PowerShell (a port of peco).&quot;&gt;jasonmarcher/poco: Interactive pipeline filtering in PowerShell (a port of peco).&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;ただしこのモジュール、&lt;a href=&quot;https://gist.github.com/yumura/8df37c22ae1b7942dec7&quot; title=&quot;powershell peco&quot;&gt;powershell peco&lt;/a&gt;のコードをそのまま使ってるのが現状みたいで、作者の方が書かれている改善点そのまま残ってるくさい😭&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://qiita.com/yumura_s/items/a068329769c6338471dd&quot; title=&quot;PowerShell で peco (インタラクティブ・フィルタリングツール)っぽいものを作った - Qiita&quot;&gt;PowerShell で peco (インタラクティブ・フィルタリングツール)っぽいものを作った - Qiita&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;という具合に不完全なできであるのは確かなんやが、雰囲気でCLIにPowerShellを使っているようなワイには非常に便利なツールなのである。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;poco-&quot; href=&quot;#poco-&quot;&gt;pocoを使ってなにか書こう&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;例えば、PowerShellではCLIの完全な入力履歴を取ろうとしたら&lt;code&gt;PSReadLine&lt;/code&gt;に頼ることになるのだが、こいつをインタラクティブにフィルタリングするコマンドをぺぺっと書いてしまうこともできる↓&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Show-ReadLineHistory&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-PSReadlineOption&lt;/span&gt;).HistorySavePath | poco&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;こんな風な単純なやつは正直なところpecoで十分なのだけど...&lt;/p&gt;
&lt;p&gt;あと、検索結果の1行を選んで即実行なんしたいのだけど、pocoの機能不足でリストアップされた検索結果をarrow keyで選んだりとかできないので、今のところかなり癖のある使い方になってる😅&lt;/p&gt;
&lt;p&gt;そんな感じPowerShellにも育てたい？ツールがあって使っていくモチベーションみたいなもんが湧いてきますな？🤔現状至らないところ多いからなんかコントリビュートしたい。
でもまず時間を作らなあかんな🤔&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 23 Jun 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-06-02-install-shfmt-to-win-using-cli.html</guid><link>https://krymtkts.github.io/posts/2019-06-02-install-shfmt-to-win-using-cli.html</link><title>シェルスクリプトのフォーマッタをCLIでインストールする</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;小ネタ。&lt;/p&gt;
&lt;p&gt;へーしゃの仕事では、Bashで書かれたスクリプトの出番がめちゃくちゃ多い。&lt;/p&gt;
&lt;p&gt;Bashが得意じゃないマンのわたしにとっては、そういったスクリプトを読み書きに慣れてないこともあり、結構疲れる仕事である。&lt;/p&gt;
&lt;p&gt;そこでせめて書くのだけは少しでも楽したいと思って、フォーマッタを導入しようと思った。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;ツールを導入する&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;shfmtというgolang製のツールがあるので、それを採択。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mvdan/sh&quot; title=&quot;mvdan/sh: A shell parser, formatter, and interpreter (POSIX/Bash/mksh)&quot;&gt;mvdan/sh: A shell parser, formatter, and interpreter (POSIX/Bash/mksh)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;しかし悲しいかな、Windows用に提供されてるパッケージはScoopのみ(リンク切れてるけど)でChocolateyにない様子🤔(筆者はChocolateyユーザである)。&lt;/p&gt;
&lt;p&gt;代わりにCLIでのインストールを使うことにする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; $(&lt;span class=&quot;hljs-built_in&quot;&gt;mktemp&lt;/span&gt; -d); go mod init tmp; go get mvdan.cc/sh/v3/cmd/shfmt
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;でも&lt;code&gt;mktemp&lt;/code&gt;コマンドはPowerShellにはないし...そこは&lt;code&gt;mkdir&lt;/code&gt;で茶を濁す。あとtmpフォルダの後始末もする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;(mkdir tmp); go mod init tmp; go get mvdan.cc/sh/v3/cmd/shfmt; &lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; ../; &lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-r&lt;/span&gt; tmp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ええがな。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;雑記&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;5月後半はうまく波に乗れずブログを書けなかった。まだアウトプットが習慣化していないようなので、きちんと積み重ねしていきたいもんやで🤔&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 02 Jun 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-05-11-pipenv-skeleton.html</guid><link>https://krymtkts.github.io/posts/2019-05-11-pipenv-skeleton.html</link><title>Pipenvのテンプレを作った</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2019-04-29-bias-amp-2issue.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;の最後に触れた、仕事で経験を得た2019年のイケてそうなPython開発環境構築について。&lt;/p&gt;
&lt;p&gt;この度新し目と思われるPythonのプロジェクト構築について学んだので、次回Pythonを触ることがあったとしてもぱぱっと始められるようにテンプレートを作ろうと思った次第である。&lt;/p&gt;
&lt;p&gt;過去のeasy_installとかpipまでで知識が止まってたが、新たにpipenvを知ってかなり便利に使えるいい感じの印象を得たのもあって、動機付けされた感じ。&lt;/p&gt;
&lt;p&gt;なので、勉強がてらGW中のお楽しみにちょろっと作った。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;作ったもの&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/pipenv-skeleton&quot; title=&quot;krymtkts/pipenv-skeleton&quot;&gt;krymtkts/pipenv-skeleton&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;いろいろとググって、pipとかvirtualenvの時代は過ぎ去っており、いまはpienvがイケていると直感を得た。
なのでpipenvについて以下の記事などを参考にこのテンプレを作った。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pipenv-ja.readthedocs.io/ja/translate-ja/&quot; title=&quot;Pipenv: 人間のためのPython開発ワークフロー — pipenv 2018.11.27.dev0 ドキュメント&quot;&gt;Pipenv: 人間のためのPython開発ワークフロー — pipenv 2018.11.27.dev0 ドキュメント&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.natsukium.com/blog/2019-02-18/python/&quot; title=&quot;Python環境構築ベストプラクティス2019 - ばいおいんふぉっぽいの！&quot;&gt;Python環境構築ベストプラクティス2019 - ばいおいんふぉっぽいの！&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://qiita.com/youkidkk/items/b6a6e39ee3a109001c75&quot; title=&quot;Windows + Python 3.6 + PipEnv + Visual Studio Code でPython開発環境 - Qiita&quot;&gt;Windows + Python 3.6 + PipEnv + Visual Studio Code でPython開発環境 - Qiita&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://qiita.com/tonluqclml/items/b09f4a5ed04ebcbd0af1&quot; title=&quot;既存プロジェクトに pipenv を導入した方法 - Qiita&quot;&gt;既存プロジェクトに pipenv を導入した方法 - Qiita&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;予めLinterやらFormatterやらをdevPackageとして用意している。LinterにはPylintを用意したが、エラーの自動修正がないようなのでautopep8も用意した。&lt;/p&gt;
&lt;p&gt;あと静的型付けに守られた世界で仕事できるように、MyPyも用意している。Better Bashとして使うときは大げさかもしれないけど、その時は単にMyPyを使わなかったらいいだけ。&lt;/p&gt;
&lt;p&gt;このプロジェクトをコピペして、moduleのところをこねこねして使うイメージ。&lt;/p&gt;
&lt;p&gt;Pythonのモジュールシステムについてはまだ理解が浅い。以下を参考にドキュメントをあたって、&lt;code&gt;__init.py__&lt;/code&gt;,&lt;code&gt;__main.py__&lt;/code&gt;のらへんを定型化した感じ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/448271/what-is-init-py-for&quot; title=&quot;python - What is &lt;strong&gt;init&lt;/strong&gt;.py for? - Stack Overflow&quot;&gt;python - What is &lt;strong&gt;init&lt;/strong&gt;.py for? - Stack Overflow&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/4042905/what-is-main-py&quot; title=&quot;python - What is &lt;strong&gt;main&lt;/strong&gt;.py? - Stack Overflow&quot;&gt;python - What is &lt;strong&gt;main&lt;/strong&gt;.py? - Stack Overflow&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;ただ、&lt;code&gt;__init.py__&lt;/code&gt;は名前空間パッケージではなくていいようだし、よりモダンな方法に寄せたいので再検討するかな。単に今はわたしの知識がそこまで及んでない😭Pythonの言語仕様もちゃんと勉強したいのう。&lt;/p&gt;
&lt;p&gt;いろいろ足りない点があるが、それらは今後改善できれば良いかな。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;moduleの名前をいろいろ変えないといけないのが面倒なので、なんか改善ができれば良。&lt;/li&gt;&lt;li&gt;テストがないので足したい。&lt;/li&gt;&lt;li&gt;なんかバッジ足したい。ビルドとか...&lt;/li&gt;&lt;li&gt;mypyで&lt;/li&gt;&lt;/ul&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;まとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Python3たのしい。&lt;/p&gt;
&lt;p&gt;せっかくテンプレを作ったので、なんかゴミスクリプトでも良いのでちまちま書いていきたい所存🤔&lt;/p&gt;
&lt;p&gt;mypyについてもメモためていこ。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 11 May 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-04-29-bias-amp-2issue.html</guid><link>https://krymtkts.github.io/posts/2019-04-29-bias-amp-2issue.html</link><title>BIAS Amp 2で保存したアンプが消える問題</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;小ネタ。&lt;/p&gt;
&lt;p&gt;個人的に、2019年からPositive Grid社のBIAS Amp miniを導入した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.positivegrid.com/bias-mini-guitar/&quot; title=&quot;BIAS MINI Guitar - Positive Grid&quot;&gt;BIAS MINI Guitar - Positive Grid&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;平たく言うと、ギターアンプの部品をいじくり回すことでサウンドメイクする、というアイデアのデジタルアンプ。そのサウンドメイクの幅の広さ、自分好みのサウンドを手探りする面白さから、とても気に入っている。&lt;/p&gt;
&lt;p&gt;ただちょっと、バグが多いように思う。現時点で2つのバグらしい挙動を見つけている。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;1-Line-OUT-&quot; href=&quot;#1-Line-OUT-&quot;&gt;1.Line OUTが出力されない問題&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;見出しの通りである。出る場合と出ない場合があるのか、パターンを絞り出せていない。&lt;/p&gt;
&lt;p&gt;Line OUTはスタジオで試したときに気づいたので、まだすべての状況において出力がないのかは調べ尽くしていない。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;2-&quot; href=&quot;#2-&quot;&gt;2.保存したアンプが消える問題&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;購入したBIAS Amp miniには、同社のモデリングソフトウェアBIAS Amp 2が付属し、それで作ったアンプモデルをBIAS Amp miniに書き込むことができる。&lt;/p&gt;
&lt;p&gt;今確認している範囲では、以下のパターンで書き込んだアンプが、消失する時がある。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;BIAS Amp 2でキャプチャしたアンプ(AMP MATCH)をTone Cloudで入手する&lt;/li&gt;&lt;li&gt;入手したアンプのパラメータを変える&lt;/li&gt;&lt;li&gt;BIAS Amp miniをdesconnect後にスキンを変更する&lt;/li&gt;&lt;li&gt;再度BIAS Amp miniを接続し、変更したアンプを書き込む&lt;/li&gt;&lt;li&gt;電源OFFから数時間後に消失&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;ただ、このパターンで2回消えたのだが、3回目の再現ができていないので別の変数が関与してそう🤔ややこしい。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;まとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;いずれも割とまじで困る系の障害なので、ちゃんと条件を調べた上でサポートに問い合わせしたいところだけど、まだ全然出来てない状態...&lt;/p&gt;
&lt;p&gt;2の保存したアンプが消える問題は一応着手中。ライブ本番とかにモデルが消えてたらほんま笑い事じゃないからな...&lt;/p&gt;
&lt;p&gt;しょうもないネタを書き記すことが増えてきたので、次回は仕事で経験を得た、2019年のイケてそうなPython開発環境構築について書きたい所存🤔&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Mon, 29 Apr 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-04-20-disable-touch-screen.html</guid><link>https://krymtkts.github.io/posts/2019-04-20-disable-touch-screen.html</link><title>Windows10でタッチスクリーンを無効化する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;小ネタ。&lt;/p&gt;
&lt;p&gt;自機は、Razer Blade Stealth 2017のタッチスクリーン対応のやつだ。&lt;/p&gt;
&lt;p&gt;ディスプレイを閉じた状態から再度開いたときに、たま～に謎に画面が連続タップされまくって制御不能になるポルターガイスト現象(偽)が起こることがあった。&lt;/p&gt;
&lt;p&gt;それ以来タッチスクリーンの無効化をしているんやが、これがWindowsの大規模アップデートがあると設定が無効になって、都度再設定が必要になってる感じ🤔&lt;/p&gt;
&lt;p&gt;最近ver1803が降りてきたことで再度必要になったので覚書。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;手順&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://support.microsoft.com/ja-jp/help/4028019/windows-enable-and-disable-your-touchscreen-in-windows-10&quot; title=&quot;Windows 10 でタッチスクリーンを有効/無効にする&quot;&gt;Windows 10 でタッチスクリーンを有効/無効にする&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;デバイスマネージャを開く&lt;/li&gt;&lt;li&gt;HID準拠タッチスクリーンのデバイスを無効化する&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;THE END&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sat, 20 Apr 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-04-14-add-a-badge.html</guid><link>https://krymtkts.github.io/posts/2019-04-14-add-a-badge.html</link><title>プロジェクトにバッジを貼ろう</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/MavenAutoCompletion/0.1&quot; title=&quot;先日PowerShell Galleryにモジュールを公開した&quot;&gt;先日PowerShell Galleryにモジュールを公開した&lt;/a&gt;ついでに、プロジェクトのGitHubにバッジを貼ってみた。&lt;/p&gt;
&lt;p&gt;のでその覚書。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;バッジを貼ろう&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;なんかいろいろサービスがあるようだけど、わたしは&lt;a href=&quot;https://shields.io/&quot; title=&quot;Shields.io: Quality metadata badges for open source projects&quot;&gt;Shields.io: Quality metadata badges for open source projects&lt;/a&gt;にしてみた。&lt;/p&gt;
&lt;p&gt;いろんなバッジが提供されてるみたいやし、利用するためのハードルが低い(とにかく楽な)のが良い。&lt;/p&gt;
&lt;p&gt;PowerShell GalleryのDownload数を表示するバッチがあったので、それを利用してみた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://shields.io/category/downloads&quot; title=&quot;Shields.io: Quality metadata badges for open source projects&quot;&gt;Shields.io: Quality metadata badges for open source projects&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;利用は簡単でURLを貼るだけ。なんかよそのOSSとか見ててたらもっと簡単な方法がありそうだが、普通のMarkdownで書いた。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/MavenAutoCompletion/blob/master/README.md&quot; title=&quot;MavenAutoCompletion/README.md at master · krymtkts/MavenAutoCompletion&quot;&gt;MavenAutoCompletion/README.md at master · krymtkts/MavenAutoCompletion&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;[&lt;span class=&quot;hljs-string&quot;&gt;![PowerShell Gallery&lt;/span&gt;](&lt;span class=&quot;hljs-link&quot;&gt;https://img.shields.io/powershellgallery/dt/MavenAutoCompletion.svg?style=flat-square&lt;/span&gt;)](&lt;span class=&quot;hljs-link&quot;&gt;https://www.powershellgallery.com/packages/MavenAutoCompletion&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コレがこうなる↓&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2019-04-14-badge/badge.png&quot; title=&quot;バッジ&quot; alt=&quot;バッジ&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;いいね～😚&lt;/p&gt;
&lt;p&gt;つかDLすっくねえ！！！&lt;/p&gt;
&lt;p&gt;まあ自分のDLは、家、家リトライ、職場の3回だけで、残りの7回は世界のどこかで使われてるということがわかった。
ので良しとしよう🤔&lt;/p&gt;
&lt;p&gt;こうなるともっとバッジをペタペタ貼りたくなりますな～。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 14 Apr 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-04-07-lint-my-statement.html</guid><link>https://krymtkts.github.io/posts/2019-04-07-lint-my-statement.html</link><title>下手な文章を Lint する</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;転職してから 2 ヶ月の間、海外労働者の同僚から、日本語のドキュメントも英語のドキュメントもレビューコメントをいただいていてつらい。&lt;/p&gt;
&lt;p&gt;英語だけならまだしろ、わしゃ日本語もろくに扱えん日本人なんかと思うと涙ちょちょぎれる次第であります。&lt;/p&gt;
&lt;p&gt;なので自分の文章に Lint をかけようと思った。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;textlint&quot; href=&quot;#textlint&quot;&gt;textlint&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;いつだったか文章の Linter についてググってたら、以下のようなものを見つけた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/textlint/textlint&quot; title=&quot;GitHub - textlint/textlint&quot;&gt;GitHub - textlint/textlint&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://qiita.com/azu/items/2c565a38df5ed4c9f4e1&quot; title=&quot;Qiita - VS Code で textlint を使って文章をチェックする&quot;&gt;Qiita - VS Code で textlint を使って文章をチェックする&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/textlint-ja/textlint-rule-preset-ja-technical-writing&quot; title=&quot;textlint-ja/textlint-rule-preset-ja-technical-writing: 技術文書向けの textlint ルールプリセット&quot;&gt;textlint-ja/textlint-rule-preset-ja-technical-writing: 技術文書向けの textlint ルールプリセット&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;...すげえな！近い内に使えるようにしよう。と思ってから数ヶ月後、実務でまともな文章を書く能力が必要になるとわ...😭
というか vscode-textlint ってホイル焼きで有名な方の作品なのですね。敬意を払うべきプロダクトだ。&lt;/p&gt;
&lt;p&gt;以下にわたしのセットアップ手順を記す(実行は PowerShell だよ)。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;VSCode で vscode-textlin を入れる&lt;/li&gt;&lt;li&gt;&lt;code&gt;npm i -g textlint textlint-rule-preset-ja-technical-writing&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;cd ~&lt;/code&gt;で&lt;code&gt;textlint --init&lt;/code&gt;してルールを書き込み&lt;/li&gt;&lt;li&gt;VSCode では設定ファイルを絶対パスで利用するからどうしたものか...(複数端末で Sync してる関係で)&lt;ol&gt;
&lt;li&gt;&lt;code&gt;~/,textlint&lt;/code&gt;にしたらユーザ名とか考えなくていいから、なんかいい 😁&lt;/li&gt;&lt;/ol&gt;
&lt;/li&gt;&lt;li&gt;ついかパッケージ &lt;code&gt;npm i -g textlint-rule-date-weekday-mismatch textlint-rule-terminology textlint-rule-ginger&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;これで簡単な typo は減らせるんじゃないかな。&lt;/p&gt;
&lt;p&gt;お気に入りのルールは&lt;code&gt;textlint-rule-date-weekday-mismatch&lt;/code&gt;。これからのオレが曜日を間違うことはないぜええええ？(フラグ&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 07 Apr 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-04-02-pubslish-first-module-to-powershell-gallery.html</guid><link>https://krymtkts.github.io/posts/2019-04-02-pubslish-first-module-to-powershell-gallery.html</link><title>はじめてのPowerShell Galleryへの公開</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;先日、自前のモジュールをPowerShell Galleryに公開したので、その時のメモを記す。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.powershellgallery.com/packages/MavenAutoCompletion/0.1&quot; title=&quot;PowerShell Gallery | MavenAutoCompletion 0.1&quot;&gt;PowerShell Gallery | MavenAutoCompletion 0.1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PowerShell Galleryのアカウントを作るだとか、モジュールのAnalysisだとかはまた別で書こう。ここではモジュールの公開の部分だけ。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;TL-DR&quot; href=&quot;#TL-DR&quot;&gt;TL;DR&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;Poblish-Module&lt;/code&gt;は除外ファイル設定とかないから公開時には注意しましょう😭&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;モジュールの公開&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;以下の手順に従う。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/ja-jp/powershell/gallery/how-to/publishing-packages/publishing-a-package&quot; title=&quot;アイテムの作成と公開 | Microsoft Docs&quot;&gt;アイテムの作成と公開 | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;事前にチェックしろよな！！！と書いてるのでそれに従い以下のコマンドを実行する&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Publish-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.\MavenAutoCompletion&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NugetAPIKey&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;キーは見せられないよ&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-WhatIf&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Verbose&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;途中で最新のNuGet入れるかい？と聞かれるのでそれはYesで。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Publish-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.\MavenAutoCompletion&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NugetAPIKey&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;キーは見せられないよ&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-WhatIf&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Verbose&lt;/span&gt;&lt;br /&gt;VERBOSE: Acquiring providers &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; assembly: C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\PackageManagement\&lt;span class=&quot;hljs-number&quot;&gt;1.3&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;\coreclr\netstandard2.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\Microsoft.PackageManagement.NuGetProvider.dll&lt;br /&gt;VERBOSE: Acquiring providers &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; assembly: C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\PackageManagement\&lt;span class=&quot;hljs-number&quot;&gt;1.3&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;\coreclr\netstandard2.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\Microsoft.PackageManagement.MetaProvider.PowerShell.dll&lt;br /&gt;VERBOSE: Acquiring providers &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; assembly: C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\PackageManagement\&lt;span class=&quot;hljs-number&quot;&gt;1.3&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;\coreclr\netstandard2.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\Microsoft.PackageManagement.ArchiverProviders.dll&lt;br /&gt;VERBOSE: Acquiring providers &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; assembly: C:\Users\takatoshi\OneDrive\Documents\PowerShell\Modules\PackageManagement\&lt;span class=&quot;hljs-number&quot;&gt;1.3&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;\coreclr\netstandard2.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;\Microsoft.PackageManagement.CoreProviders.dll&lt;br /&gt;&lt;br /&gt;NuGet.exe is required to &lt;span class=&quot;hljs-keyword&quot;&gt;continue&lt;/span&gt;&lt;br /&gt;This version of PowerShellGet requires minimum version &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;4.1.0&amp;#x27;&lt;/span&gt; of NuGet.exe to publish an item to the&lt;br /&gt;Nu&lt;span class=&quot;hljs-built_in&quot;&gt;Get-based&lt;/span&gt; repositories. NuGet.exe must be available &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;C:\ProgramData\Microsoft\Windows\PowerShell\PowerShellGet\&amp;#x27;&lt;/span&gt; or&lt;br /&gt;&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;C:\Users\takatoshi\AppData\Local\Microsoft\Windows\PowerShell\PowerShellGet\&amp;#x27;&lt;/span&gt;, or under one of the&lt;br /&gt;paths specified &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; PATH environment variable value. NuGet.exe can be downloaded from&lt;br /&gt;https://aka.ms/&lt;span class=&quot;hljs-built_in&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;get-nugetexe&lt;/span&gt;. &lt;span class=&quot;hljs-keyword&quot;&gt;For&lt;/span&gt; more information, see https://aka.ms/installing&lt;span class=&quot;hljs-literal&quot;&gt;-powershellget&lt;/span&gt; . &lt;span class=&quot;hljs-keyword&quot;&gt;Do&lt;/span&gt;&lt;br /&gt;you want PowerShellGet to install the latest version of NuGet.exe now?&lt;br /&gt;&lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;Y&lt;/span&gt;] &lt;span class=&quot;hljs-title&quot;&gt;Yes&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;N&lt;/span&gt;] &lt;span class=&quot;hljs-title&quot;&gt;No&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;hljs-function&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt;] &lt;span class=&quot;hljs-title&quot;&gt;Suspend&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;hljs-function&quot;&gt;[?] &lt;span class=&quot;hljs-title&quot;&gt;Help&lt;/span&gt;&lt;/span&gt; (default is &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Y&amp;quot;&lt;/span&gt;): y&lt;br /&gt;VERBOSE: Installing NuGet.exe.&lt;br /&gt;VERBOSE: GET https://aka.ms/&lt;span class=&quot;hljs-built_in&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;get-nugetexe&lt;/span&gt; with &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-byte&lt;/span&gt; payload&lt;br /&gt;VERBOSE: received &lt;span class=&quot;hljs-number&quot;&gt;5690456&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-byte&lt;/span&gt; response of content &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; application/x&lt;span class=&quot;hljs-literal&quot;&gt;-msdownload&lt;/span&gt;&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Publish Location:&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/package/&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Module &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt; was found &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;C:\Users\takatoshi\dev\powershell\MavenAutoCompletion&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PowerShellGet&amp;#x27;&lt;/span&gt; for searching packages.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the specified source names : &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Getting the provider object &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the PackageManagement Provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: The specified Location is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/items/psscript/&amp;#x27;&lt;/span&gt; and PackageManagementProvider is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Searching repository &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/items/psscript/FindPackagesById()?id=&amp;#x27;&lt;/span&gt;MavenAutoCompletion&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Total package yield:&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the specified package &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PowerShellGet&amp;#x27;&lt;/span&gt; for searching packages.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the specified source names : &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Getting the provider object &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the PackageManagement Provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: The specified Location is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt; and PackageManagementProvider is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Searching repository &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/FindPackagesById()?id=&amp;#x27;&lt;/span&gt;MavenAutoCompletion&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Total package yield:&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the specified package &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt;.&lt;br /&gt;What &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;: Performing the operation &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Publish-Module&amp;quot;&lt;/span&gt; on target &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Version &amp;#x27;0.0.1&amp;#x27; of module &amp;#x27;MavenAutoCompletion&amp;#x27;&amp;quot;&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;それらしいエラーも警告も出ないので、実行に移す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Publish-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.\MavenAutoCompletion&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NugetAPIKey&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;キーは見せられないよ&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Verbose&lt;/span&gt;&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Publish Location:&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/package/&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Module &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt; was found &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;C:\Users\takatoshi\dev\powershell\MavenAutoCompletion&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PowerShellGet&amp;#x27;&lt;/span&gt; for searching packages.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the specified source names : &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Getting the provider object &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the PackageManagement Provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: The specified Location is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/items/psscript/&amp;#x27;&lt;/span&gt; and PackageManagementProvider is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Searching repository &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/items/psscript/FindPackagesById()?id=&amp;#x27;&lt;/span&gt;MavenAutoCompletion&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Total package yield:&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the specified package &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PowerShellGet&amp;#x27;&lt;/span&gt; for searching packages.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the specified source names : &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Getting the provider object &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the PackageManagement Provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: The specified Location is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt; and PackageManagementProvider is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Searching repository &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/FindPackagesById()?id=&amp;#x27;&lt;/span&gt;MavenAutoCompletion&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Total package yield:&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the specified package &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Performing the operation &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Publish-Module&amp;quot;&lt;/span&gt; on target &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Version &amp;#x27;0.0.1&amp;#x27; of module &amp;#x27;MavenAutoCompletion&amp;#x27;&amp;quot;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Pushing MavenAutoCompletion.&lt;span class=&quot;hljs-number&quot;&gt;0.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;.nupkg to &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/package/&amp;#x27;&lt;/span&gt;...&lt;br /&gt;  PUT https://www.powershellgallery.com/api/v2/package/&lt;br /&gt;�x��: &amp;lt;licenseUrl&amp;gt; element will be deprecated, please consider switching to specifying the license &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;&lt;br /&gt;the package. Learn more: https://aka.ms/deprecateLicenseUrl.&lt;br /&gt;  Created https://www.powershellgallery.com/api/v2/package/ &lt;span class=&quot;hljs-number&quot;&gt;3489&lt;/span&gt;ms&lt;br /&gt;Your package was pushed.&lt;br /&gt;&lt;br /&gt;VERBOSE: Successfully published module &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt; to the module publish location &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/package/&amp;#x27;&lt;/span&gt;. Please allow few minutes &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt; to show up &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; the search results.
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;�x��: &lt;licenseUrl&gt; element will be deprecated, please consider switching to specifying the license in
the package. Learn more: &lt;a href=&quot;https://aka.ms/deprecateLicenseUrl&quot; title=&quot;undefined&quot;&gt;https://aka.ms/deprecateLicenseUrl&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;う、モジュールのマニフェストでdeprecatedな属性があるが...いけたっぽい。この文字化けはemojiかな(Win10 1809ではterminalでemoji化けがあるのは既知)&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;いけて...ない！&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;困ったことにイケてなかった...gitのオブジェクトとかそういうのまで全部publishedなかんじでまじで笑えねえ...とりあえずPowerShell Gallery上でリスト表示しないリクエストを出しておいたが笑えねえ😭&lt;/p&gt;
&lt;p&gt;どうもこれはPowerShell Getの既知の問題？みたい...事前調査が足りてなかったぜえ...😭&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PowerShellGet/issues/191&quot; title=&quot;Ignore files when using &lt;code&gt;Publish-Module&lt;/code&gt; · Issue #191 · PowerShell/PowerShellGet&quot;&gt;Ignore files when using &lt;code&gt;Publish-Module&lt;/code&gt; · Issue #191 · PowerShell/PowerShellGet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;現状できることとしては、別にモジュールと同名のフォルダを作って、その中にpublishしたいファイルをコピーし、&lt;code&gt;Publish-Module&lt;/code&gt;を実行するしかないのではないかなと思う🤔&lt;/p&gt;
&lt;p&gt;この際なので↑の取りなしでvr0.1として公開することにする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Publish-Module&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;.\MavenAutoCompletion&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-NugetAPIKey&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;キーは見せられないよ&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Verbose&lt;/span&gt;&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Publish Location:&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/package/&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Module &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt; was found &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;C:\Users\takatoshi\dev\powershell\MavenAutoCompletion\publish\MavenAutoCompletion&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PowerShellGet&amp;#x27;&lt;/span&gt; for searching packages.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the specified source names : &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Getting the provider object &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the PackageManagement Provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: The specified Location is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/items/psscript/&amp;#x27;&lt;/span&gt; and PackageManagementProvider is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Searching repository &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/items/psscript/FindPackagesById()?id=&amp;#x27;&lt;/span&gt;MavenAutoCompletion&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Total package yield:&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the specified package &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Repository details, Name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;, Location = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt;; IsTrusted = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;; IsRegistered = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;True&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PowerShellGet&amp;#x27;&lt;/span&gt; for searching packages.&lt;br /&gt;VERBOSE: &lt;span class=&quot;hljs-keyword&quot;&gt;Using&lt;/span&gt; the specified source names : &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;PSGallery&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Getting the provider object &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the PackageManagement Provider &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: The specified Location is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/&amp;#x27;&lt;/span&gt; and PackageManagementProvider is &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;NuGet&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Searching repository &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/FindPackagesById()?id=&amp;#x27;&lt;/span&gt;MavenAutoCompletion&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Total package yield:&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;1&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; the specified package &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Performing the operation &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Publish-Module&amp;quot;&lt;/span&gt; on target &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Version &amp;#x27;0.1&amp;#x27; of module &amp;#x27;MavenAutoCompletion&amp;#x27;&amp;quot;&lt;/span&gt;.&lt;br /&gt;VERBOSE: Pushing MavenAutoCompletion.&lt;span class=&quot;hljs-number&quot;&gt;0.1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;.nupkg to &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/package/&amp;#x27;&lt;/span&gt;...&lt;br /&gt;  PUT https://www.powershellgallery.com/api/v2/package/&lt;br /&gt;�x��: &amp;lt;licenseUrl&amp;gt; element will be deprecated, please consider switching to specifying the license &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;&lt;br /&gt;the package. Learn more: https://aka.ms/deprecateLicenseUrl.&lt;br /&gt;  Created https://www.powershellgallery.com/api/v2/package/ &lt;span class=&quot;hljs-number&quot;&gt;4558&lt;/span&gt;ms&lt;br /&gt;Your package was pushed.&lt;br /&gt;&lt;br /&gt;VERBOSE: Successfully published module &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt; to the module publish location &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;https://www.powershellgallery.com/api/v2/package/&amp;#x27;&lt;/span&gt;. Please allow few minutes &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;MavenAutoCompletion&amp;#x27;&lt;/span&gt; to show up &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; the search results.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これによって一応無事にPowerShell Getでの公開はできたし、一旦コレでええか😅&lt;/p&gt;
&lt;p&gt;今度非推奨になってる&lt;code&gt;&amp;lt;licenseUrl&amp;gt;&lt;/code&gt;を変えなあかんな。&lt;/p&gt;
&lt;p&gt;ファイルコピって公開するためのスクリプトを起こしたので、次回はそれでやろうと思う。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Tue, 02 Apr 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-03-31-win-openssh-is-gone.html</guid><link>https://krymtkts.github.io/posts/2019-03-31-win-openssh-is-gone.html</link><title>Windows10の更新でOpenSSHが逝った</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;今更ながら、Raser Blade Stealth 2017にもWindows10 ver1809の更新が来てたようだった。&lt;/p&gt;
&lt;p&gt;何の気なしに更新してみたところ、更新自体はすぐに終わってあっさりいったなと思っていたのだが、terminalを立ち上げると...&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;TL-DR&quot; href=&quot;#TL-DR&quot;&gt;TL;DR&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Windows10 ver1809のOpenSSHは既知のバグがあるのでOpenSSH Portableを入れ直そう。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-SSH-Agent-&quot; href=&quot;#-SSH-Agent-&quot;&gt;まずSSH Agentのサービスが無効になってた&lt;/a&gt;&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Process&lt;/span&gt; : Cannot find a &lt;span class=&quot;hljs-keyword&quot;&gt;process&lt;/span&gt; with the name &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ssh-agent&amp;quot;&lt;/span&gt;. Verify the &lt;span class=&quot;hljs-keyword&quot;&gt;process&lt;/span&gt; name and call the cmdlet again.&lt;br /&gt;At C:\Users\takatoshi\OneDrive\Documents\PowerShell\Microsoft.PowerShell_profile.ps1:&lt;span class=&quot;hljs-number&quot;&gt;40&lt;/span&gt; char:&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;&lt;br /&gt;+ &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (! (&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Process&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ssh-agent&amp;#x27;&lt;/span&gt;)) {&lt;br /&gt;+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;+ CategoryInfo          : ObjectNotFound: (ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;:String) [&lt;span class=&quot;hljs-built_in&quot;&gt;Get-Process&lt;/span&gt;], ProcessCommandException&lt;br /&gt;+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;PowerShellのprofileで&lt;code&gt;ssh-agent&lt;/code&gt;のプロセスの存在を確認するようにしてたのだけど、Windowsの更新でサービスの自動実行が無効になってたようなのでこのエラーが...とりあえず今回は手動で自動実行するように変えて終わった。&lt;/p&gt;
&lt;p&gt;あとどういうわけかわからないが、PC起動時のサービスの立ち上がりがめちゃくちゃ遅くなった気がする(体感)。PC起動後にすぐterminalを立ち上げると同じエラーがまだ出るから。根治させるにはprofileをいじらないといけないかな🤔&lt;/p&gt;
&lt;p&gt;後述の問題に比べれば、こちらは楽しいアクシデント程度のものだ。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;Win10-OpenSSH-&quot; href=&quot;#Win10-OpenSSH-&quot;&gt;Win10備え付けのOpenSSHに既知のバグが有るとか云々&lt;/a&gt;&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; git remote show origin&lt;br /&gt;warning: agent returned different signature &lt;span class=&quot;hljs-built_in&quot;&gt;type&lt;/span&gt; ssh&lt;span class=&quot;hljs-literal&quot;&gt;-rsa&lt;/span&gt; (expected rsa&lt;span class=&quot;hljs-literal&quot;&gt;-sha2-512&lt;/span&gt;)&lt;br /&gt;...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;↑この警告が常時出るようになった。むかつく💢&lt;/p&gt;
&lt;p&gt;直さな...😭と思ってググってみると...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/Win32-OpenSSH/issues/1263&quot; title=&quot;ssh-agent: agent returned different signature type · Issue #1263 · PowerShell/Win32-OpenSSH&quot;&gt;ssh-agent: agent returned different signature type · Issue #1263 · PowerShell/Win32-OpenSSH&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これの様子🤔&lt;/p&gt;
&lt;p&gt;更に調べると、これマジIssueやなと思わざるを得ない... -&amp;gt; &lt;a href=&quot;https://github.com/PowerShell/openssh-portable/pull/366&quot; title=&quot;Fixes to ssh-agent issues by manojampalam · Pull Request #366 · PowerShell/openssh-portable&quot;&gt;Fixes to ssh-agent issues by manojampalam · Pull Request #366 · PowerShell/openssh-portable&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;つまりはバグが直ったOpenSSH-Portbale入れないと解決しないってんでFAかな...キレそう❤&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.frankfu.com.au/2019/03/21/moving-from-windows-1809s-openssh-to-openssh-portable/&quot; title=&quot;Moving from Windows 1809&amp;#39;s OpenSSH to OpenSSH Portable&quot;&gt;Moving from Windows 1809&amp;#39;s OpenSSH to OpenSSH Portable&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;幸いにも同じ障害を解消したブログがあったので助かる🙏&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;処置する&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;&lt;a href=&quot;https://blog.frankfu.com.au/2019/03/21/moving-from-windows-1809s-openssh-to-openssh-portable/&quot; title=&quot;Moving from Windows 1809&amp;#39;s OpenSSH to OpenSSH Portable&quot;&gt;Moving from Windows 1809&amp;#39;s OpenSSH to OpenSSH Portable&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この記事にそのまま従えばいける。&lt;/p&gt;
&lt;p&gt;Windowsに関わる操作はPowerShell Coreではできないので、PowerShell CoreとWindowsPowerShellを使い分けた(WindowsPowerShellで全部やればいいものを...😅)&lt;/p&gt;
&lt;p&gt;Coreでできる範囲から始める。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Service&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt; | &lt;span class=&quot;hljs-built_in&quot;&gt;Stop-Service&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; sc.exe delete ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;SC&lt;/span&gt;] DeleteService SUCCESS
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;WindowsPowerShellでしかできない範囲&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Remove-WindowsCapability&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Online&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;OpenSSH.Client~~~~0.0.1.0&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Path          :&lt;br /&gt;Online        : True&lt;br /&gt;RestartNeeded : False&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;Remove-WindowsCapability&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Online&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;OpenSSH.Server~~~~0.0.1.0&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Path          :&lt;br /&gt;Online        : True&lt;br /&gt;RestartNeeded : False
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Coreで続きをやる&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; choco install openssh &lt;span class=&quot;hljs-literal&quot;&gt;--package-parameters&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/SSHAgentFeature&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Chocolatey v0.10.13&lt;br /&gt;2 validations performed. 1 success(es), 1 warning(s), and 0 error(s).&lt;br /&gt;&lt;br /&gt;Validation Warnings:&lt;br /&gt; - A pending system reboot request has been detected, however, this is&lt;br /&gt;   being ignored due to the current Chocolatey configuration.  If you&lt;br /&gt;   want to halt when this occurs, then either set the global feature&lt;br /&gt;   using:&lt;br /&gt;     choco feature enable -name=exitOnRebootDetected&lt;br /&gt;   or pass the option --exit-when-reboot-detected.&lt;br /&gt;&lt;br /&gt;Installing the following packages:&lt;br /&gt;openssh&lt;br /&gt;By installing you accept licenses for the packages.&lt;br /&gt;Progress: Downloading openssh 7.9.0.1... 100%&lt;br /&gt;&lt;br /&gt;openssh v7.9.0.1 [Approved]&lt;br /&gt;openssh package files install completed. Performing other installation steps.&lt;br /&gt;The package openssh wants to run &amp;#x27;chocolateyinstall.ps1&amp;#x27;.&lt;br /&gt;Note: If you don&amp;#x27;t run this script, the installation will fail.&lt;br /&gt;Note: To confirm automatically next time, use &amp;#x27;-y&amp;#x27; or consider:&lt;br /&gt;choco feature enable -n allowGlobalConfirmation&lt;br /&gt;Do you want to run the script?([Y]es/[N]o/[P]rint): y&lt;br /&gt;&lt;br /&gt;Running on: Windows 10 Home, (Core)&lt;br /&gt;Windows Version: 10.0.17763&lt;br /&gt;&lt;br /&gt;************************************************************************************&lt;br /&gt;************************************************************************************&lt;br /&gt;This package is a Universal Installer and can ALSO install Win32-OpenSSH on&lt;br /&gt;Nano, Server Core, Docker Containers and more WITHOUT using Chocolatey.&lt;br /&gt;&lt;br /&gt;See the following for more details:&lt;br /&gt;https://github.com/DarwinJS/ChocoPackages/blob/master/openssh/readme.md&lt;br /&gt;************************************************************************************&lt;br /&gt;************************************************************************************&lt;br /&gt;&lt;br /&gt;/SSHAgentFeature was used, including SSH Agent Service.&lt;br /&gt;Extracting C:\ProgramData\chocolatey\lib\openssh\tools\OpenSSH-Win64.zip to C:\Users\takatoshi\AppData\Local\Temp\chocolatey\OpenSSHTemp...&lt;br /&gt;C:\Users\takatoshi\AppData\Local\Temp\chocolatey\OpenSSHTemp&lt;br /&gt;Source files are internal to the package, checksums are not required nor checked.&lt;br /&gt;C:\Program Files\OpenSSH-Win64&lt;br /&gt;C:\Program Files\OpenSSH-Win64\FixHostFilePermissions.ps1&lt;br /&gt;C:\Program Files\OpenSSH-Win64\FixUserFilePermissions.ps1&lt;br /&gt;C:\Program Files\OpenSSH-Win64\install-sshd.ps1&lt;br /&gt;C:\Program Files\OpenSSH-Win64\libcrypto.dll&lt;br /&gt;C:\Program Files\OpenSSH-Win64\openssh-events.man&lt;br /&gt;C:\Program Files\OpenSSH-Win64\OpenSSHUtils.psd1&lt;br /&gt;C:\Program Files\OpenSSH-Win64\OpenSSHUtils.psm1&lt;br /&gt;C:\Program Files\OpenSSH-Win64\scp.exe&lt;br /&gt;C:\Program Files\OpenSSH-Win64\sftp-server.exe&lt;br /&gt;C:\Program Files\OpenSSH-Win64\sftp.exe&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh-add.exe&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh-agent.exe&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh-keygen.exe&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh-keyscan.exe&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh-shellhost.exe&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh.exe&lt;br /&gt;C:\Program Files\OpenSSH-Win64\sshd.exe&lt;br /&gt;C:\Program Files\OpenSSH-Win64\sshd_config_default&lt;br /&gt;C:\Program Files\OpenSSH-Win64\uninstall-sshd.ps1&lt;br /&gt;C:\Program Files\OpenSSH-Win64\Set-SSHDefaultShell.ps1&lt;br /&gt;PATH environment variable does not have C:\Program Files\OpenSSH-Win64 in it. Adding...&lt;br /&gt;Updating machine environment variable TERM from &amp;quot;&amp;quot; to &amp;quot;&amp;quot;&lt;br /&gt;[SC] SetServiceObjectSecurity SUCCESS&lt;br /&gt;Starting SSH-Agent...&lt;br /&gt;&lt;br /&gt;NEW VERSIONS OF SSH EXES:&lt;br /&gt;&lt;br /&gt;FileName                                         FileVersion&lt;br /&gt;--------                                         -----------&lt;br /&gt;C:\Program Files\OpenSSH-Win64\scp.exe           7.9.0.0&lt;br /&gt;C:\Program Files\OpenSSH-Win64\sftp-server.exe   7.9.0.0&lt;br /&gt;C:\Program Files\OpenSSH-Win64\sftp.exe          7.9.0.0&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh-add.exe       7.9.0.0&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh-agent.exe     7.9.0.0&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh-keygen.exe    7.9.0.0&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh-keyscan.exe   7.9.0.0&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh-shellhost.exe 7.9.0.0&lt;br /&gt;C:\Program Files\OpenSSH-Win64\ssh.exe           7.9.0.0&lt;br /&gt;C:\Program Files\OpenSSH-Win64\sshd.exe          7.9.0.0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;WARNING: You must start a new prompt, or use the command &amp;#x27;refreshenv&amp;#x27; (provided by your chocolatey install) to re-read the environment for the tools to be available in this shell session.&lt;br /&gt;Environment Vars (like PATH) have changed. Close/reopen your shell to&lt;br /&gt; see the changes (or in powershell/cmd.exe just type `refreshenv`).&lt;br /&gt; The install of openssh was successful.&lt;br /&gt;  Software installed to &amp;#x27;C:\Users\takatoshi\AppData\Local\Temp\chocolatey\OpenSSHTemp&amp;#x27;&lt;br /&gt;&lt;br /&gt;Chocolatey installed 1/1 packages.&lt;br /&gt; See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;Get-Service&lt;/span&gt; ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Status   Name               DisplayName&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;------&lt;/span&gt;   &lt;span class=&quot;hljs-literal&quot;&gt;----&lt;/span&gt;               &lt;span class=&quot;hljs-literal&quot;&gt;-----------&lt;/span&gt;&lt;br /&gt;Running  ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;          ssh&lt;span class=&quot;hljs-literal&quot;&gt;-agent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; git config &lt;span class=&quot;hljs-literal&quot;&gt;--global&lt;/span&gt; core.sshCommand &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;#x27;C:\Program Files\OpenSSH-Win64\ssh.exe&amp;#x27;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;環境変数PATHを反映させてから、terminalでwariningが消えたのを確認&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;振り返り&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Windowsのでかい更新の際はちゃんと注意して取り組まなあかんな🤔(めんどい)&lt;/p&gt;
&lt;p&gt;あとこれまた既知の別件なのだけど、ver1809だとterminalのemojiの表示が中点とかに化けるので、これもなんとかしたいわ...&lt;/p&gt;
&lt;p&gt;Cmder/ConEmuじゃなくてWindows自体の問題みたい。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 31 Mar 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-03-24-coverage-of-qunt-puppeteer.html</guid><link>https://krymtkts.github.io/posts/2019-03-24-coverage-of-qunt-puppeteer.html</link><title>QUnit で CI したい その 2</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2019-03-21_want-to-run-qunit-in-cli.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;、QUnit のユニットテストを puppeteer で CLI 実行できるようにした&lt;/p&gt;
&lt;p&gt;今回は code coverage を計測できるようにする。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;前回のおさらい&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;puppeteer で JavaScript のカバレッジを計測することができる(&lt;a href=&quot;https://developers.google.com/web/updates/2017/04/devtools-release-notes&quot; title=&quot;What&amp;#39;s New In DevTools (Chrome 59)  |  Web  |  Google Developers&quot;&gt;What&amp;#39;s New In DevTools (Chrome 59)  |  Web  |  Google Developers&lt;/a&gt;)のだが、現状利用している&lt;a href=&quot;https://www.npmjs.com/package/node-qunit-puppeteer&quot; title=&quot;node-qunit-puppeteer&quot;&gt;node-qunit-puppeteer&lt;/a&gt;だと、puppeteer の部分をモジュール外部から触れないので利用できなくて困った、ということろまで書いた。&lt;/p&gt;
&lt;p&gt;理想ではユニットテストの実施と同時にカバレッジを計測したいところなのだが、一旦は簡単のために別々に、つまりユニットテストの実行後さらにカバレッジ取得のためにユニットテスを再実行する、というかたちで楽しようと考えた。ユニットテストの実行が軽いうちは 2 度実行したところで大した負荷にならないというのもあり。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;やったこと&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;これ ↓&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/istanbuljs/puppeteer-to-istanbul&quot; title=&quot;istanbuljs/puppeteer-to-istanbul: given coverage information output by puppeteer&amp;#39;s API output a format consumable by Istanbul reports&quot;&gt;istanbuljs/puppeteer-to-istanbul: given coverage information output by puppeteer&amp;#39;s API output a format consumable by Istanbul reports&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;puppeteer で計測したカバレッジを istanbul(nyc)で利用できる形に書き出すモジュールを使う。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/qunit-trial/blob/master/test/run.js&quot; title=&quot;すでにある node-qunit-puppeteer のテストランナー&quot;&gt;すでにある node-qunit-puppeteer のテストランナー&lt;/a&gt;と一緒には使えないので、カバレッジ計測のためのスクリプトも新たに書く(無駄)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; pti = &lt;span class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;puppeteer-to-istanbul&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; puppeteer = &lt;span class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;puppeteer&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; path = &lt;span class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;path&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;(&lt;span class=&quot;hljs-title function_&quot;&gt;async&lt;/span&gt; () =&amp;gt; {&lt;br /&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; browser = &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; puppeteer.&lt;span class=&quot;hljs-title function_&quot;&gt;launch&lt;/span&gt;();&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; page = &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; browser.&lt;span class=&quot;hljs-title function_&quot;&gt;newPage&lt;/span&gt;();&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; page.&lt;span class=&quot;hljs-property&quot;&gt;coverage&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;startJSCoverage&lt;/span&gt;();&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; page.&lt;span class=&quot;hljs-title function_&quot;&gt;goto&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;`file://&lt;span class=&quot;hljs-subst&quot;&gt;${path.join(__dirname, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/index.html&amp;quot;&lt;/span&gt;)}&lt;/span&gt;`&lt;/span&gt;);&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; jsCoverage = &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; page.&lt;span class=&quot;hljs-property&quot;&gt;coverage&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;stopJSCoverage&lt;/span&gt;();&lt;br /&gt;&lt;br /&gt;    pti.&lt;span class=&quot;hljs-title function_&quot;&gt;write&lt;/span&gt;(jsCoverage);&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; browser.&lt;span class=&quot;hljs-title function_&quot;&gt;close&lt;/span&gt;();&lt;br /&gt;  } &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; (error) {&lt;br /&gt;    &lt;span class=&quot;hljs-variable language_&quot;&gt;console&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;error&lt;/span&gt;(error);&lt;br /&gt;  }&lt;br /&gt;})();
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これもほぼサンプルママで使えた。読み込ませるページのパスだけ工夫が必要ってだけ。&lt;/p&gt;
&lt;p&gt;あとはカバレッジ計測に成功したら nyc のレポート作成を実行するだけでおｋ。これを npm のタスクにする。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;node &lt;span class=&quot;hljs-built_in&quot;&gt;test&lt;/span&gt;/coverage.js &amp;amp;&amp;amp; nyc report --reporter=html
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これでページを開いたときに読み込まれる JS のカバレッジを計測できた。ただしこのままだと、QUnit やユニットテスト自体のカバレッジも含まれてしまうので、仕事の CI で使う場合なんかには特定のファイルのカバレッジだけを見るか、あるいは除外設定があればいいのだけど。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;まとめ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;また今回試した内容は以下の repo に反映してある&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/qunit-trial&quot; title=&quot;krymtkts/qunit-trial: sandbox to enhance legacy QUnit test.&quot;&gt;krymtkts/qunit-trial: sandbox to enhance legacy QUnit test.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2 回ユニットテストを実行していて無駄感があるので、node-qunit-puppeteer に手を入れることも検討していいかも 🤔&lt;/p&gt;
&lt;p&gt;続く&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 24 Mar 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-03-21-want-to-run-qunit-in-cli.html</guid><link>https://krymtkts.github.io/posts/2019-03-21-want-to-run-qunit-in-cli.html</link><title>QUnit で CI したい その 1</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;2 月に転職した。&lt;/p&gt;
&lt;p&gt;へーしゃでの初めての仕事はフロントエンド、と言ってもトラッキングに関わる部分である。&lt;/p&gt;
&lt;p&gt;生の ES5 で書かれてて&lt;a href=&quot;https://github.com/google/closure-compiler&quot; title=&quot;Google Closure Compiler&quot;&gt;Google Closure Compiler&lt;/a&gt;で minify されてるようなのだけど、困ったことにユニットテストがない様子？
どこそこのチームで作ってたことがあったらしいという情報は得たので、それを CI に組み込めたらいいかなと思っていた。&lt;/p&gt;
&lt;p&gt;蓋を開けてみると、2 年間ほどメンテされていない死んだユニットテストで、最新のコードベースに対するテストでなかった(テストコードと同ディレクトリにテスト対象のコードがコピられてて)🤔&lt;/p&gt;
&lt;p&gt;CI に組み込まれないテストは陳腐化すると云うが、まさかそれを身をもって実感することになろうとは思わなんだ。&lt;/p&gt;
&lt;p&gt;&lt;del&gt;仕方ないので&lt;/del&gt;既存の資産を活かすためにも、テスティングフレームワークなど既存のものを利用して少なくとも CI に組み込めるところまでは持っていこうと考えた。CI に組み込まれればビルド失敗の通知を恐れてみんなユニットテストを書くのをサボらなくなる。&lt;/p&gt;
&lt;p&gt;というわけで、許可を取り付けた上で仕事の合間を縫ってユニットテストの整備を行うことにした。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;現状把握と展望&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ユニットテストは&lt;a href=&quot;https://qunitjs.com/&quot; title=&quot;QUnit&quot;&gt;QUnit&lt;/a&gt;で書かれていて、モッキングフレームワークには&lt;a href=&quot;https://sinonjs.org/&quot; title=&quot;Sinon.JS&quot;&gt;Sinon.JS&lt;/a&gt;が使われていた。&lt;/p&gt;
&lt;p&gt;linter は&lt;a href=&quot;https://eslint.org/&quot; title=&quot;ESLint - Pluggable JavaScript linter&quot;&gt;ESLint - Pluggable JavaScript linter&lt;/a&gt;を用意してあるようなのだけどどうも長らく利用されてなかったようで、試しに実行すると 41 件の autofix 可能なエラーが...😅&lt;/p&gt;
&lt;p&gt;ブラウザで&lt;code&gt;index.html&lt;/code&gt;を開くことでテストが実行されるタイプのやつで、CLI での実行は用意されてなかった。
プロダクトコードが&lt;code&gt;window&lt;/code&gt;オブジェクトに依存してることもあって、QUnit のテストをヘッドレスブラウザで実行するのが良さげかな。&lt;/p&gt;
&lt;p&gt;ここにカバレッジ計測も追加して、最終的にはプルリクをトリガーにした自動テストが CI に組み込まれるのが良さげかなと思う。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;やったこと＆やらなかったこと&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;とりあえずカバレッジは置いといて今ある QUnit の CLI 実行を優先した。&lt;/p&gt;
&lt;p&gt;node でのカバレッジ計測に関しては知らないことが多かったので軽く下調べだけした。
istabul というやつが node 界隈で強かったみたいだが、こいつは 2 年ほどメンテされてなくて、後続の&lt;a href=&quot;https://www.npmjs.com/package/nyc&quot; title=&quot;nyc - npm&quot;&gt;nyc - npm&lt;/a&gt;と言うやつがみつかる 👀
puppeteer もそれ単体でカバレッジが測れるようす ↓&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.philkrie.me/2018/07/04/extracting-coverage.html&quot; title=&quot;Using Puppeteer to Extract Code Coverage Data from Chrome Dev Tools&quot;&gt;Using Puppeteer to Extract Code Coverage Data from Chrome Dev Tools&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/istanbuljs/puppeteer-to-istanbul&quot; title=&quot;istanbuljs/puppeteer-to-istanbul: given coverage information output by puppeteer&amp;#39;s API output a format consumable by Istanbul reports&quot;&gt;istanbuljs/puppeteer-to-istanbul: given coverage information output by puppeteer&amp;#39;s API output a format consumable by Istanbul reports&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;やったこと&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;まず元々ある QUnit もそのまま使えないとブラウザで見つつの開発の利便性も下がっちゃうので、そこは担保したかった。
(&lt;code&gt;window&lt;/code&gt;オブジェクトがないので CommonJS は死ぬ)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/qunit-puppeteer&quot; title=&quot;qunit-puppeteer - npm&quot;&gt;qunit-puppeteer - npm&lt;/a&gt;は簡単にテスト実行できて楽だったのだけど、テストの url を絶対パスで指定しないといけず＆自分で URL をこねくり回せなくて却下。&lt;/p&gt;
&lt;p&gt;なのでそのへん柔軟な&lt;a href=&quot;https://www.npmjs.com/package/node-qunit-puppeteer&quot; title=&quot;node-qunit-puppeteer - npm&quot;&gt;node-qunit-puppeteer - npm&lt;/a&gt;しか選択肢が残らなかったわけだ。&lt;/p&gt;
&lt;p&gt;とりま&lt;code&gt;eslint&lt;/code&gt;だけあるからソイツはそのままに、QUnit を headless browser 実行するための module だけ足す。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;npm install &lt;span class=&quot;hljs-literal&quot;&gt;--save-dev&lt;/span&gt; node&lt;span class=&quot;hljs-literal&quot;&gt;-qunit-puppeteer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;は以下のような感じにした&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;scripts&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;lint&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;eslint --fix ./&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;node test/run.js&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;lint&lt;/code&gt;はメンテされてなかった関係で 40 件くらいの error があるけど、最終的には実行できるようになる(ハズな)ので用意しておく。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;test/run.js&lt;/code&gt;は以下の通りで、&lt;a href=&quot;https://github.com/ameshkov/node-qunit-puppeteer&quot; title=&quot;ameshkov/node-qunit-puppeteer: A simple node module for running qunit tests with headless Chromium&quot;&gt;ameshkov/node-qunit-puppeteer: A simple node module for running qunit tests with headless Chromium&lt;/a&gt;の Example とほぼ同じで行ける便利さ。しびれる。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#! /usr/bin/env node&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// almost the same as the sample code :-p&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// https://github.com/ameshkov/node-qunit-puppeteer&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; path = &lt;span class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;path&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; { runQunitPuppeteer, printOutput } = &lt;span class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;node-qunit-puppeteer&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; qunitArgs = {&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;targetUrl&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;`file://&lt;span class=&quot;hljs-subst&quot;&gt;${path.join(__dirname, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/index.html&amp;quot;&lt;/span&gt;)}&lt;/span&gt;`&lt;/span&gt;,&lt;br /&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;redirectConsole&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;,&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;hljs-title function_&quot;&gt;runQunitPuppeteer&lt;/span&gt;(qunitArgs)&lt;br /&gt;  .&lt;span class=&quot;hljs-title function_&quot;&gt;then&lt;/span&gt;(&lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;result&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// Print the test result to the output&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-title function_&quot;&gt;printOutput&lt;/span&gt;(result, &lt;span class=&quot;hljs-variable language_&quot;&gt;console&lt;/span&gt;);&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (result.&lt;span class=&quot;hljs-property&quot;&gt;stats&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;failed&lt;/span&gt; &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {&lt;br /&gt;      &lt;span class=&quot;hljs-comment&quot;&gt;// Handle the failed test run&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;hljs-comment&quot;&gt;// currently notghing to do.&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;  })&lt;br /&gt;  .&lt;span class=&quot;hljs-title function_&quot;&gt;catch&lt;/span&gt;(&lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;ex&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-variable language_&quot;&gt;console&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;error&lt;/span&gt;(ex);&lt;br /&gt;  });
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;実行結果は以下のような感じで出る。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$&lt;/span&gt; npm run test&lt;br /&gt;&lt;br /&gt;&amp;gt; qunit@&lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; test C:\Users\takatoshi\dev\javascript\qunit&lt;br /&gt;&amp;gt; node test/run.js&lt;br /&gt;&lt;br /&gt;Module: hello module&lt;br /&gt;  hello test&lt;br /&gt;    Status: success&lt;br /&gt;    Passed assertions: &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; of &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;    Elapsed: &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;ms&lt;br /&gt;&lt;br /&gt;Test run result: success&lt;br /&gt;Total tests: &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;  Assertions: &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;  Passed assertions: &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;  Failed assertions: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;  Elapsed: &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;ms
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;と、ここまで書いた内容を会社のコードに組み込んだのだけど、会社で作ったものは外に出せないので模倣したゴミプロジェクトを作った ↓&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/qunit-trial&quot; title=&quot;krymtkts/qunit-trial: sandbox to enhance legacy QUnit test.&quot;&gt;krymtkts/qunit-trial: sandbox to enhance legacy QUnit test.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今後いじくり回すときの砂場としても使おうかな。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;あとやりたいこと&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;ユニットテストだけあってカバレッジ計測がないのはちょっとアレなので早々に追加したい所存 🤔&lt;/p&gt;
&lt;p&gt;そもそもユニットテスト書くにしてもどの経路通ったとかわからないのでテスト品質を保証しづらく、コード網羅率 Level C1 を 100%にしたいマンなのもありカバレッジ必須。&lt;/p&gt;
&lt;p&gt;でも事前に調べてた nyc や puppeteer での方法だと、現状の node-qunit-puppeteer を使ったテストのカバレッジ計測できなさそう...&lt;/p&gt;
&lt;p&gt;もう少し調べる必要がありそう 😳&lt;/p&gt;
&lt;p&gt;続く&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Thu, 21 Mar 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-02-24-lein-ring-server-error.html</guid><link>https://krymtkts.github.io/posts/2019-02-24-lein-ring-server-error.html</link><title>lein ringでエラーが発生した</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2019-02-20-instead-of-ping.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;以下のコメントを残した&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;この記事をしたためておるときに&lt;code&gt;lein ring server&lt;/code&gt;でエラーが出るようになってたのを解消したので、メモがてら次回に記す。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;どのような状況だったかを以下に記すと&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;lein ring server&lt;br /&gt;clojure.lang.Compiler&lt;span class=&quot;hljs-variable&quot;&gt;$CompilerException:&lt;/span&gt; Syntax error macroexpanding clojure.core/fn at (clojure/core/unify.clj:&lt;span class=&quot;hljs-number&quot;&gt;83&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;18&lt;/span&gt;).&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#:clojure.error{:phase :macro-syntax-check, :line 83, :column 18, :source &amp;quot;clojure/core/unify.clj&amp;quot;, :symbol clojure.core/fn}&lt;/span&gt;&lt;br /&gt; at clojure.lang.Compiler.checkSpecs (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6971&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.macroexpand1 (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6987&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyzeSeq (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7092&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyze (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6789&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyzeSeq (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7094&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyze (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6789&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.access&lt;span class=&quot;hljs-variable&quot;&gt;$300&lt;/span&gt; (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;38&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler&lt;span class=&quot;hljs-variable&quot;&gt;$DefExpr&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$Parser&lt;/span&gt;.parse (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;596&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyzeSeq (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7106&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyze (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6789&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyze (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6745&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7180&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;421&lt;/span&gt;)&lt;br /&gt;    clojure.core.contracts.impl.transformers&lt;span class=&quot;hljs-variable&quot;&gt;$eval690&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$loading__6706__auto____691&lt;/span&gt;.invoke (transformers.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.core.contracts.impl.transformers&lt;span class=&quot;hljs-variable&quot;&gt;$eval690&lt;/span&gt;.invokeStatic (transformers.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.core.contracts.impl.transformers&lt;span class=&quot;hljs-variable&quot;&gt;$eval690&lt;/span&gt;.invoke (transformers.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7176&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7165&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    leinjacker.defconstrainedfn&lt;span class=&quot;hljs-variable&quot;&gt;$eval684&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$loading__6706__auto____685&lt;/span&gt;.invoke (defconstrainedfn.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leinjacker.defconstrainedfn&lt;span class=&quot;hljs-variable&quot;&gt;$eval684&lt;/span&gt;.invokeStatic (defconstrainedfn.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leinjacker.defconstrainedfn&lt;span class=&quot;hljs-variable&quot;&gt;$eval684&lt;/span&gt;.invoke (defconstrainedfn.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7176&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7165&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;669&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$use&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6093&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$use&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6093&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    leinjacker.deps&lt;span class=&quot;hljs-variable&quot;&gt;$eval676&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$loading__6706__auto____677&lt;/span&gt;.invoke (deps.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leinjacker.deps&lt;span class=&quot;hljs-variable&quot;&gt;$eval676&lt;/span&gt;.invokeStatic (deps.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leinjacker.deps&lt;span class=&quot;hljs-variable&quot;&gt;$eval676&lt;/span&gt;.invoke (deps.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7176&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7165&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;436&lt;/span&gt;)&lt;br /&gt;    leiningen.ring.server&lt;span class=&quot;hljs-variable&quot;&gt;$eval668&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$loading__6706__auto____669&lt;/span&gt;.invoke (server.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leiningen.ring.server&lt;span class=&quot;hljs-variable&quot;&gt;$eval668&lt;/span&gt;.invokeStatic (server.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leiningen.ring.server&lt;span class=&quot;hljs-variable&quot;&gt;$eval668&lt;/span&gt;.invoke (server.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7176&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7165&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;669&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$use&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6093&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$use&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6093&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;551&lt;/span&gt;)&lt;br /&gt;    leiningen.ring&lt;span class=&quot;hljs-variable&quot;&gt;$eval662&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$loading__6706__auto____663&lt;/span&gt;.invoke (ring.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leiningen.ring&lt;span class=&quot;hljs-variable&quot;&gt;$eval662&lt;/span&gt;.invokeStatic (ring.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leiningen.ring&lt;span class=&quot;hljs-variable&quot;&gt;$eval662&lt;/span&gt;.invoke (ring.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7176&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7165&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    leiningen.core.utils&lt;span class=&quot;hljs-variable&quot;&gt;$require_resolve&lt;/span&gt;.invokeStatic (utils.clj:&lt;span class=&quot;hljs-number&quot;&gt;102&lt;/span&gt;)&lt;br /&gt;    leiningen.core.utils&lt;span class=&quot;hljs-variable&quot;&gt;$require_resolve&lt;/span&gt;.invoke (utils.clj:&lt;span class=&quot;hljs-number&quot;&gt;95&lt;/span&gt;)&lt;br /&gt;    leiningen.core.utils&lt;span class=&quot;hljs-variable&quot;&gt;$require_resolve&lt;/span&gt;.invokeStatic (utils.clj:&lt;span class=&quot;hljs-number&quot;&gt;105&lt;/span&gt;)&lt;br /&gt;    leiningen.core.utils&lt;span class=&quot;hljs-variable&quot;&gt;$require_resolve&lt;/span&gt;.invoke (utils.clj:&lt;span class=&quot;hljs-number&quot;&gt;95&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$lookup_task_var&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;69&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$lookup_task_var&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;65&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$pass_through_help_QMARK_&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;79&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$pass_through_help_QMARK_&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;73&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$task_args&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;82&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$task_args&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;81&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$resolve_and_apply&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;339&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$resolve_and_apply&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;336&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$_main&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6771&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;449&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$_main&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;439&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$_main&lt;/span&gt;.doInvoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;436&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Var.applyTo (Var.java:&lt;span class=&quot;hljs-number&quot;&gt;705&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;665&lt;/span&gt;)&lt;br /&gt;    clojure.main&lt;span class=&quot;hljs-variable&quot;&gt;$main_opt&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;491&lt;/span&gt;)&lt;br /&gt;    clojure.main&lt;span class=&quot;hljs-variable&quot;&gt;$main_opt&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;487&lt;/span&gt;)&lt;br /&gt;    clojure.main&lt;span class=&quot;hljs-variable&quot;&gt;$main&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;598&lt;/span&gt;)&lt;br /&gt;    clojure.main&lt;span class=&quot;hljs-variable&quot;&gt;$main&lt;/span&gt;.doInvoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;561&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Var.applyTo (Var.java:&lt;span class=&quot;hljs-number&quot;&gt;705&lt;/span&gt;)&lt;br /&gt;    clojure.main.main (main.java:&lt;span class=&quot;hljs-number&quot;&gt;37&lt;/span&gt;)&lt;br /&gt;Caused by: clojure.lang.ExceptionInfo: Call to clojure.core/fn did not conform to spec.&lt;br /&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#:clojure.spec.alpha{:problems ({:path [:fn-tail :arity-1 :params], :pred clojure.core/vector?, :val clojure.core.unify/var-unify, :via [:clojure.core.specs.alpha/params+body :clojure.core.specs.alpha/param-list :clojure.core.specs.alpha/param-list], :in [0]} {:path [:fn-tail :arity-n], :pred (clojure.core/fn [%] (clojure.core/or (clojure.core/nil? %) (clojure.core/sequential? %))), :val clojure.core.unify/var-unify, :via [:clojure.core.specs.alpha/params+body :clojure.core.specs.alpha/params+body], :in [0]}),&lt;/span&gt;&lt;br /&gt;:spec &lt;span class=&quot;hljs-comment&quot;&gt;#object[clojure.spec.alpha$regex_spec_impl$reify__2509 0x4f379769 &amp;quot;clojure.spec.alpha$regex_spec_impl$reify__2509@4f379769&amp;quot;], :value (clojure.core.unify/var-unify [G__800 G__801 G__802 G__803] (clojure.core/if-let [vb__793__auto__ (G__803 G__801)] (clojure.core.unify/garner-unifiers G__800 vb__793__auto__ G__802 G__803) (clojure.core/if-let [vexpr__794__auto__ (clojure.core/and (G__800 G__802) (G__803 G__802))] (clojure.core.unify/garner-unifiers G__800 G__801 vexpr__794__auto__ G__803) (if (clojure.core.unify/occurs? G__800 G__801 G__802 G__803) (throw (java.lang.IllegalStateException. (clojure.core/str &amp;quot;Cycle found in the path &amp;quot; G__802))) (clojure.core.unify/bind-phase G__803 G__801 G__802))))), :args (clojure.core.unify/var-unify [G__800 G__801 G__802 G__803] (clojure.core/if-let [vb__793__auto__ (G__803 G__801)] (clojure.core.unify/garner-unifiers G__800 vb__793__auto__ G__802 G__803) (clojure.core/if-let [vexpr__794__auto__ (clojure.core/and (G__800 G__802) (G__803 G__802))] (clojure.core.unify/garner-unifiers G__800 G__801 vexpr__794__auto__ G__803) (if (clojure.core.unify/occurs? G__800 G__801 G__802 G__803) (throw (java.lang.IllegalStateException. (clojure.core/str &amp;quot;Cycle found in the path &amp;quot; G__802))) (clojure.core.unify/bind-phase G__803 G__801 G__802)))))}&lt;/span&gt;&lt;br /&gt; at clojure.spec.alpha&lt;span class=&quot;hljs-variable&quot;&gt;$macroexpand_check&lt;/span&gt;.invokeStatic (alpha.clj:&lt;span class=&quot;hljs-number&quot;&gt;705&lt;/span&gt;)&lt;br /&gt;    clojure.spec.alpha&lt;span class=&quot;hljs-variable&quot;&gt;$macroexpand_check&lt;/span&gt;.invoke (alpha.clj:&lt;span class=&quot;hljs-number&quot;&gt;697&lt;/span&gt;)&lt;br /&gt;    clojure.lang.AFn.applyToHelper (AFn.java:&lt;span class=&quot;hljs-number&quot;&gt;156&lt;/span&gt;)&lt;br /&gt;    clojure.lang.AFn.applyTo (AFn.java:&lt;span class=&quot;hljs-number&quot;&gt;144&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Var.applyTo (Var.java:&lt;span class=&quot;hljs-number&quot;&gt;705&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.checkSpecs (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.macroexpand1 (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6987&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyzeSeq (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7092&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyze (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6789&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyzeSeq (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7094&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyze (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6789&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.access&lt;span class=&quot;hljs-variable&quot;&gt;$300&lt;/span&gt; (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;38&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler&lt;span class=&quot;hljs-variable&quot;&gt;$DefExpr&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$Parser&lt;/span&gt;.parse (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;596&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyzeSeq (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7106&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyze (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6789&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.analyze (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;6745&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7180&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;421&lt;/span&gt;)&lt;br /&gt;    clojure.core.contracts.impl.transformers&lt;span class=&quot;hljs-variable&quot;&gt;$eval690&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$loading__6706__auto____691&lt;/span&gt;.invoke (transformers.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.core.contracts.impl.transformers&lt;span class=&quot;hljs-variable&quot;&gt;$eval690&lt;/span&gt;.invokeStatic (transformers.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.core.contracts.impl.transformers&lt;span class=&quot;hljs-variable&quot;&gt;$eval690&lt;/span&gt;.invoke (transformers.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7176&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7165&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    leinjacker.defconstrainedfn&lt;span class=&quot;hljs-variable&quot;&gt;$eval684&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$loading__6706__auto____685&lt;/span&gt;.invoke (defconstrainedfn.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leinjacker.defconstrainedfn&lt;span class=&quot;hljs-variable&quot;&gt;$eval684&lt;/span&gt;.invokeStatic (defconstrainedfn.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leinjacker.defconstrainedfn&lt;span class=&quot;hljs-variable&quot;&gt;$eval684&lt;/span&gt;.invoke (defconstrainedfn.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7176&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7165&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;669&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$use&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6093&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$use&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6093&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    leinjacker.deps&lt;span class=&quot;hljs-variable&quot;&gt;$eval676&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$loading__6706__auto____677&lt;/span&gt;.invoke (deps.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leinjacker.deps&lt;span class=&quot;hljs-variable&quot;&gt;$eval676&lt;/span&gt;.invokeStatic (deps.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leinjacker.deps&lt;span class=&quot;hljs-variable&quot;&gt;$eval676&lt;/span&gt;.invoke (deps.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7176&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7165&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;436&lt;/span&gt;)&lt;br /&gt;    leiningen.ring.server&lt;span class=&quot;hljs-variable&quot;&gt;$eval668&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$loading__6706__auto____669&lt;/span&gt;.invoke (server.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leiningen.ring.server&lt;span class=&quot;hljs-variable&quot;&gt;$eval668&lt;/span&gt;.invokeStatic (server.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leiningen.ring.server&lt;span class=&quot;hljs-variable&quot;&gt;$eval668&lt;/span&gt;.invoke (server.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7176&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7165&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;669&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$use&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6093&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$use&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6093&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;551&lt;/span&gt;)&lt;br /&gt;    leiningen.ring&lt;span class=&quot;hljs-variable&quot;&gt;$eval662&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$loading__6706__auto____663&lt;/span&gt;.invoke (ring.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leiningen.ring&lt;span class=&quot;hljs-variable&quot;&gt;$eval662&lt;/span&gt;.invokeStatic (ring.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    leiningen.ring&lt;span class=&quot;hljs-variable&quot;&gt;$eval662&lt;/span&gt;.invoke (ring.clj:&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7176&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.eval (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7165&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Compiler.load (Compiler.java:&lt;span class=&quot;hljs-number&quot;&gt;7635&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;381&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.loadResourceScript (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;372&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;463&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RT.load (RT.java:&lt;span class=&quot;hljs-number&quot;&gt;428&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6824&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6126&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6125&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6109&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5908&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_one&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5903&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6765&lt;/span&gt;.invoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5948&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5947&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_lib&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5928&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;142&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5985&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$load_libs&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;5969&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;667&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$require&lt;/span&gt;.doInvoke (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;6007&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.invoke (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;408&lt;/span&gt;)&lt;br /&gt;    leiningen.core.utils&lt;span class=&quot;hljs-variable&quot;&gt;$require_resolve&lt;/span&gt;.invokeStatic (utils.clj:&lt;span class=&quot;hljs-number&quot;&gt;102&lt;/span&gt;)&lt;br /&gt;    leiningen.core.utils&lt;span class=&quot;hljs-variable&quot;&gt;$require_resolve&lt;/span&gt;.invoke (utils.clj:&lt;span class=&quot;hljs-number&quot;&gt;95&lt;/span&gt;)&lt;br /&gt;    leiningen.core.utils&lt;span class=&quot;hljs-variable&quot;&gt;$require_resolve&lt;/span&gt;.invokeStatic (utils.clj:&lt;span class=&quot;hljs-number&quot;&gt;105&lt;/span&gt;)&lt;br /&gt;    leiningen.core.utils&lt;span class=&quot;hljs-variable&quot;&gt;$require_resolve&lt;/span&gt;.invoke (utils.clj:&lt;span class=&quot;hljs-number&quot;&gt;95&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$lookup_task_var&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;69&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$lookup_task_var&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;65&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$pass_through_help_QMARK_&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;79&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$pass_through_help_QMARK_&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;73&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$task_args&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;82&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$task_args&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;81&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$resolve_and_apply&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;339&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$resolve_and_apply&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;336&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$_main&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$fn__6771&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;449&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$_main&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;439&lt;/span&gt;)&lt;br /&gt;    leiningen.core.main&lt;span class=&quot;hljs-variable&quot;&gt;$_main&lt;/span&gt;.doInvoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;436&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Var.applyTo (Var.java:&lt;span class=&quot;hljs-number&quot;&gt;705&lt;/span&gt;)&lt;br /&gt;    clojure.core&lt;span class=&quot;hljs-variable&quot;&gt;$apply&lt;/span&gt;.invokeStatic (core.clj:&lt;span class=&quot;hljs-number&quot;&gt;665&lt;/span&gt;)&lt;br /&gt;    clojure.main&lt;span class=&quot;hljs-variable&quot;&gt;$main_opt&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;491&lt;/span&gt;)&lt;br /&gt;    clojure.main&lt;span class=&quot;hljs-variable&quot;&gt;$main_opt&lt;/span&gt;.invoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;487&lt;/span&gt;)&lt;br /&gt;    clojure.main&lt;span class=&quot;hljs-variable&quot;&gt;$main&lt;/span&gt;.invokeStatic (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;598&lt;/span&gt;)&lt;br /&gt;    clojure.main&lt;span class=&quot;hljs-variable&quot;&gt;$main&lt;/span&gt;.doInvoke (main.clj:&lt;span class=&quot;hljs-number&quot;&gt;561&lt;/span&gt;)&lt;br /&gt;    clojure.lang.RestFn.applyTo (RestFn.java:&lt;span class=&quot;hljs-number&quot;&gt;137&lt;/span&gt;)&lt;br /&gt;    clojure.lang.Var.applyTo (Var.java:&lt;span class=&quot;hljs-number&quot;&gt;705&lt;/span&gt;)&lt;br /&gt;    clojure.main.main (main.java:&lt;span class=&quot;hljs-number&quot;&gt;37&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;lein ring server&lt;/code&gt;がエラーを吐くようになった。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lein help&lt;/code&gt;で見てみてもringだけエラーが出てる&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;lein help&lt;br /&gt;Leiningen is a tool &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; working with Clojure projects.&lt;br /&gt;&lt;br /&gt;Several tasks are available:&lt;br /&gt;change              Rewrite project.clj with f applied to the value at key&lt;span class=&quot;hljs-operator&quot;&gt;-or&lt;/span&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-path&lt;/span&gt;.&lt;br /&gt;check               Check syntax and warn on reflection.&lt;br /&gt;classpath           &lt;span class=&quot;hljs-built_in&quot;&gt;Write&lt;/span&gt; the classpath of the current project to output&lt;span class=&quot;hljs-operator&quot;&gt;-file&lt;/span&gt;.&lt;br /&gt;clean               Removes all files from paths &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; clean&lt;span class=&quot;hljs-literal&quot;&gt;-targets&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; a project&lt;br /&gt;compile             Compile Clojure source into .class files.&lt;br /&gt;deploy              Deploy jar and pom to remote repository.&lt;br /&gt;deps                Show details about dependencies.&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;                  Higher&lt;span class=&quot;hljs-literal&quot;&gt;-order&lt;/span&gt; task to perform other tasks &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; succession.&lt;br /&gt;help                Display a list of tasks or help &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; a given task or subtask.&lt;br /&gt;install             Install jar and pom to the local repository; typically ~/.m2.&lt;br /&gt;jar                 Package up all the project&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;s files into a jar file.&lt;br /&gt;javac               Compile Java source files.&lt;br /&gt;new                 Generate scaffolding for a new project based on a template.&lt;br /&gt;plugin              DEPRECATED. Please use the :user profile instead.&lt;br /&gt;pom                 Write a pom.xml file to disk for Maven interoperability.&lt;br /&gt;release             Perform release tasks.&lt;br /&gt;repl                Start a repl session either with the current project or standalone.&lt;br /&gt;retest              Run only the test namespaces which failed last time around.&lt;br /&gt;leiningen.ring  Problem loading: Syntax error macroexpanding clojure.core/fn at (clojure/core/unify.clj:83:18).&lt;br /&gt;run                 Run the project&amp;#x27;&lt;/span&gt;s &lt;span class=&quot;hljs-literal&quot;&gt;-main&lt;/span&gt; function.&lt;br /&gt;search              Search Central and Clojars &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; published artifacts.&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;show-profiles&lt;/span&gt;       List all available profiles or display one &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; given an argument.&lt;br /&gt;test                Run the project&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;s tests.&lt;br /&gt;trampoline          Run a task without nesting the project&amp;#x27;&lt;/span&gt;s JVM inside Leiningen&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;s.&lt;br /&gt;uberjar             Package up the project files and all dependencies into a jar file.&lt;br /&gt;update-in           Perform arbitrary transformations on your project map.&lt;br /&gt;upgrade             Upgrade Leiningen to specified version or latest stable.&lt;br /&gt;vcs                 Interact with the version control system.&lt;br /&gt;version             Print version for Leiningen and the current JVM.&lt;br /&gt;with-profile        Apply the given task with the profile(s) specified.&lt;br /&gt;&lt;br /&gt;Run `lein help $TASK` for details.&lt;br /&gt;&lt;br /&gt;Global Options:&lt;br /&gt;  -o             Run a task offline.&lt;br /&gt;  -U             Run a task after forcing update of snapshots.&lt;br /&gt;  -h, --help     Print this help or help for a specific task.&lt;br /&gt;  -v, --version  Print Leiningen&amp;#x27;&lt;/span&gt;s version.&lt;br /&gt;&lt;br /&gt;These aliases are available:&lt;br /&gt;downgrade, expands to upgrade&lt;br /&gt;&lt;br /&gt;See also: readme, faq, tutorial, news, sample, profiles, deploying, gpg,&lt;br /&gt;mixed&lt;span class=&quot;hljs-literal&quot;&gt;-source&lt;/span&gt;, templates, and copying.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;この前後にPCのソフトウェア更新など諸々してたしJDK更新したからか？と云う気もしたが原因はわからず。&lt;/p&gt;
&lt;p&gt;ブログを作るだけなら&lt;code&gt;lein run&lt;/code&gt;すりゃいいだけなのでなくてもよいのだが、見れたほうが良いので他のversionだとどうか試してみたところ、
0.12.5以上でならイケることがわかったので、cryogenの&lt;code&gt;project.clj&lt;/code&gt;に記述されてる&lt;code&gt;lein-ring&lt;/code&gt;のversionを上げることで障害を解消した。&lt;/p&gt;
&lt;p&gt;ブログを書くための見えない部分の障害なので最も楽な解決方法でいったが、プロダクトでこれが起こってたらもっとエラーの原因を深掘りしたであろうな🤔&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Sun, 24 Feb 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-02-20-instead-of-ping.html</guid><link>https://krymtkts.github.io/posts/2019-02-20-instead-of-ping.html</link><title>pingの代わりにTest-Connectionを使う</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;PowerShellには&lt;code&gt;Test-Connection&lt;/code&gt;というやつがあるのを今更ながら知った。&lt;/p&gt;
&lt;p&gt;今の仕事では、仮想マシン(dockerでない)を複数立ち上げて作業することが常になってるのだが、結構立ち上げ忘れてたりしてうっかりSSHしたときに繋げないのである😢&lt;/p&gt;
&lt;p&gt;疎通確認と合わせてSSHするすべを探してたところ、これを知ったので以下のようなスクリプトを作ってCmderのTaskに登録して使っている。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$waken&lt;/span&gt; = &lt;span class=&quot;hljs-built_in&quot;&gt;Test-Connection&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-TargetName&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$ip&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Count&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Quiet&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!&lt;span class=&quot;hljs-variable&quot;&gt;$waken&lt;/span&gt;) {&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;target not found. please start up &lt;span class=&quot;hljs-variable&quot;&gt;$ip&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-variable&quot;&gt;$Host&lt;/span&gt;.UI.RawUI.ReadKey() | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;exit&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;ssh &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;admin@&lt;span class=&quot;hljs-variable&quot;&gt;$ip&lt;/span&gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://blog.shibata.tech/entry/2016/06/16/231239&quot; title=&quot;Test-Connectionが遅い理由と対策方法について - しばたテックブログ&quot;&gt;Test-Connectionが遅い理由と対策方法について - しばたテックブログ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;↑このような話もあるようなので目を通しておきたいところ🤔&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;おまけ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://qiita.com/twinkfrag/items/f3ecf79b68ea09eadec2&quot; title=&quot;PowerShellでPause - Qiita&quot;&gt;PowerShellでPause - Qiita&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;最近のPowerShellには&lt;code&gt;Pause&lt;/code&gt;なるもんがデフォで入ってるが、古来からの方法でEnter以外のキーでも使えるようにしておくのが良いであらうか？&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;type key to continue...&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$Host&lt;/span&gt;.UI.RawUI.ReadKey() | &lt;span class=&quot;hljs-built_in&quot;&gt;Out-Null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;スクリプトの中でコレを呼んだら、なんかのキーを押すまで止まる。&lt;/p&gt;
&lt;p&gt;戻り値が標準出力されないようにするために&lt;code&gt;Out-Null&lt;/code&gt;にパイプラインする。&lt;code&gt;$null&lt;/code&gt;に代入でもよいが。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;余談&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;この記事をしたためておるときに&lt;code&gt;lein ring server&lt;/code&gt;でエラーが出るようになってたのを解消したので、メモがてら次回に記す。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Wed, 20 Feb 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-02-11-Register-ArgumentCompleter2.html</guid><link>https://krymtkts.github.io/posts/2019-02-11-Register-ArgumentCompleter2.html</link><title>Register-ArgumentCompleterのScriptBlockの引数</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;&lt;a href=&quot;/posts/2019-02-04-Register-ArgumentCompleter.html&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;の続き。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Register-ArgumentCompleter&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Native&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-CommandName&lt;/span&gt; mvn &lt;span class=&quot;hljs-literal&quot;&gt;-ScriptBlock&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$wordToComplete&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$commandAst&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$cursorPosition&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;↑こんなんいるやん？&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wordToComplete&lt;/code&gt;には入力中の文字列が入ってくる。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$commandAst&lt;/code&gt;にはコマンドラインが全部載ってくる。&lt;/p&gt;
&lt;p&gt;でも実際詳しく知らんので、たとえば&lt;code&gt;maven clean install -pl :module1 -&lt;/code&gt;ってとこまで入力してCtrl+Spaceやったときにはどういうパラメータになるかわからんので調べた。&lt;/p&gt;
&lt;p&gt;結論から言うと&lt;code&gt;$commandAst&lt;/code&gt;はASTが乗ってくる。&lt;code&gt;mvn clean install --d&lt;/code&gt;でtabしたときのデバッガでの出力は以下の通り(デバッグ実行にはISEを利用した)。 &lt;a href=&quot;https://docs.microsoft.com/ja-jp/powershell/scripting/components/ise/exploring-the-windows-powershell-ise?view=powershell-6&quot; title=&quot;Windows PowerShell ISE の操作 | Microsoft Docs&quot;&gt;Windows PowerShell ISE の操作 | Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt; C:\Users\takatoshi\Desktop\maven&amp;gt; mvn clean install &lt;span class=&quot;hljs-literal&quot;&gt;--d&lt;/span&gt;&lt;br /&gt;ヒット &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;C:\Users\takatoshi\dev\powershell\MavenAutoCompletion\MavenAutoCompletion.ps1:152&amp;#x27;&lt;/span&gt; の行のブレークポイント&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;DBG&lt;/span&gt;]: &lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt; C:\Users\takatoshi\Desktop\maven&amp;gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$commandAst&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CommandElements    : {mvn, clean, install, &lt;span class=&quot;hljs-literal&quot;&gt;--d&lt;/span&gt;}&lt;br /&gt;InvocationOperator : Unknown&lt;br /&gt;DefiningKeyword    :&lt;br /&gt;Redirections       : {}&lt;br /&gt;Extent             : mvn clean install &lt;span class=&quot;hljs-literal&quot;&gt;--d&lt;/span&gt;&lt;br /&gt;Parent             : mvn clean install &lt;span class=&quot;hljs-literal&quot;&gt;--d&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;DBG&lt;/span&gt;]: &lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt; C:\Users\takatoshi\Desktop\maven&amp;gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$wordToComplete&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;--d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;mvn clean install --projects :&lt;/code&gt;でtabした場合↓&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;[&lt;span class=&quot;hljs-type&quot;&gt;DBG&lt;/span&gt;]: &lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt; C:\Users\takatoshi\Desktop\maven&amp;gt;&amp;gt;&lt;br /&gt;mvn clean install &lt;span class=&quot;hljs-literal&quot;&gt;--projects&lt;/span&gt; :&lt;br /&gt;ヒット &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;C:\Users\takatoshi\dev\powershell\MavenAutoCompletion\MavenAutoCompletion.ps1:152&amp;#x27;&lt;/span&gt; の行のブレークポイント&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;DBG&lt;/span&gt;]: &lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt; C:\Users\takatoshi\Desktop\maven&amp;gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$commandAst&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CommandElements    : {mvn, clean, install, &lt;span class=&quot;hljs-literal&quot;&gt;--projects&lt;/span&gt;...}&lt;br /&gt;InvocationOperator : Unknown&lt;br /&gt;DefiningKeyword    :&lt;br /&gt;Redirections       : {}&lt;br /&gt;Extent             : mvn clean install &lt;span class=&quot;hljs-literal&quot;&gt;--projects&lt;/span&gt; :&lt;br /&gt;Parent             : mvn clean install &lt;span class=&quot;hljs-literal&quot;&gt;--projects&lt;/span&gt; :&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[&lt;span class=&quot;hljs-type&quot;&gt;DBG&lt;/span&gt;]: &lt;span class=&quot;hljs-built_in&quot;&gt;PS&lt;/span&gt; C:\Users\takatoshi\Desktop\maven&amp;gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$commandAst&lt;/span&gt;.CommandElements&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;StringConstantType : BareWord&lt;br /&gt;Value              : mvn&lt;br /&gt;StaticType         : System.String&lt;br /&gt;Extent             : mvn&lt;br /&gt;Parent             : mvn clean install &lt;span class=&quot;hljs-literal&quot;&gt;--projects&lt;/span&gt; :&lt;br /&gt;&lt;br /&gt;StringConstantType : BareWord&lt;br /&gt;Value              : clean&lt;br /&gt;StaticType         : System.String&lt;br /&gt;Extent             : clean&lt;br /&gt;Parent             : mvn clean install &lt;span class=&quot;hljs-literal&quot;&gt;--projects&lt;/span&gt; :&lt;br /&gt;&lt;br /&gt;StringConstantType : BareWord&lt;br /&gt;Value              : install&lt;br /&gt;StaticType         : System.String&lt;br /&gt;Extent             : install&lt;br /&gt;Parent             : mvn clean install &lt;span class=&quot;hljs-literal&quot;&gt;--projects&lt;/span&gt; :&lt;br /&gt;&lt;br /&gt;StringConstantType : BareWord&lt;br /&gt;Value              : &lt;span class=&quot;hljs-literal&quot;&gt;--projects&lt;/span&gt;&lt;br /&gt;StaticType         : System.String&lt;br /&gt;Extent             : &lt;span class=&quot;hljs-literal&quot;&gt;--projects&lt;/span&gt;&lt;br /&gt;Parent             : mvn clean install &lt;span class=&quot;hljs-literal&quot;&gt;--projects&lt;/span&gt; :&lt;br /&gt;&lt;br /&gt;StringConstantType : BareWord&lt;br /&gt;Value              : :&lt;br /&gt;StaticType         : System.String&lt;br /&gt;Extent             : :&lt;br /&gt;Parent             : mvn clean install &lt;span class=&quot;hljs-literal&quot;&gt;--projects&lt;/span&gt; :
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;wordToComplete&lt;/code&gt; こいつはまじでただの文字列。&lt;code&gt;commandAst.CommandElements&lt;/code&gt;の最後の要素の&lt;code&gt;value&lt;/code&gt;が出てる。&lt;/p&gt;
&lt;p&gt;という感じだったので、MavenAutoCompletion的には&lt;code&gt;commandAst.CommandElements&lt;/code&gt;の最後から2要素を対象に正規表現してやれば、だいたい望みのことができるのがわかったのであった。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;余談&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;PowerShellで配列の任意の連続した要素を抜き出すのに、slice的なんがないんかと調べたところ、以下のようにするようだ。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt; = &lt;span class=&quot;hljs-selector-tag&quot;&gt;@&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;mvn&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;clean&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;install&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;-pl&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;:&amp;#x27;&lt;/span&gt;)&lt;br /&gt;&amp;gt; &lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt;[(&lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;.Length&lt;/span&gt; -&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)&lt;span class=&quot;hljs-type&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$a&lt;/span&gt;&lt;span class=&quot;hljs-type&quot;&gt;.Length&lt;/span&gt;]&lt;br /&gt;&lt;span class=&quot;hljs-literal&quot;&gt;-pl&lt;/span&gt;&lt;br /&gt;:
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;cool😉&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Mon, 11 Feb 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-02-04-Register-ArgumentCompleter.html</guid><link>https://krymtkts.github.io/posts/2019-02-04-Register-ArgumentCompleter.html</link><title>Register-ArgumentCompleter</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;まだoutputが習慣化してなくて随分空いてしまった🤔&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-a-href-https-docs-microsoft-com-en-us-powershell-module-microsoft-powershell-core-register-argumentcompleter-view-powershell-6-title-Register-ArgumentCompleter-Register-ArgumentCompleter-a-&quot; href=&quot;#-a-href-https-docs-microsoft-com-en-us-powershell-module-microsoft-powershell-core-register-argumentcompleter-view-powershell-6-title-Register-ArgumentCompleter-Register-ArgumentCompleter-a-&quot;&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/register-argumentcompleter?view=powershell-6&quot; title=&quot;Register-ArgumentCompleter&quot;&gt;Register-ArgumentCompleter&lt;/a&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;PowerShell5から、従来の&lt;code&gt;TabExpansion&lt;/code&gt;に代わる&lt;code&gt;Register-ArgumentCompleter&lt;/code&gt;なるモノが現れたのは、PowerShellerなら知っているだろう(わたしは去年まで知らんかったのでPowerShellerではないのだ)。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;サンプル書いてみた&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Mavenのよく使うコマンドでお試し。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Register-ArgumentCompleter&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Native&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-CommandName&lt;/span&gt; mvn &lt;span class=&quot;hljs-literal&quot;&gt;-ScriptBlock&lt;/span&gt; {&lt;br /&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;param&lt;/span&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;$wordToComplete&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$commandAst&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$cursorPosition&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;--&lt;/span&gt; clean install eclipse:eclipse |&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Where-Object&lt;/span&gt; { &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;-like&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$wordToComplete&lt;/span&gt;*&amp;quot;&lt;/span&gt; } |&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;Sort-Object&lt;/span&gt; |&lt;br /&gt;        &lt;span class=&quot;hljs-built_in&quot;&gt;ForEach-Object&lt;/span&gt; {&lt;br /&gt;            [&lt;span class=&quot;hljs-type&quot;&gt;System.Management.Automation.CompletionResult&lt;/span&gt;]::new(&lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ParameterValue&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-variable&quot;&gt;$_&lt;/span&gt;)&lt;br /&gt;        }&lt;br /&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;めちゃんこ簡単。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;作ったもの&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;当時仕事で巨大なMavenプロジェクトを使っていて、コマンド打つのも億劫だったのでPowerShellで自動補完がほしいなと思っていたのだが、&lt;code&gt;TabExpantion&lt;/code&gt;はちょっと自分には使いこなせなかった。関数のオーバーライドをしたりのおまじないが必要だし。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Register-ArgumentCompleter&lt;/code&gt;なら簡単に作れたので、APIが進化してる感をひしと感じたのであった。以下成果物↓&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/krymtkts/MavenAutoCompletion&quot; title=&quot;krymtkts/MavenAutoCompletion: MavenAutoCompletion provides a simple auto completion of Maven 3 to PowerShell.&quot;&gt;krymtkts/MavenAutoCompletion: MavenAutoCompletion provides a simple auto completion of Maven 3 to PowerShell.&lt;/a&gt;&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;既知のバグ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;PowerShell5だと&lt;code&gt;-Native&lt;/code&gt;オプションありの場合に&lt;code&gt;-&lt;/code&gt;を利用した補完ができないバグがあって、前述の自動補完がうまく使えなくて辛い...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PowerShell/PowerShell/issues/2912&quot; title=&quot;Native ArgumentCompleter not invoked for inputs that begin with hyphen (-) · Issue #2912 · PowerShell/PowerShell&quot;&gt;Native ArgumentCompleter not invoked for inputs that begin with hyphen (-) · Issue #2912 · PowerShell/PowerShell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PowerShell5.xでも使えないものかと試してみたところ、Trickyな回避策として&lt;code&gt;&amp;#x60;&lt;/code&gt;で&lt;code&gt;-&lt;/code&gt;をエスケープしたらイケるというのを見つけたが...posh-gitもchocolateyもそれで従来からの&lt;code&gt;TabExpantion&lt;/code&gt;を使ってたのかーという気付きは得られた。&lt;/p&gt;
&lt;p&gt;ちなみにわたしはPowerShell6を使ってるのでかんけーないのだ😜&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;残&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;Register-ArgumentCompleter&lt;/code&gt;のScriptBlockの引数をちまちま調べたのがあるけど、長いから別に書こう。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Mon, 04 Feb 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-01-17-build-qmk-firmware-of-planck.html</guid><link>https://krymtkts.github.io/posts/2019-01-17-build-qmk-firmware-of-planck.html</link><title>Planckのキーマップをビルドする</title><description>&lt;div class=&quot;section&quot;&gt;&lt;blockquote&gt;
&lt;p&gt;当時使ってたPCではプログラミングしなくなったのと、改めてQMK firmwareのdocument見たらbuild toolsんとこの記事が変わってるので、今度環境構築がてら再確認してfirmwareのとこだけ新しく書こうと思う。&lt;/p&gt;
&lt;p&gt;わたしのkeymapのrepo(&lt;a href=&quot;https://github.com/krymtkts/qmk_firmware&quot; title=&quot;krymtkts/qmk_firmware&quot;&gt;krymtkts/qmk_firmware&lt;/a&gt;)は「デフォのキーマップをコピった」的なコミットを最後に止まってるので、旧PCに遺物が残されてそう...作り直したほうが早いわ😅&lt;/p&gt;
&lt;p&gt;去年はWSLで書き込む方法が確か使えてたはずだけど今は非推奨になってて、MSYS2を使う方法が主流になった？？？謎い🤔&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;./2019-01-14-ortho-linear-keyboard-planck&quot; title=&quot;前回&quot;&gt;前回&lt;/a&gt;のこの辺の続き。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;ビルド環境をセットアップする&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ドキュメント&lt;a href=&quot;https://docs.qmk.fm/#/getting_started_build_tools&quot; title=&quot;QMK Firmware - Installing Build Tools&quot;&gt;QMK Firmware - Installing Build Tools&lt;/a&gt;に記載のWSLの手順をそのままでOK。ちょっとWSLを使いたかったのでMSYS2でのやつではあえてやらなかった。&lt;/p&gt;
&lt;p&gt;WSL用のセットアップは&lt;code&gt;util/wsl_install.sh&lt;/code&gt;で行う。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; ./c/qmk_firmware/&lt;br /&gt;$ ./util/wsl_install.sh
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;途中ドライバを全部入れる？と聞かれて、それは流石に...と思ったのでConnectedという接続したドライバだけ入れるやつ&lt;code&gt;C&lt;/code&gt;にした。&lt;/p&gt;
&lt;p&gt;Flip入れる？と聞かれたけどつかわないだろうし必要なときに、と思ったので&lt;code&gt;N&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wsl_install.sh&lt;/code&gt;完了後にPlanckのrev4のdefaultキーマップを試しにコンパイルする。&lt;/p&gt;
&lt;p&gt;bashを再起動してサンプルのコマンドを実行する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ make planck/rev4:default
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;でバイナリが吐き出されたのでOK。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;Planck-firmware-&quot; href=&quot;#Planck-firmware-&quot;&gt;Planckのfirmwareをビルドする&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;わたしのキーマップはこちら→&lt;a href=&quot;https://github.com/krymtkts/qmk_firmware/blob/master/keyboards/planck/keymaps/krymtkts/keymap.c&quot; title=&quot;qmk_firmware/keymap.c at master · krymtkts/qmk_firmware&quot;&gt;qmk_firmware/keymap.c at master · krymtkts/qmk_firmware&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2017年末頃にビルドしたころとは&lt;code&gt;keyboards/planck/&lt;/code&gt;配下のコードが結構変わってるようなので、作成済みのキーマップを削除して新しく&lt;code&gt;default&lt;/code&gt;キーマップを作成する。それ用のシェルがあるので使う。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ ./util/new_keymap.sh planck krymtkts
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これで一旦ビルドする。revisionはわからんけど時期的に5だと思う。[要出典?]&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ make planck/rev5:krymtkts
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コマンドラインでfirmwareを書き込む。revision5では以下のコマンドが正しい。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ make planck/rev5:krymtkts:dfu
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;でもエラーになった。なんかエラーが無限に繰り返される。CTRL+Cで中断&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ make planck/rev5:krymtkts:dfu&lt;br /&gt;QMK Firmware 0.6.228&lt;br /&gt;Making planck/rev5 with keymap krymtkts and target dfu&lt;br /&gt;&lt;br /&gt;avr-gcc (GCC) 4.9.2&lt;br /&gt;Copyright (C) 2014 Free Software Foundation, Inc.&lt;br /&gt;This is free software; see the &lt;span class=&quot;hljs-built_in&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; copying conditions.  There is NO&lt;br /&gt;warranty; not even &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&lt;br /&gt;&lt;br /&gt;Size before:&lt;br /&gt;text    data     bss     dec     hex filename&lt;br /&gt;    0   26614       0   26614    67f6 .build/planck_rev5_krymtkts.hex&lt;br /&gt;&lt;br /&gt;Compiling: keyboards/planck/keymaps/krymtkts/keymap.c                                               [OK]&lt;br /&gt;Linking: .build/planck_rev5_krymtkts.elf                                                            [OK]&lt;br /&gt;Creating load file &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; flashing: .build/planck_rev5_krymtkts.hex                                    [OK]&lt;br /&gt;Copying planck_rev5_krymtkts.hex to qmk_firmware folder                                             [OK]&lt;br /&gt;Checking file size of planck_rev5_krymtkts.hex                                                      [OK]&lt;br /&gt;* The firmware size is fine - 26614/28672 (2058 bytes free)&lt;br /&gt;Error: Bootloader not found. Trying again &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; 5s.&lt;br /&gt;Error: Bootloader not found. Trying again &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; 5s.&lt;br /&gt;Error: Bootloader not found. Trying again &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; 5s.&lt;br /&gt;Error: Bootloader not found. Trying again &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; 5s.&lt;br /&gt;Error: Bootloader not found. Trying again &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; 5s.&lt;br /&gt;^Ctmk_core/avr.mk:141: recipe &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; target &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;dfu&amp;#x27;&lt;/span&gt; failed&lt;br /&gt;make[1]: *** [dfu] Interrupt&lt;br /&gt;Makefile:529: recipe &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; target &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;planck/rev5:krymtkts:dfu&amp;#x27;&lt;/span&gt; failed&lt;br /&gt;make: *** [planck/rev5:krymtkts:dfu] Interrupt
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;エラーダイアログで「libusb0.dllがない」というような旨が表示される。WSLでやろうとしたからダメだったのか？&lt;/p&gt;
&lt;p&gt;コマンドラインで焼くのを一旦諦めて、&lt;code&gt;qmk_tookbox.exe&lt;/code&gt;を使うことにしたら一発成功、Planckに自分のキーマップを焼くことに成功した。&lt;/p&gt;
&lt;p&gt;でもコマンドラインで焼けないのは困るので、PlanckのMakefileの&lt;code&gt;rules.mk&lt;/code&gt;見てみたところ、&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-makefile&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;ifeq&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$(&lt;span class=&quot;hljs-built_in&quot;&gt;strip&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$(KEYBOARD)&lt;/span&gt;)&lt;/span&gt;, planck/rev4)&lt;br /&gt;    BOOTLOADER = atmel-dfu&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;endif&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;ifeq&lt;/span&gt; (&lt;span class=&quot;hljs-variable&quot;&gt;$(&lt;span class=&quot;hljs-built_in&quot;&gt;strip&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$(KEYBOARD)&lt;/span&gt;)&lt;/span&gt;, planck/rev5)&lt;br /&gt;    BOOTLOADER = qmk-dfu&lt;br /&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;とあって、rev4と4rev5でbootloaderが変わってることから、あれ？わたしのPlanckもしかしてrev4じゃ？と思って試してみたところ...&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ make planck/rev4:krymtkts:dfu&lt;br /&gt;QMK Firmware 0.6.228&lt;br /&gt;Making planck/rev4 with keymap krymtkts and target dfu&lt;br /&gt;&lt;br /&gt;avr-gcc (GCC) 4.9.2&lt;br /&gt;Copyright (C) 2014 Free Software Foundation, Inc.&lt;br /&gt;This is free software; see the &lt;span class=&quot;hljs-built_in&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; copying conditions.  There is NO&lt;br /&gt;warranty; not even &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&lt;br /&gt;&lt;br /&gt;Compiling: quantum/audio/muse.c                                                                     [OK]&lt;br /&gt;Compiling: keyboards/planck/planck.c                                                                [OK]&lt;br /&gt;Compiling: keyboards/planck/keymaps/krymtkts/keymap.c                                               [OK]&lt;br /&gt;Compiling: quantum/quantum.c                                                                        [OK]&lt;br /&gt;Compiling: quantum/keymap_common.c                                                                  [OK]&lt;br /&gt;Compiling: quantum/keycode_config.c                                                                 [OK]&lt;br /&gt;Compiling: quantum/matrix.c                                                                         [OK]&lt;br /&gt;Compiling: quantum/process_keycode/process_audio.c                                                  [OK]&lt;br /&gt;Compiling: quantum/process_keycode/process_clicky.c                                                 [OK]&lt;br /&gt;Compiling: quantum/audio/audio.c                                                                    [OK]&lt;br /&gt;Compiling: quantum/audio/voices.c                                                                   [OK]&lt;br /&gt;Compiling: quantum/audio/luts.c                                                                     [OK]&lt;br /&gt;Compiling: quantum/process_keycode/process_music.c                                                  [OK]&lt;br /&gt;Compiling: tmk_core/common/host.c                                                                   [OK]&lt;br /&gt;Compiling: tmk_core/common/keyboard.c                                                               [OK]&lt;br /&gt;Compiling: tmk_core/common/action.c                                                                 [OK]&lt;br /&gt;Compiling: tmk_core/common/action_tapping.c                                                         [OK]&lt;br /&gt;Compiling: tmk_core/common/action_macro.c                                                           [OK]&lt;br /&gt;Compiling: tmk_core/common/action_layer.c                                                           [OK]&lt;br /&gt;Compiling: tmk_core/common/action_util.c                                                            [OK]&lt;br /&gt;Compiling: tmk_core/common/print.c                                                                  [OK]&lt;br /&gt;Compiling: tmk_core/common/debug.c                                                                  [OK]&lt;br /&gt;Compiling: tmk_core/common/util.c                                                                   [OK]&lt;br /&gt;Compiling: tmk_core/common/eeconfig.c                                                               [OK]&lt;br /&gt;Compiling: tmk_core/common/report.c                                                                 [OK]&lt;br /&gt;Compiling: tmk_core/common/avr/suspend.c                                                            [OK]&lt;br /&gt;Compiling: tmk_core/common/avr/timer.c                                                              [OK]&lt;br /&gt;Compiling: tmk_core/common/avr/bootloader.c                                                         [OK]&lt;br /&gt;Assembling: tmk_core/common/avr/xprintf.S                                                           [OK]&lt;br /&gt;Compiling: tmk_core/common/magic.c                                                                  [OK]&lt;br /&gt;Compiling: tmk_core/protocol/lufa/lufa.c                                                            [OK]&lt;br /&gt;Compiling: tmk_core/protocol/usb_descriptor.c                                                       [OK]&lt;br /&gt;Compiling: tmk_core/protocol/lufa/outputselect.c                                                    [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Class/Common/HIDParser.c                                       [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Device_AVR8.c                                        [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/EndpointStream_AVR8.c                                [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Endpoint_AVR8.c                                      [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Host_AVR8.c                                          [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/PipeStream_AVR8.c                                    [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Pipe_AVR8.c                                          [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/USBController_AVR8.c                                 [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/USBInterrupt_AVR8.c                                  [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/ConfigDescriptors.c                                       [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/DeviceStandardReq.c                                       [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/Events.c                                                  [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/HostStandardReq.c                                         [OK]&lt;br /&gt;Compiling: lib/lufa/LUFA/Drivers/USB/Core/USBTask.c                                                 [OK]&lt;br /&gt;Linking: .build/planck_rev4_krymtkts.elf                                                            [OK]&lt;br /&gt;Creating load file &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; flashing: .build/planck_rev4_krymtkts.hex                                    [OK]&lt;br /&gt;Copying planck_rev4_krymtkts.hex to qmk_firmware folder                                             [OK]&lt;br /&gt;Checking file size of planck_rev4_krymtkts.hex                                                      [OK]&lt;br /&gt; * The firmware size is fine - 26614/28672 (2058 bytes free)&lt;br /&gt;Bootloader Version: 0x00 (0)&lt;br /&gt;Erasing flash...  Success&lt;br /&gt;Checking memory from 0x0 to 0x6FFF...  Empty.&lt;br /&gt;Checking memory from 0x0 to 0x67FF...  Empty.&lt;br /&gt;0%                            100%  Programming 0x6800 bytes...&lt;br /&gt;[&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;]  Success&lt;br /&gt;0%                            100%  Reading 0x7000 bytes...&lt;br /&gt;[&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;]  Success&lt;br /&gt;Validating...  Success&lt;br /&gt;0x6800 bytes written into 0x7000 bytes memory (92.86%).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;成功した。時期的にrev5だと思ってたけどrev4だったとは😅まあうまくいってよかった。&lt;/p&gt;
&lt;p&gt;キーマップはまだしっくり来ていないのでちまちま更新する予定。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Thu, 17 Jan 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-01-14-ortho-linear-keyboard-planck.html</guid><link>https://krymtkts.github.io/posts/2019-01-14-ortho-linear-keyboard-planck.html</link><title>Ortho-Linear Keyboard &quot;Planck&quot;</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;わたしが&lt;a href=&quot;https://olkb.com/planck/&quot; title=&quot;Planck&quot;&gt;Planck&lt;/a&gt;を手に入れたのは割と遅めのタイミング。&lt;/p&gt;
&lt;p&gt;2017年の春に&lt;a href=&quot;https://www.massdrop.com/&quot; title=&quot;Massdrop&quot;&gt;Massdrop&lt;/a&gt;で買って、6月末に届く予定だったのだけど、手元に届いたのが秋頃だった。jackhumbertさん(OLKBの中の人)随分忙しかったようで遅れまくり。&lt;/p&gt;
&lt;p&gt;普段の仕事では&lt;a href=&quot;https://ergodox-ez.com/&quot; title=&quot;Ergodox EZ&quot;&gt;Ergodox EZ&lt;/a&gt;を使ってるんやが、持ち運びに便利なminimalなキーボードが欲しくて買った。&lt;/p&gt;
&lt;p&gt;以下はその作業ログである。&lt;/p&gt;
&lt;hr/&gt;&lt;p&gt;&lt;em&gt;date: 2017-10-07&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2019-01-14-planck/planck-case-keyswitches.jpg&quot; title=&quot;者共&quot; alt=&quot;者共&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;ケース付き、キースイッチ付きでDIYキットを購入。キースイッチはCherry MX Clear。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;はじめに&lt;/a&gt;&lt;/h4&gt;&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;手順の理解&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;Jack Humbert氏のYoutubeを見てイメージを掴む。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=S2FApwzVxAQ&quot; title=&quot;How to Actually Build a Planck (or Preonic or Atomic) from OLKB&quot;&gt;How to Actually Build a Planck (or Preonic or Atomic) from OLKB&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;説明動画を見てケッコー以外だったのが、key switchの端子の歪みを素手で直してた所。ピンセットとか使わないんや...&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;作業に入る&lt;/a&gt;&lt;/h4&gt;&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;検品&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;&lt;img src=&quot;/img/2019-01-14-planck/planck-picking.jpg&quot; title=&quot;パーツ欠品確認&quot; alt=&quot;パーツ欠品確認&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;パーツは全部揃っている。数も数えたしOK&lt;/p&gt;
&lt;p&gt;一箇所Switch Plateに多分プレス時にズレかなんかあったであろう痕があってちょっと残念。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2019-01-14-planck/planck-unfortunate.jpg&quot; title=&quot;プレスミス？&quot; alt=&quot;プレスミス？&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;PCBはUSBに接続して音がなればOKとのこと。ファンシーなnoiseが奏でられた&lt;/p&gt;
&lt;p&gt;PlanckはLEDにも対応してるけど、今回はデフォ実装するためナシ。でも今後欲しい感じもする。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;Switch-&quot; href=&quot;#Switch-&quot;&gt;Switchはめ込み&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;Sitch PlateにKey Switchをはめる&lt;/p&gt;
&lt;p&gt;48Keyで使う。ちょっと数が多いしはめ込むのは面倒だけど、黙々とやる。
KeySwitchの端子がひん曲がっているやつはピンで直しながらはめ込んでいきく。&lt;/p&gt;
&lt;p&gt;真ん中の1 or 2 keyがえらべるところはPCBにはんだ付けするまでswitchがスライドするので注意。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2019-01-14-planck/planck-half.jpg&quot; title=&quot;半分まではめ込んだ&quot; alt=&quot;半分まではめ込んだ&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;全部はめ込んだ痕でSwitch Plateの裏表があるっぽいことに気づく。裏側のほうがピカピカしてる。でも傷が多いので今のままで行こうと決定&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;Soldering&quot; href=&quot;#Soldering&quot;&gt;Soldering&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;マスクを着用。&lt;/p&gt;
&lt;p&gt;今回ハンダゴテを新調した。白光のいいやつで温度調節ができる。調べた感じだとkeyboardのPCBにはんだ付けする最適温度が350とのことなので、それがえらべるのが良い。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2019-01-14-planck/planck-solders.jpg&quot; title=&quot;ハンダゴテ比較&quot; alt=&quot;ハンダゴテ比較&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;ギターの配線用に使ってた旧・ハンダゴテとは随分と違う...&lt;/p&gt;
&lt;p&gt;黙々とはんだ付けする。格子状に並んでいるので非常に楽。いやハンダゴテが良いモノだからなのかも。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2019-01-14-planck/planck-soldering.jpg&quot; title=&quot;作業中&quot; alt=&quot;作業中&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;はんだ付け完了したのがこちら。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2019-01-14-planck/planck-soldered.jpg&quot; title=&quot;はんだ付け完了&quot; alt=&quot;はんだ付け完了&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;ところどころ熱で弾けたであろうヤニが付いてるので、組込前に掃除にした。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;keycap-&quot; href=&quot;#keycap-&quot;&gt;keycapはめ込み&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;今回keycapはセットで買えたXDAのやつにした。もちろん印字なんかは不要。&lt;/p&gt;
&lt;p&gt;作業中の写真なし。無念の撮り忘れ😭&lt;/p&gt;
&lt;p&gt;完成！&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2019-01-14-planck/planck-complete.jpg&quot; title=&quot;美しい完成品&quot; alt=&quot;美しい完成品&quot; loading=&quot;lazy&quot; /&gt;&lt;/p&gt;
&lt;hr/&gt;&lt;p&gt;...最後のfirmwareのビルドのところがログに残ってないのだけど、Ergodox EZのキーマップをビルドするDockerでできてたような気がする。firmwareも書き込み済み。&lt;/p&gt;
&lt;p&gt;当時使ってたPCではプログラミングしなくなったのと、改めてQMK firmwareのdocument見たらbuild toolsんとこの記事が変わってるので、今度環境構築がてら再確認してfirmwareのとこだけ新しく書こうと思ってる(作業中)。&lt;/p&gt;
&lt;p&gt;わたしのkeymapのrepo(&lt;a href=&quot;https://github.com/krymtkts/qmk_firmware&quot; title=&quot;krymtkts/qmk_firmware&quot;&gt;krymtkts/qmk_firmware&lt;/a&gt;)は「デフォのキーマップをコピった」的なコミットを最後に止まってるので、旧PCに遺物が残されてそう😅&lt;/p&gt;
&lt;p&gt;去年はWSLで書き込む方法が確か使えてたはずだけど今は非推奨になってて、MSYS2を使う方法が主流になった？？？謎い🤔&lt;/p&gt;
&lt;p&gt;にしてもや、この文章を認めるためにOLKBのページを久しぶりに見たが、今のPCBはrevision.6で、hot swappableなkey switch、接続はUSB Type-Cという進化っぷりに驚きを隠せない😰わたしのはrev.5かそれ以前(忘れた)&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Mon, 14 Jan 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-01-10-make-blog-with-clojure.html</guid><link>https://krymtkts.github.io/posts/2019-01-10-make-blog-with-clojure.html</link><title>Clojureでブログを作った</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;このブログはClojure製の静的サイトジェネレータ&lt;a href=&quot;http://cryogenweb.org/&quot; title=&quot;Cryogen&quot;&gt;Cryogen&lt;/a&gt;で作った。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;動機&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;現在有給消化中のため暇である。プログラマ的暇潰しが必要だったのだが、ブログを作るのはそれなりに楽しめそうな気がした。&lt;/p&gt;
&lt;p&gt;あと、過去にブログサービスを使ってたときブログが長続きしなかった理由に、わたしは物書きじゃあないので簡単にブログが書けるとかいう部分が琴線に触れない、というようなものが根底にあるような気もする🤔&lt;/p&gt;
&lt;p&gt;自分で作るならその心配はない。&lt;/p&gt;
&lt;p&gt;ついでに折角GitHubのアカウントも持ってるので、GitHub Pagesを使わない手はない。blogのコードをrepoに登録しておけば芝生も青々としてええな！的な。&lt;/p&gt;
&lt;p&gt;また別の観点としてブログサービスを選ぶとなった場合、書く記事の内容が技術的なものだったり単なる趣味の話だったり内容がブレると思うので、利用規約に触れて垢バンされるようなサービスは選び辛い。ちょうど良い選択かも知れない。&lt;/p&gt;
&lt;p&gt;そこで今回はブログ自体を自分で作ってしまおうと決めた。&lt;/p&gt;
&lt;p&gt;因みにClojureを選んだのは個人的な好みである。&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;静的サイトジェネレータの選定&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;普通にググって調べようと思ってたけど、いまはこんなのクソ便利なんがあるのね...→&lt;a href=&quot;https://www.staticgen.com/&quot; title=&quot;StaticGen&quot;&gt;StaticGen&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;LanguageをClojureにしたら3個hitしたのでそれぞれ見てみた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cryogen-project/cryogen&quot; title=&quot;Cryogen&quot;&gt;Cryogen&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/liquidz/misaki&quot; title=&quot;Misaki&quot;&gt;Misaki&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/hashobject/perun&quot; title=&quot;Perun&quot;&gt;Perun&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Misakiは永らくメンテされてないからなし。
CryogenもPerunも、検索したら日本語の情報にhitするのでやりがいに違いはなさそう。
単純に⭐が多いのとBootを使ったことがないというだけの理由で&lt;a href=&quot;https://github.com/cryogen-project/cryogen&quot; title=&quot;Cryogen&quot;&gt;Cryogen&lt;/a&gt;を使うことにした。&lt;/p&gt;
&lt;p&gt;(後知恵だが、ここはもっと慎重に考えた方が良かった)&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;-a-href-https-github-com-cryogen-project-cryogen-title-Cryogen-Cryogen-a-&quot; href=&quot;#-a-href-https-github-com-cryogen-project-cryogen-title-Cryogen-Cryogen-a-&quot;&gt;&lt;a href=&quot;https://github.com/cryogen-project/cryogen&quot; title=&quot;Cryogen&quot;&gt;Cryogen&lt;/a&gt;を使ってぶろぐを作ろうぜ&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;ドキュメントが充実してるので、書いたてることに従うだけで簡単にできた。&lt;/p&gt;
&lt;p&gt;出来上がったコードはこちら→&lt;a href=&quot;https://github.com/krymtkts/blog-cryogen&quot; title=&quot;My personal blog project&quot;&gt;My personal blog project&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;以降に記すコマンド例はPowerShellで実行したものである。筆者はWindows10ユーザなので。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;手始めに&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;Leiningenでテンプレートを作成する。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;lein new cryogen blog&lt;br /&gt;Retrieving cryogen/lein&lt;span class=&quot;hljs-literal&quot;&gt;-template&lt;/span&gt;/&lt;span class=&quot;hljs-number&quot;&gt;0.3&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;/lein&lt;span class=&quot;hljs-literal&quot;&gt;-template-0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;3.7&lt;/span&gt;.pom from clojars&lt;br /&gt;Retrieving leinjacker/leinjacker/&lt;span class=&quot;hljs-number&quot;&gt;0.4&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;/leinjacker&lt;span class=&quot;hljs-literal&quot;&gt;-0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;4.2&lt;/span&gt;.pom from clojars&lt;br /&gt;Retrieving org/clojure/core.contracts/&lt;span class=&quot;hljs-number&quot;&gt;0.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;/core.contracts&lt;span class=&quot;hljs-literal&quot;&gt;-0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0.1&lt;/span&gt;.pom from central&lt;br /&gt;Retrieving org/clojure/pom.contrib/&lt;span class=&quot;hljs-number&quot;&gt;0.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;26&lt;/span&gt;/pom.contrib&lt;span class=&quot;hljs-literal&quot;&gt;-0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0.26&lt;/span&gt;.pom from central&lt;br /&gt;Retrieving org/clojure/core.unify/&lt;span class=&quot;hljs-number&quot;&gt;0.5&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;/core.unify&lt;span class=&quot;hljs-literal&quot;&gt;-0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;5.3&lt;/span&gt;.pom from central&lt;br /&gt;Retrieving cryogen/lein&lt;span class=&quot;hljs-literal&quot;&gt;-template&lt;/span&gt;/&lt;span class=&quot;hljs-number&quot;&gt;0.3&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;/lein&lt;span class=&quot;hljs-literal&quot;&gt;-template-0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;3.7&lt;/span&gt;.jar from clojars&lt;br /&gt;Retrieving org/clojure/core.contracts/&lt;span class=&quot;hljs-number&quot;&gt;0.0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;/core.contracts&lt;span class=&quot;hljs-literal&quot;&gt;-0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0.1&lt;/span&gt;.jar from central&lt;br /&gt;Retrieving org/clojure/core.unify/&lt;span class=&quot;hljs-number&quot;&gt;0.5&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;/core.unify&lt;span class=&quot;hljs-literal&quot;&gt;-0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;5.3&lt;/span&gt;.jar from central&lt;br /&gt;Retrieving org/clojure/clojure/&lt;span class=&quot;hljs-number&quot;&gt;1.4&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;/clojure&lt;span class=&quot;hljs-literal&quot;&gt;-1&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;4.0&lt;/span&gt;.jar from central&lt;br /&gt;Retrieving leinjacker/leinjacker/&lt;span class=&quot;hljs-number&quot;&gt;0.4&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;/leinjacker&lt;span class=&quot;hljs-literal&quot;&gt;-0&lt;/span&gt;.&lt;span class=&quot;hljs-number&quot;&gt;4.2&lt;/span&gt;.jar from clojars&lt;br /&gt;Generating fresh &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;lein new&amp;#x27;&lt;/span&gt; Cryogen project.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ブログを動かしてみよう&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;lein ring server
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ブラウザに表示された。OK👍&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;コンテンツを整理する&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;わたしの場合はMarkdownで書くのでAsciiDocのディレクトリは消してしまう。サーバ起動中にこれをやると例外が発生する、止めてからやるのが良いだろう。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Remove-Item&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Recurse&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; ./resources/templates/ascii
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;あとsampleで置いてあるpostやaboutを自分用に書き換えるなど。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;-&quot; href=&quot;#-&quot;&gt;テーマを作る&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;themeはデフォで&lt;code&gt;blue&lt;/code&gt;, &lt;code&gt;blue_centered&lt;/code&gt;, &lt;code&gt;lotus&lt;/code&gt;, &lt;code&gt;nucleus&lt;/code&gt;の4種類置いてある。&lt;code&gt;lotus&lt;/code&gt;を使うとエラーになったけど、これを直すのが目的じゃないので無視した🙈&lt;/p&gt;
&lt;p&gt;自分用のテーマとしては何が良いかな？と検討して、お気に入りのSolarizedにしようと決めた。terminalやeditorはSolarized darkを使っているが、ブログはlightでやろうと思う。syntax highlightingについてはいつも通りのdarkを採用することにした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ethanschoonover.com/solarized/&quot; title=&quot;Solarized&quot;&gt;Solarized&lt;/a&gt;を参考に自分でthemeを作る。元にするのは&lt;code&gt;blue_centered&lt;/code&gt;にした。ブラウザの開発者ツールで見てみてもレスポンシブデザインになってたし、cssのコード量も少なくてシンプルなのがいい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;resources/templates/themes&lt;/code&gt;にファイル名&lt;code&gt;solarized_light&lt;/code&gt;でコピって書き換える。&lt;/p&gt;
&lt;p&gt;基本は書いたあるルールに沿うけど一部それとなく変える。カラーコードの編集はsassにしたら楽だろうけどコピった元はそうじゃないので、該当する箇所を書き換えるだけに留めた。&lt;/p&gt;
&lt;p&gt;Cryogenのsyntax highlightingは&lt;code&gt;highlight.js&lt;/code&gt;が採用されている。
デフォの24種だと使わないやつもいるので削って、使いそうな言語を足したものを&lt;a href=&quot;https://highlightjs.org/download/&quot; title=&quot;highlight.js&quot;&gt;highlight.js&lt;/a&gt;で作ってダウンロードする。
これは手動でダウンロードして、デフォの&lt;code&gt;highlight.pack.js&lt;/code&gt;に上書きした。&lt;/p&gt;
&lt;p&gt;スタイルは&lt;code&gt;base.html&lt;/code&gt;で&lt;code&gt;default&lt;/code&gt;が指定されているので&lt;code&gt;solarized_dark&lt;/code&gt;を選ぶ。ついでにhighlight.jsのversionも9.7から9.13.1へ上げちゃう。&lt;/p&gt;
&lt;p&gt;404 Page not foundのときのページがどうやって表示されるのかわからなかったが、GitHub Pagesの機能で提供されるルールに従えば良い様子。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://help.github.com/articles/creating-a-custom-404-page-for-your-github-pages-site/&quot; title=&quot;Customizing GitHub Pages / Creating a custom 404 page for your GitHub Pages site&quot;&gt;Customizing GitHub Pages / Creating a custom 404 page for your GitHub Pages site&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;デフォの404ページのスタイルが他のページとぜんぜん違うので、スタイルに合わせておいた。&lt;/p&gt;
&lt;p&gt;ページが縦に長くなって垂直スクロールバーが出るとコンテンツのズレが生じるのだけど、これ多分bootstrapに起因する問題か🤔悩ましいが一旦そのままに。&lt;/p&gt;
&lt;p&gt;これでおおよそのデザイン面は完成した。&lt;/p&gt;
&lt;p&gt;作業中のコードは一旦BitBucketのprivate repoにブチ込んでおいたのだけど、GitHubの無償アカウントでもprivate repoが使えるようになって分ける理由がなくなってしまった...まあよし。&lt;/p&gt;
&lt;p&gt;あと、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bootstrap3から4に上げたい&lt;/li&gt;&lt;li&gt;Google Analytics&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;など残しているが、一旦はコンテンツの公開を優先して後回しにする予定。&lt;/p&gt;
&lt;h5 &gt;&lt;a name=&quot;GitHub-Pages-&quot; href=&quot;#GitHub-Pages-&quot;&gt;GitHub Pagesにうｐる&lt;/a&gt;&lt;/h5&gt;&lt;p&gt;&lt;a href=&quot;https://pages.github.com/&quot; title=&quot;GitHub Pages&quot;&gt;GitHub Pages&lt;/a&gt;の説明と&lt;a href=&quot;http://cryogenweb.org/docs/deploying-to-github-pages.html&quot; title=&quot;Cryogen - GitHub Pages&quot;&gt;Cryogen - GitHub Pages&lt;/a&gt;を見たらできる。&lt;/p&gt;
&lt;p&gt;作るのはユーザーのpageなので、まず&lt;code&gt;krymtkts.github.io&lt;/code&gt;のrepoを作る。
中身は空で。Licenseの選択もなし。&lt;/p&gt;
&lt;p&gt;Cryogenのドキュメントに従い、&lt;code&gt;config.edn&lt;/code&gt;の&lt;code&gt;blog-prefix&lt;/code&gt;キーの値は空にする。&lt;/p&gt;
&lt;p&gt;あとはCryogenが出力した&lt;code&gt;resource/public&lt;/code&gt;を先程作ったrepoのmasterブランチにpushするのみ。&lt;/p&gt;
&lt;p&gt;この出力先&lt;code&gt;resource/public&lt;/code&gt;を変更する方法がわからなかったので、&lt;code&gt;krymtkts.github.io&lt;/code&gt;という名前のシンボリックリンクを作って、あたかもそういう名前のフォルダをGitで管理してる感を醸し出して茶を濁した。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;New-Item&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Value&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;.\blog\resources\public\&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;./&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;krymtkts.github.io&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;-ItemType&lt;/span&gt; SymbolicLink&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; krymtkts.github.io&lt;br /&gt;git init&lt;br /&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;# krymtkts.github.io&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; README.md&lt;br /&gt;git add README.md&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;First commit&amp;quot;&lt;/span&gt;&lt;br /&gt;git add .&lt;br /&gt;git commit &lt;span class=&quot;hljs-literal&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Add contents&amp;#x27;&lt;/span&gt;&lt;br /&gt;git remote add origin git@github.com:krymtkts/krymtkts.github.io.git&lt;br /&gt;git push &lt;span class=&quot;hljs-literal&quot;&gt;-u&lt;/span&gt; origin master
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;これでわたしのブログがpublishされたのであった🎉&lt;/p&gt;
&lt;p&gt;めでたしめでたし...&lt;/p&gt;
&lt;h4 &gt;&lt;a name=&quot;To-be-continued&quot; href=&quot;#To-be-continued&quot;&gt;To be continued&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;で終わらなかった。&lt;/p&gt;
&lt;p&gt;これを作りきって、急激にCryogenに興味がなくなってしまった。&lt;/p&gt;
&lt;p&gt;結局の所、テンプレートエンジンにSelmerを使ってることで、HTMLやスタイルの編集自体にClojure感の薄さがあってなんか楽しみがないのかなと。最初から予想できそうな結果やけどな🤔&lt;/p&gt;
&lt;p&gt;コンテンツ自体はMarkdownで書くし可搬性があるので記事の更新はしつつ、次段階としてPerunで作り直してみようと思う。&lt;/p&gt;
&lt;p&gt;破壊と創造こそが人類の本質ですね(違う&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Thu, 10 Jan 2019 09:00:00 +0900</pubDate></item><item><guid>https://krymtkts.github.io/posts/2019-01-08-first-post.html</guid><link>https://krymtkts.github.io/posts/2019-01-08-first-post.html</link><title>ブログを始めた</title><description>&lt;div class=&quot;section&quot;&gt;&lt;p&gt;ブログを始めてみた。&lt;/p&gt;
&lt;p&gt;自分のメモを取るのには永らくEvernoteを使ってるのだけど、そういったものをまとめてアウトプットできるものが欲しいなー、と常々思ってた。&lt;/p&gt;
&lt;p&gt;ただ過去にブログサービスを使ってたときは大して続かなく、また中等半端にやめかねないなという気持ちもあったのだが、去年アラフォーになったことであるし、不惑ということで一歩踏み出してみたのである。&lt;/p&gt;
&lt;p&gt;自己紹介は&lt;a href=&quot;/pages/about.html&quot; title=&quot;About Me&quot;&gt;About Me&lt;/a&gt;を参照いただきたく🙇&lt;/p&gt;
&lt;p&gt;当面は自分の作業ログを清書したものを書いていくつもりやけど、もし誰かの目に留まって、何かの役に立ったなら幸いである。&lt;/p&gt;
&lt;/div&gt;</description><pubDate>Tue, 08 Jan 2019 09:00:00 +0900</pubDate></item></channel></rss>