OmniAICreator/Qiita-1.07M huggingface dataset:
[Windows] [PowerToys] ショートカットで画像から文字列抽出

# 紹介したいこと
- 2022年9月ころからPowerToysに**ショートカット一発で画像から文字抽出**する機能(**Text Extractor**)が入ったのを知ってますか？
- テレワークでの共有画面、ブラウザで視聴している動画の**画像から簡易的に文字列抽出したい需要**はあるのではないかと思いました。
- 環境が条件に合えばすぐに導入できるので、皆さんの**時短**につながるのではと思い紹介させてください。

# インストール方法
Microsoft Storeから検索してインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/775f5134-d687-843f-d595-b02686b489f0.png)
# 操作方法
［Windows］＋［Shift］＋［T］キーを押すと、デスクトップ全体が暗転して矩形選択モードになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/a70eaeed-653d-dc2d-e71e-0a7f6f4607b3.png)

［Windows］＋［Shift］＋［S］キーで指定した範囲のビットマップをとるのと似てますね・・😮

例えば、上図のところを選択するとクリップボードに文字列が抽出されて利用できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/8ced826a-8dd0-a520-d87c-ce4e64085681.png)
クリップボードの文字列をメモ帳に張り付けた例
日本語もちゃんと抽出できてる😀

# 前提条件
ある程度、最近のWindowsのバージョンでないとインストールできないので、そこはご注意ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/d83206b6-bbbf-d976-4a75-a4c497513298.png)
(2022/11/13時点)

https://learn.microsoft.com/ja-jp/windows/powertoys/install

# 参考

わかりやすい。

https://twitter.com/biccameraP/status/1583654625760235522

https://learn.microsoft.com/ja-jp/windows/powertoys/

https://forest.watch.impress.co.jp/docs/news/1437924.html

https://learn.microsoft.com/ja-jp/uwp/api/windows.media.ocr?view=winrt-22621

Joe Finney のText-Grabがもとになってるようです。処理のソースコードみたかったらこのリンクをチェック。
https://github.com/TheJoeFin/Text-Grab

PowerToysには他にも機能があるので、興味ありましたら設定の画面から機能を確認してみることをお勧めします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/51e06830-6628-16e1-30cd-1931d01221b9.png)

https://youtu.be/0U9SnmgLClo

https://support.microsoft.com/ja-jp/office/%E7%94%BB%E5%83%8F%E3%81%8B%E3%82%89%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B-3c1bb58d-2c59-4bc0-b04a-a671a6868fd7
AndroidのランダムMacアドレスにやられた話

今日、息子から・・・

> スマホのWi-Fi調子悪いんだけどさー
> 5Ghzだと切れることがあるんで、2.4Ghzにしたいんだけど、つながらないんだよねー
> つながるようにして。

と言われ、
そんなことあるかい！確かに家のWi-FiルータはMacアドレスフィルタリングしているけど、Macアドレスの登録は、5Ghz帯も2.4GHz帯も同じなんだから、片方でつながって、片方でつながらないことなんてないだろ？パスワード間違ってるんじゃないのか？

と思って、色々調べてみると、息子のAndroid11にはランダムMacアドレスってのがあって、デフォルトでこれが有効になっているらしい。

調べてみるとAndroid10からの機能で、おそらくプライバシー保護、Macアドレスで端末/個人を特定されるのを防ぐのが目的だと思われる。自分のスマホはAndroid9なので、気が付かなかった。
[進むMACアドレスのランダム化。影響や切り替え方法をご紹介](https://www.ntt-bp.net/column/blog/2021/12/post-64.html#:~:text=Wi%2DFi%E3%82%B9%E3%83%9D%E3%83%83%E3%83%88%E4%BB%A5%E5%A4%96%E3%81%8B%E3%82%89%E8%A8%AD%E5%AE%9A%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%97%E3%81%9F%E3%81%84%E5%A0%B4%E5%90%88&text=%E2%91%A0%E3%80%8C%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%80%8D%E7%94%BB%E9%9D%A2%E3%81%8B%E3%82%89%E3%80%8C,%E3%81%AE%E5%88%87%E3%82%8A%E6%9B%BF%E3%81%88%E3%81%AF%E5%AE%8C%E4%BA%86%E3%81%A7%E3%81%99%E3%80%82)

![Screenshot_20221113_142240.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933408/efbe3943-61b7-429d-9948-a0a294fc9c86.png)

しかし、これは公衆Wi-Fiとかはいいけど、家庭用Wi-FiでMacアドレスフィルタリングを使っている場合は困る。家庭用Wi-Fiは誰でもつなぎに来られては困るので、Macアドレスフィルタリングを使わざるを得ない。

Macアドレスフィルタリング機能自体が、無意味なんじゃないか？(いくらでも偽装できる)という話もあるが・・・家庭用は一応ないよりはあったほうがいいと思う。

ランダムMacアドレスを使うか、固定(そのデバイスの)Macアドレスを使うかはWi-Fiの接続単位で設定できる。
ランダムMacアドレスを選ぶと、Wi-Fiの接続毎にバラバラのMacアドレスなのか？、同じMacアドレスなのか？は不明。

うーん・・・こんなのがデフォルトになると困るなー
DOMの習得までの道のり(1/n)_やりたいことまとめ

## この記事の趣旨
近頃DOMの勉強をしています。
うまくやりたいことが実現できないため、
備忘を兼ねて道のりや手段についてメモをとっていこうと思います。
最終的には解決策のみをまとめたページを作成予定です。

## 解きたい課題
DOMを利用して、`<div>`の中に`<p>`で並んだ要素を、
`<ul><li>`を用いたリスト形式に変換したい

```html:before
<!DOCTYPE html>
<html lang="ja">
  <head>
    <title>TEST</title>
  </head>
  <body>
    <div id="foods">
      <p>にんじん</p>
      <p>じゃがいも</p>
      <p>たまねぎ</p>
    </div>
    <button onclick="dispList()">リスト形式で表示</button>
    <script type="text/javascript" src="./scripts/test.js"></script>
  </body>
</html>
```

```html:after
<!DOCTYPE html>
<html lang="ja">
  <head>
    <title>TEST</title>
  </head>
  <body>
    <!-- ここから -->
    <ul id="foods">
      <li>にんじん</li>
      <li>じゃがいも</li>
      <li>たまねぎ</li>
    </ul>
    <!-- ここまでの変更 -->
    <button onclick="dispList()">リスト形式で表示</button>
    <script type="text/javascript" src="./scripts/test.js"></script>
  </body>
</html>
```

<!-- ここからCodePen -->

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="xxzdMWK" data-user="SayCheeese" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/SayCheeese/pen/xxzdMWK">
  FoodDOM_test01</a> by SayCheeese (<a href="https://codepen.io/SayCheeese">@SayCheeese</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

<!-- ここからCodePen After -->

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="OJEmdEj" data-user="SayCheeese" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/SayCheeese/pen/OJEmdEj">
  FoodDOM_test02</a> by SayCheeese (<a href="https://codepen.io/SayCheeese">@SayCheeese</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

<!-- CodePen ここまで/ -->


## 戦略
1. `<button>`が`onclick`状態になったら以下が行われるようにする
1. HTMLの`<div id="foods">`要素を抽出
1. 子要素`<p>`のテキストを配列fdTxtArrayとして抽出
`["にんじん", "じゃがいも", "たまねぎ"]`
1. fdTxtArrayの各要素を`<li>`に収納
`<li>にんじん</li> <li>じゃがいも</li> <li>たまねぎ</li>`
1. `<li>`要素すべてを`<ul>`に格納
1. `<div>`要素の前に`<ul>`要素をいれる
1. `<ul>`要素に`<id="foods">`をつける
1. `<div>`要素の削除

## 進める上で心がけること
- jsにおいて、`const`, `let`は使用しても、`var`は使わない。

https://qiita.com/cheez921/items/7b57835cb76e70dd0fc4

- 出てきたら追記
ざっくりAlpine.js

「最近プロジェクトで使用しているlivewireについての記事でも書くか〜」っと思ったが、その前にalpine.jsについて書いた方が順序として綺麗だなと思ったので、軽く書いておく。
公式サイトは[こちら](https://alpinejs.dev/)（日本語訳はないけどシンプルなので労せず読めるはず）

# 概論
シンプルにしたVueのようなもの。
公式サイトにあるモダンなjQueryって言い方がしっくりくる

# 使い方
```index.html
    <script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
```
これだけでOK
あとはx-dataでデータを定義して、そのコンポーネント内でなんやかんやしていく。
使用頻度高いなと感じたのは以下。

## x-text
・タグ内に定義したデータを出力する。
・""内にjsを書ける。
・{}とかで出力されるわけではない。
```index.html
<div x-data="{ message: 'Alpineによるデータ定義' }">
    <p x-text="message"></p> <!-- Alpineによるデータ定義と出力 -->
    <p>{message}</p> <!-- こっちは{message}となる -->
    <p x-text="10 * 10"></p> <!-- 100と出力 -->
</div>
```

## x-on(@)
・イベントリスナ
```index.html
<div x-data="{count:0}">
    <p x-text="count"></p>
    <button x-on:click="count++">カウントアップ</button>
    <button @click="count++">こっちも同じ</button>
</div>
```

# x-if,x-show
・表示/非表示切り替え
・x-ifは要素自体を、x-showは表示/非表示のみ切り替える
・x-ifはtemplateタグ内でのみ使用可能
```index.html
<div x-data="{display:true}">
    <template x-if="display">
        <p>ifによる表示/非表示</p>
    </template>
    <p x-show="display">showによる表示/非表示</p>
    <button @click="display = !display">切り替え</button>
</div>
```

## x-for
・色々操作する場合はkeyが必要（例みたいに表示だけなら不要）
・使用する場合はtemplateタグ
```index.html
<div x-data="{datas:
    [
        {
            id:1,
            name:'ichiro',
        },
        {
            id:2,
            name:'ziro',
        },
        {
            id:3,
            name:'saburo',
        },
    ]
}">
    <template x-for="data in datas" :key="data.id">
        <p x-text="data.name"></p>
    </template>
</div>
```

## $el
・その要素自身を表す($thisみたいなもの)
```index.html
<div x-data="{message:''}">
    <input @input="message = $el.value">
    <p x-text="message"></p><!-- inputの値と連動 -->
</div>
```

## $store
・グローバルな値を扱う
```index.html
<div x-init="$store.message = '初期メッセージ'"></div>
<div x-data>
    <p x-text="$store.message"></p> <!-- 別コンポーネントで定義しているが、グローバルなので出力 -->
</div>
```
Shellのエラー処理

シンプルに1行でエラー処理ができたのでメモ

下記のような構文を用いる

```shell
{エラー判定するコマンド} && {成功時に実行するコマンド} || {エラー時に実行するコマンド}

```

```shell
test 0 -gt 30 && echo 正しい || echo 間違い
処理結果: 間違い
```

```shell
test 100 -gt 30 && echo 正しい || echo 間違い
処理結果: 正しい
```
フォーマットに苦戦した話

ブック名を付けようとしたときに手こずった話。
次月のブックを作りたかったので、
```VBA
Format(Val(月) + 1, "00")
```
みたいな感じで作ろうとしたんですが、Formatの中身がStringでないと"04"や"08"の形にならず、この"月"の型がLongだったため、試行錯誤しても中々解に辿り着けませんでした。
関数に使う型の確認は大事ですよ、というお話でした。
Windwos10でAndroidエミュレータを起動するとWindows10がBSODでお亡くなりなって困った話

ここ数ヶ月前から、Android+kotlinでアプリ開発を初めたのですが、使用しているノートPCでAndroidエミュレータを起動すると数分で固まり、WindwosがBSOD(Blue screen of death)でお亡くなりになって困ったお話。
![IMG_20220718_081832.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933408/c0ec3abb-b6cf-f8ea-2c4b-6e4c8bb904d4.jpeg)

使用環境は以下の通り
- 機種: HP ENVY x360 Convertible 13-ay0xxx
- CPU: AMD Ryzen 7 4700U with Radeon Graphics 2000MHz
- Memory: 16GB
- SSD: SAMSUNG MZVLB512HB!-000H1
- BIOS Vender Insyde
- BIOS Revision: F.13
- Windows: Windows 10 Home 21H2 OSビルド 19044.2006
- AndroidStudio: Dolphin 2021.3.1

どうやら、初期のRyzenの特有の問題らしいという情報もちらほら見られる、BIOS(UEFI)を最新版にアップデートすると治るかもしれないというので、BIOSをF.21にアップデート。

**しかし、状況変わらず。1分と持たない・・・** ＿|￣|○

う・・・む、これじゃ、Android開発に使えない。実機をUSB/Wi-Fiで接続する分には問題ないので、やはりAndroidエミュレータ(QEMU)と、このノートPCでは相性が悪いと諦めるしかないのか・・・

[Nox Player](https://jp.bignox.com/?utm_source=smartaws)も同じようにBSODでWindows10がお亡くなりになる。

と思ったところで、有用な情報が、
[Androidエミュレーター「Nox」　起動時エラーについて](http://nox-azu.blog.jp/archives/5194779.html)

ここにある
**②「Avastのハードウェアによる仮想化支援機能を利用する」が有効になっている**

たまたま、AVASTを使っているのを思い出し(我が家は全般的にスマホも含めてAVASTを使っている)この仮想化支援機能を無効にしてみました。

そうすると、Windows10が落ちなくなりました。 **＼(^o^)／**

しばらく、これで使ってみようと思っています。Ryzen CPUで同様に、BSODでお悩みの方は試してみてください。
（しかし、AVASTの仮想化支援機能って何なんだ・・・？）
PowerShellのスクリプトテンプレート


PowerShellのスクリプトをいっぱい書くことになったので、
ログ出力とかのテンプレートを固めておきたいと思って投稿しました。

フォルダ構成はこんな感じ ※logフォルダは自動で作成されるので手で作る必要はないです。
相対パスで動くようにしているので、基本どこに置いても動作すると思います。
※バッチファイルについては[こちら](https://qiita.com/sakekasunuts/items/d80ecae428866f9acdaa)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604770/5e3e5c2a-e466-fc5f-4c8c-fe3037b1314d.png)

実行すると↓みたいなlogが作成される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604770/2587d6fe-28b4-b86e-0122-af51ed54a4e1.png)

中身はこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604770/641dffb5-46ef-959a-7ce1-2524c24a59c6.png)

## ソースコード
```PowerShell
#==============日時・ログファイル定義==============
$Date = Get-Date -Format yyyy_MM_dd
$Time = Get-Date -Format HH_mm_ss
$Now = "$Date`_$Time"
$Name_ps1 = [System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath)
$Log_Ps1 = "$PSScriptRoot\log\$Name_ps1`_$Now`_$env:COMPUTERNAME`_$env:USERNAME`.log"

#==============スクリプト終了定義==============
Function Finish_Ps1{
    Write-Host (Get-Date -Format HH_mm_ss) "`t**********スクリプトを終了します**********"
    Stop-Transcript
    Exit
}

#==============スクリプト開始==============
Start-Transcript $Log_Ps1
Write-Host (Get-Date -Format HH_mm_ss) "`t**********スクリプトを開始します**********"
Write-Host ""

#==============処理Aを記述==============
Write-Host (Get-Date -Format HH_mm_ss) "`t▼▼▼▼▼▼▼▼▼▼処理Aを開始します▼▼▼▼▼▼▼▼▼▼"
Write-Host (Get-Date -Format HH_mm_ss) "`t==========A-1実行中=========="
Write-Host (Get-Date -Format HH_mm_ss) "`t==========A-2実行中=========="
Write-Host (Get-Date -Format HH_mm_ss) "`t==========A-3実行中=========="
Write-Host (Get-Date -Format HH_mm_ss) "`t▲▲▲▲▲▲▲▲▲▲処理Aを終了します▲▲▲▲▲▲▲▲▲▲"
Write-Host ""

#==============処理Bを記述==============
Write-Host (Get-Date -Format HH_mm_ss) "`t▼▼▼▼▼▼▼▼▼▼処理Bを開始します▼▼▼▼▼▼▼▼▼▼"
Write-Host (Get-Date -Format HH_mm_ss) "`t==========B-1実行中=========="
Write-Host (Get-Date -Format HH_mm_ss) "`t==========B-2実行中=========="
Write-Host (Get-Date -Format HH_mm_ss) "`t==========B-3実行中=========="
Write-Host (Get-Date -Format HH_mm_ss) "`t▲▲▲▲▲▲▲▲▲▲処理Bを終了します▲▲▲▲▲▲▲▲▲▲`n"
Write-Host ""

#==============スクリプト終了==============
Finish_Ps1

```
原神でDUALSHOCK4のBluetooth接続がたまーに切れる時の対応策

:::note warn
細かい動作検証していないので、あくまで参考情報です。
:::

# 現象

5分～10分くらいの間隔で ↓ こうなる。

>コントローラーの接続に異常が発生しました、接続し直すかゲームを再起動してください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/f5086c19-8f52-b734-ab2e-ea630984f84f.png)

急いでDUALSHOCK4のPSボタン押すと3～5秒くらいで再接続できてゲーム復旧できる。
（ゲームやOSをシャットダウンまではしなくて大丈夫）

環境はざっくり ↓ こう。

Windows 10 Home 21H1 19043.2130
DUALSHOCK 4 CUH-ZCT2J （PCとはBluetoothで接続してる）
原神 3.2

# 発生する条件っぽいもの

発生した時は毎回 ↓ こんなふうに起動してた。

1. DUALSHOCK4の電源入れ忘れた（Bluetooth接続してない）状態で原神起動。
1. 原神起動後からDUALSHOCK4の電源ONしてWindows10と接続。
1.  ↓ ゲーム内の設定でデバイスを変更。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/c816ff4e-6520-ba18-9a74-7e82c925f05e.png)

逆に原神 **起動前** にDUALSHOCK4の電源入れて、Windows10と接続しておけば発生しなかった。

ゲーム始める前にちょっと気をつければいい話なので **ままええわ** で流した。
【JavaScript】文字列を配列に変換する方法

# 文字列→配列

1文字区切りで配列にする

```js
const string = 'hoge';

// split
string.split('');

// spread
[...string];

// arrayfrom
Array.from(string);

// match
string.match(/./g);

// 出力:
// ['h', 'o', 'g', 'e']
```


## 参考
https://www.samanthaming.com/tidbits/83-4-ways-to-convert-string-to-character-array/
絶対覚えたい便利なショートカットキー集

みんな大好きコピー＆ペースト。
通称「コピペ」

コードを書く時も使いますし、資料を作る時にも使います。
パソコン作業の基礎中の基礎です。
そして、毎日の業務の中で必ずと言っていいほど使います。

**「毎日ある同じ作業をできるだけ手間をなくしたい」** と思うのが、システムエンジニアの思考です。
そういう時に覚えたいのが、ショートカットキーです。

今回は業務でよく使うものをまとめています。
※Macのショートカットキーを書いてるので、Windowsの時は「command」の代わりに「ctrl」にすれば、だいたいできると思います。

## 絶対覚えたい便利なショートカットキー集

### 全選択：command + A
全選択。

### 処理を戻す：command + Z
処理を戻す。
間違えて消した時、間違えて上書きした時に、一個ずつ戻れて便利です。

### 選択範囲をコピー：command + C
選択範囲をコピー。

### ペースト：command + V
ペースト。

### 装飾なしペースト：command + shift + V
装飾なしペースト。

メールのコピーや資料作成の時に使います。
ただペーストすると、スタイルもペーストされてしまうことがあります。

### 拡大：command + +
拡大。
ブラウザとvscodeでよく使います。

### 縮小：command + -
縮小。
ブラウザとvscodeでよく使います。

### 拡大・縮小をリセットします：command + 0 （google chrome）
拡大・縮小をリセットします。
Google Chrome限定かもしれません。たまに使います。

### アプリの強制終了：command + Q
アプリの強制終了。

### 画面キャブチャ（全体）：command + shift + 3
画面キャブチャ（全体）。

資料作っていると、画面撮ること多いですよね。
Windowsでは、PrintScreenキー使いますね。（バージョンやFnキー使ったりしますね、詳しくは調べてみてください...）

### 画面キャプチャ（範囲選択）：command + shift + 4
画面キャプチャ（範囲選択）。

資料作っていると、画面撮ること多いです。（2回目）
Windowsでは、アプリ「Snipping Tool」使います。

### 開発者ツールの表示：command + shift + C （google chrome）
開発者ツールの表示。

他にも開くショートカットキーありますが、これは画面の要素にカーソル当てて探せるので好きで使っています。
Webアプリの開発ではよく画面のデータがどうなっているか確認すること多いですし。

## さいごに
画面キャプチャや開発ツールなどできることを覚えておくと、時間短縮できます。
装飾なしペーストができる「command + shift + V」は、大好きです。
JavaScriptでアップロードされたファイルの拡張子を取得する

ファイルが選択されたら以下のコードを実行します。
```js
const filename = 'foo.jpg';
const pos = filename.lastIndexOf('.');
if (pos === -1) {
    console.log('拡張子がありません');
} else {
    console.log('拡張子がありました');
    console.log('拡張子=>', filename.slice(pos + 1));
};
```


## 参考
https://blog.ver001.com/javascript-get-extension/

## 追記
下にコメントいただいた方法も、ぜひ参考にしてください。
ラグランジュ双対問題の強双対性について幾何学的にみてみよう！

# はじめに
最適制御や機械学習をやっていれば、主問題とラグランジュ双対問題を聞いたことがあると思います。最適化の本を調べると、本の通りに式変形をすると確かにラグランジュ双対問題を導出できるし、なぜか強双対性とかいって、主問題とラグランジュ双対問題の最適解が一致するとか言われて、頭の中が？？？と混乱したことはないでしょうか？標示関数を使って説明されても、なんかイメージが湧かない方もいらっしゃるかもしれません。とはいえ、下の記事はわかりやすく説明されているので紹介しておきます。

https://qiita.com/birdwatcher/items/b23209f06177373c6df4

最適化の本や上の記事で、そっと本や記事を閉じてしまった方を対象に直観的にわかるようにゆるふわに解説します。

# ラグランジュ双対問題を幾何学的に理解する。

以下の主問題を考えます。

```math
\begin{eqnarray}
\min_x &  &f(\boldsymbol{x}) \\

\mathrm{s.t.} & &g(\boldsymbol{x})\leq 0\\
              & & \boldsymbol{x}\in X
\end{eqnarray}
```

このときのラグランジュ双対問題は、$\theta(u):=\inf_{\boldsymbol{x}\in X}\lbrace f(\boldsymbol{x})+ug(\boldsymbol{x})\rbrace$とおけば、


```math
\begin{eqnarray}
\max_u &  &\theta(u) \\

\mathrm{s.t.} & &u\geq 0\\
\end{eqnarray}
```

ここの式変形を幾何学的に理解していきましょう！

凸最適化問題について考えると、主問題とラグランジュ双対問題は下図の関係にあります。$(x_0,y_0)$は主問題の最適解を表します。凸最適化問題では、主問題とラグランジュ双対問題の最適解は一致する(**強双対性**)ことがわかります。ラグランジュ双対問題を考えるとき、傾き$u\geq0$の条件をつけないといけないことに注意します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139678/a63c396b-4635-d443-0fd7-cb7066a95d87.png)

図の見方について説明します。
Step1で何をしているかというと、$\theta(u):=\inf_{\boldsymbol{x}\in X}\lbrace f(\boldsymbol{x})+ug(\boldsymbol{x})\rbrace$を考えています。集合$G$の点と交わるように、傾き$u$を固定して切片$\alpha^\prime$を最小化しているんですね。切片$\alpha^\prime$は、$\theta(u)$に相当しています。ただし$u$は$u\geq0$の範囲であらゆる値をとる変数であることに注意です。

Step2で何をしているかというと、ラグランジュ双対問題を考えています。集合$G$の点と交わるように、傾き$u$について切片$\alpha$を最大化しているんですね。Step1の条件を満足する必要があるのでStep2では支持平面のみ考えればよいです。切片$\alpha$は、ラグランジュ双対問題の目的関数に相当します。この直線$y+u_0x=\alpha_0$と集合$G$の交わる点が、最適解$(x_0,y_0)$となります。つまり、主問題とラグランジュ双対問題の最適解は一致することがわかります。

$u<0$の場合どうなるの？という疑問は出てくると思います。$u<0$の場合について考えると、主問題とラグランジュ双対問題の解が一致しないことが分かります。さらに、ラグランジュ双対問題の解は、$g(\boldsymbol{x})\leq0$を満たしていないことが分かります。これは困りました。やはり$u\geq0$という条件は必要なようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139678/e08fd39c-07b9-045f-f908-c008d55e9aaf.png)

# ラグランジュ双対問題の導出

標示関数を用いてラグランジュ双対問題を導出する際、$u<0$の場合を式変形の中で除外できるようにラグランジュ関数$L(\boldsymbol{x},u)$を設計する必要があります。試しに、こんな定義はどうでしょう？

```math
L(\boldsymbol{x},u)=
\left\{
\begin{array}
af(\boldsymbol{x})+ug(\boldsymbol{x}) & u\geq0\\
-\infty      & u<0
\end{array}
\right.
```

あとは、機械的にラグランジュ双対問題を求めるだけです。$\theta(u) = \inf_{\boldsymbol{x}\in X}L(\boldsymbol{x},u)$とおけば、ラグランジュ双対問題は下式です。

```math
\max_u \theta(u) \\
```

制約式がないように見えますが、$u<0$のとき、$\theta(u)=-\infty$となるため、$u\geq0$という制約条件を含んでいることが分かります。

```math
\begin{eqnarray}
\max_u &  &\theta(u) \\

\mathrm{s.t.} & &u\geq 0\\
\end{eqnarray}
```

機械的に主問題からラグランジュ双対問題を導出できました。めでたしめでたし。

# おわりに
本記事では厳密な議論を避け直観的に説明しました。本当はよくないことです。この記事でラグランジュ双対問題について直観的に分かった方は、ぜひ参考文献を購入することを検討してみてください！

以下は、線形計画を通してラグランジュ双対問題を理解しようという記事です。

https://mathlog.info/articles/582

KKT条件については下記の記事を参照ください。

https://qiita.com/momo10/items/69fc831fa4b793b5c4ee

ラグランジュ双対問題とKKT条件が理解出来たら、Pythonで線形計画を実装してみましょう。

https://qiita.com/momo10/items/824c2fd8a0f432a676f4

# 参考文献
- 凸解析と最適化理論、田中謙輔、牧野書店
- 非線形最適化の基礎、福島雅夫、朝倉書店
- Convex Optimization、Stephen Boyd、Lieven Vandenberghe、CAMBRIDGE UNIVERSITY PRRESS
Knowledge Article で画像を追加する


# 既知の問題

+ [【修正なし】Images added to a Rich Text Area field on a Knowledge Article are not visible in Lightning Experience](https://trailblazer.salesforce.com/issues_view?id=a1p3A000000n4lBQAQ)
ナレッジ記事のリッチテキストエリア項目に追加された画像が Lightning Experience に表示されない

リッチ テキスト エリア項目の項目名 (API 名) が 27 文字を超えると、ナレッジ記事のリッチ テキスト エリア項目に追加された概要画像が Lightning Experience に表示されません。

回避策
リッチ テキスト エリア フィールド (API) の名前を、名前の末尾に追加される「__c」を含めて最大 27 文字に短縮します。

+[【レビュー中】Feature Request: Add ability to select existing Salesforce Files for images in Lightning Knowledge articles]（）https://trailblazer.salesforce.com/issues_view?Id=a1p3A000000mDYk

機能のリクエスト: Lightning Knowledge 記事の画像用に既存の Salesforce ファイルを選択する機能を追加する

Lightning で作成されたナレッジ記事のリッチ テキスト エリア項目に追加された画像は、作成者のみに表示され
ます

回避策
現時点ではありません。

Spring '18 リリースより前に Salesforce Files から Lightning の記事に追加された既存の画像は、ユーザーのローカルマシンにダウンロードまたは保存してから、RTE 画像ツールの唯一の利用可能なオプションを使用してファイルを選択することで再追加または置換する必要があります。ユーザーのローカル マシンから。

更新
2019 年 9 月 16 日: この既知の問題は、IdeaExchange のアイデアに相当する Salesforce 内部の機能要求または作業項目に変換されました。この機能の現在の機能が将来のリリースで改善されるように、アイデアを作成または宣伝することを検討してください。

# 質問

+ [インポートした記事の画像を更新するには?](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000JedxkSAB)

公開された記事の画像を直接更新することはできません。最初に記事の新しいドラフト バージョンを作成し、次に画像を更新してから記事を再度公開する必要があります。 

公開された記事を一括更新する場合。必ず  

公開された記事の新しいドラフト バージョンを作成します。
必要な変更を加えて、記事の下書きバージョンを更新します。
記事を再度公開します。
 

一括更新された Salesforce 公開ナレッジ記事については、以下の記事を参照してください。

https://sfcrunch.com/mass-updated-salesforce-published-knowledge-articles/  

データローダでリッチテキストフィールドに画像を一括インポートする方法については、以下の記事を参照してください。

https://help.salesforce.com/s/articleView?id=000383208&type=1

目標を達成するには、上記の両方の記事を組み合わせる必要があります。 

+ [画像付きのナレッジ記事の作成](https://salesforce.stackexchange.com/questions/101386/creating-knowledge-articles-with-images)

REST API を介して別のシステムから多くの記事をインポートしようとしています。追加の（バイナリ）リソースなしで、なんとか単純なものを作成できました。それは正常に動作します。

しかし、バイナリ データをどのように扱うかはあまり明確ではありません。Base64 データの形式で画像を指定しようとしましdata-uriたが、この場合、リッチ テキスト フィールドのデフォルトの 32K 制限をすぐに超えてしまいます。128K まで拡張できますが、それでも低すぎます。

これまでのところ、バイナリ添付ファイルをアップロードするためのこのリンクしか見つかりませんでしたが、私の場合に適用できるかどうかは明確ではありません。 http://blog.enree.co/2013/01/salesforce-apex-post-mutipartform-data.html

ところで、最初は細工された CSV ファイルを介して一括インポートも試みましたが、この場合、既存の記事 (私の場合は要求されています) を更新できなかったため、REST の方法を使用しました。
PlatformIOからM5Paperに書き込むと起動しなくなって困った

久々にM5Paperで遊ぼうと思ったらつまづいたので、対処法を共有できればと思います。

# 前提条件
M5Paper: v1.0 (古いやつ)
環境：VSCode上のPlatformIO(Core 6.1.5, Home 3.4.3)
やったこと： GitHubのFactoryTest[^1]をcloneしてPlatformIOで書き込み

# 状況
・コンパイル、書き込みは成功するが、M5Paperが起動しなくなる。
・画面は下図の初期画面が点滅する。
![IMG_3981.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467266/3adb917c-4228-837d-2456-4c44f3562d7a.jpeg)

・シリアルモニタでは以下が繰り返し表示される。

```
M5EPD initializing...[  2643][D][M5EPD_Driver.cpp:68] begin(): Init SUCCESS.
[  3270][E][esp32-hal-cpu.c:110] addApbChangeCallback(): duplicate func=0x400fc9c8 arg=0x3ffbde2c
[  3416][W][sd_diskio.cpp:186] sdCommand(): token error [0] 0x12
[  3417][W][sd_diskio.cpp:516] ff_sd_initialize(): GO_IDLE_STATE failed
[  3417][E][sd_diskio.cpp:802] sdcard_mount(): f_mount failed: (3) The physical drive cannot work
[  3435][D][GT911.cpp:35] begin(): GT911: Initialization
[  3435][I][esp32-hal-i2c.c:75] i2cInit(): Initialising I2C Master: sda=21 scl=22 freq=100000
[     7][D][esp32-hal-cpu.c:244] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz
[   456][I][esp32-hal-psram.c:96] psramInit(): PSRAM enabled
```

# 原因、対処法
画面でもシリアルモニタでもわかる通り、FactoryTestのブートに失敗しているみたいです。
シリアルモニタの出力でググってみると、M5Stack Communityに対処法がありました[^2]。

どうやらPlatformIOのM5Paper(の中身のESP32)用のフレームワーク(framework-arduinoespressif32)の最新バージョン(v.5.2.0)では、FactoryTestが動かないようです。以前のバージョン(v.5.1.1以下)のフレームワークなら動くらしい。
なので、platformio.iniのplatformで読み込むものをv5.1.1に変更すればいいわけです。
GitHubからクローンした状態では以下のようになっています。

```
platform = espressif32
```

espressif32とだけ書いた場合、自動で最新版を使うようなので、

```
platform = espressif32@5.1.1
```
と@以後にバージョンを追記すればいいです。

フレームワークとArduinoのバージョンが合わないでエラーが出ることはよくありますが、この場合はなまじコンパイルと書き込みが通ってしまうだけ面倒ですね。

# ちなみに
今回の問題はPlatformIOのフレームワークの問題なので、FactoryTestに限らず、PlarformIOからM5Paperに書き込む場合すべてで発生しますが、同様の対処法で解決します。

PlatformIO以外で書き込んだ場合はうまくいくようで、M5burnerからのFactoryTestの書き込みを試してみたところ、正常に起動しました。初期状態に戻したいだけならM5burnerを使った方がいいかもしれません。

最初に書いたように僕は古いM5Paper(v.1.0)を使っています。M5Paperの新しいバージョン(v.1.1)では状況が違う可能性があるので注意してください。

ちなみに、のちなみにですが、FactoryTestを書き込めたのはいいものの、以前(2年前くらい)では読み込んでくれたSDカードを認識してくれませんでした。


[^1]: https://github.com/m5stack/M5Paper_FactoryTest
[^2]: https://community.m5stack.com/topic/4700/m5paper-build-factory-test-from-github/2
Rocky Linux 8.5で "dnf --releasever" すると404エラー

解決策まで調べきれてないのだけど、時間がないので確認した範囲についてメモ。

# 現象

AWS EC2に、[Rocky Linuxのクラウドイメージページ](https://rockylinux.org/ja/cloud-images)で確認したRocky Linux 8のAMI ID（ `ap-northeast-1` 用の `ami-0ddb05e945a674cf5` ）でインスタンスをデプロイすると、Rocky Linux 8.5が構成される。

```
[root tmp]# cat /etc/redhat-release
Rocky Linux release 8.5 (Green Obsidian)
```

この環境で `dnf --releasever=8.5` で何かしらインストールしようとすると、404 not foundエラーになる。

```
[root tmp]# dnf --releasever=8.5 -y install zip
Rocky Linux 8.5 - AppStream                                                                                                                                                       4.9 kB/s |  15 kB     00:02
Errors during downloading metadata for repository 'appstream':
  - Status code: 404 for https://mirrors.rockylinux.org/mirrorlist?arch=x86_64&repo=AppStream-8.5 (IP: 151.101.54.132)
Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: Status code: 404 for https://mirrors.rockylinux.org/mirrorlist?arch=x86_64&repo=AppStream-8.5 (IP: 151.101.54.132)
```

# 調査と考察

404を返している https://mirrors.rockylinux.org/mirrorlist?arch=x86_64&repo=AppStream-8.5 のエラー画面を見ると、以下のように有効な `repo` と `arch` の組合せが一覧表示される。

```
# repo = AppStream-8.5 arch = x86_64 error: invalid repo or arch
# following repositories are available:
# repo=rocky-AppStream-8.6&arch=aarch64
# repo=rocky-AppStream-8.6&arch=x86_64
:
```

ここからすると、2つ問題が考えられそう。

1. リポジトリ名は `AppStream-` ではなく `rocky-AppStream-` で始まる必要がありそう。
2. そうだとしても `rocky-AppStream-8.5` はないので、8.6か9を指定する必要がありそう。

## リポジトリ名は `rocky-AppStream-` で始まる必要がありそう。

下記リンク先の投稿を見つけた。多分同じ問題を議論していて、AzureイメージのStockでは `/etc/yum.repos.d/` 以下の `Rocky-AppStream.repoyum.repo` 等で `rocky-AppStream-` になっているらしい。

* [Mirrorlist repo name mismatch? - General - Rocky Linux Forum](https://forums.rockylinux.org/t/mirrorlist-repo-name-mismatch/6303)

ただし「ProComputers RockyLinux-8.6-x86_64-Minimal-8GiB-HVM-」をサブスクライブしてデプロイしたところ、 `/etc/yum.repos.d/` 以下の `Rocky-AppStream.repoyum.repo` ではリポジトリ名は `AppStream-` で始まる記述のままになっていた。

```
root tmp]# cat /etc/redhat-release
Rocky Linux release 8.6 (Green Obsidian)
[root tmp]# cat /etc/yum.repos.d/Rocky-AppStream.repo
# （コメント行略）
[appstream]
name=Rocky Linux $releasever - AppStream
mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=AppStream-$releasever
#（以下略）
```

こちらの環境ではエラーにならないので、もしかしたらどちらでもいいのかもしれない。

## `rocky-AppStream-8.5` はないので、8.6か9を指定する必要がありそう。

こちらは、Rocky Linux8.5ってリポジトリ提供されていないのかなというところなのだけど、よくわからない（私がRHELにもRockyLinuxにも曚い）。

「なぜRHELにもRockyLinuxにも曚いくせに8.6使わないの」「奇数マイナーバージョン（≒開発版）使っておいて自力で問題解消できませんとかどうなの」と言われると一言もないのだけど、あえて言わせてもらうとなんでRockyLinuxプロジェクト公式のクラウドイメージは8.5なんですかね（ **個人の意見です** ）？上記の通りProComputersによるRockyLinux 8.6のイメージ使えば問題起きないので、8.5使わせるRockyLinuxプロジェクトが（以下割愛、**個人の意見です** ）。

# 終わりに

RHELにもRockyLinuxにも曚いのに8.5使ってごめんなさい。もしなにか解決策ご存じの方おいででしたら、コメントいただけると嬉しいです。本当に困ってます…。
【Chrome拡張V3】犬、猫がマウスを追いかけてくる拡張機能をリリースしました。

# はじめに
会社の同期と一緒に何か作ってみたいね、という話になり手始めにリリースまでやってみました。
昔(v2の頃？)触ったことがあったのですが、(v3？になり)結構変わっているようで色々調べ直すところから始めたので、私たちが実装したベースで内容を備忘録として残します。
折角なのでリリースした拡張機能について。実装する上で苦労した点も少し触れます。

# 拡張機能概要
まず先に機能概要について書きます。
最初はマウスについてこずフラフラしていますが、餌をあげることで少しずつ懐いてついてくるようになります。餌をあげることでウン〇コをするので片づける必要があります。(私が描いた)下手なドット絵ですがちょっとした癒しになればと思っています。

https://chrome.google.com/webstore/detail/petkeeper/hahaifmfkjnkeafjalilpfnogcppkiba?hl=ja&authuser=1

# Chrome拡張V3について
## manifest.json
以下、私たちが実装した`manifest.json`です。v2の時と比べると色々変わっているので、これをv3のひな型として使用していただけるかもしれません。

```
{
  "manifest_version": 3,
  "name": "petKeeper",
  "version": "1.0",
  "action": {
    "default_title": "petKeeper",
    "default_icon": "img/icon.png"
  },
  "icons": {
    "16": "img/icon.png",
    "48": "img/icon.png",
    "128": "img/icon.png"
  },
  "background": {
    "service_worker": "js/background.js",
    "type": "module"
  },
  "commands": {
    "feed": {
      "suggested_key": {
        "default": "Ctrl+Shift+E",
        "mac": "Command+Shift+E"
      },
      "description": "餌を出す"
    }
  },
  "content_scripts": [
    {
      "run_at": "document_start",
      "matches": ["https://*/*"],
      "js": ["js/loader.js"],
      "css": ["css/animation.css"]
    }
  ],
  "permissions": ["background"],
  "web_accessible_resources": [
    {
      "resources": [
        "img/*/*.png",
        "css/*.css",
        "class/*.js",
        "js/*.js",
        "util/*.js"
      ],
      "matches": ["https://*/*"]
    }
  ]
}
```

主要なところについて説明します。

## background
文字通りバックグラウンドで動かす機能を設定します。DOMにアクセスできませんがAPIが利用でき、私たちが実装したようにコマンド入力を検知することができます。それを`content_script`に流す、ということができます。

## content_script
`background`とは異なりDOMアクセスが可能です。しかし利用できるAPIには制限がありますので記載した通り`background`から必要なAPI実行結果を連携する必要があります。

## web_accessible_resources
対象リソースとそれを利用することができるURLを指定します。
jsファイルや犬猫の画像、httpsであれば全URLで拡張機能が有効になるように`https://*/*`を設定しています。


# 苦労した点
## content_scriptの動作確認
私はいつも`console.log()`を埋め込んで動作確認をしていたのですがどこにそのログが表示されるのかわからずの状態でした。暫くはひたすら実際に触って動かして現象からコードの箇所を切り分けて…と動作検証をしていたのですが、あきらめ半分で`alert()`を埋め込んだところ動作したので、これを使って動作確認していました。

## パッケージされた画像を取得
第一の壁として、ドット絵を描いてパスもあっているはずなのにドット絵が表示されない問題にぶち当たりました。拡張機能特有の取り方があるようで`chrome.runtime.getURL(URL)`で実装していたのにも関わらず取得できませんでした。結局原因がわからないままですが、class対して以下のようにcssをあてることでも画像取得ができるようでした。

```css
.class {
    background-image: url(chrome-extension://__MSG_@@extension_id__/imapgePath)
}
```

# リリース
折角なのでリリースまでやってみました。(記憶違いかもしれませんが)昔調べたときはお金を払う必要なかった気がするのですが、今回リリースにあたって調べなおしてみると**5ドル**かかるようでした。
その際の手順に関しては[こちら](https://belltree.life/chrome-extension-release/)を参照ください。

**▼補足**
「プライバシーへの取り組み」欄はしっかり描いた方がよさそうです。審査に時間がかかり、リリースが遅くなる可能性があるようです。参考までに、私は以下のように記載しました。

**単一用途**
これはストア掲載情報の説明欄に記載した内容を記載しました。

**backgroundが必要な理由**

```
コマンドを入力して餌を配置するために必要です。
```

**ホスト権限が必要な理由**

```
chromeを使っている限りあらゆるドメインで使用して、楽しんでいただきたいためです。
```

# さいごに
少なくとも私担当分では大した実装はしていませんでしたが、拡張機能特有v2とv3の違いに苦しめられました。また、これを作成する案が出たときに深く考えていなかったのですが、身近な人でドット絵が描ける人がいなかったので自分たちで描く羽目になりました…。もう少しだけでも可愛く癒し成分を加えて描き上げたかったです…。

一人で色々勉強をしてアウトプットし続けることは難しいと思っていたため、一緒に開発を通して勉強していけるかどうか相性を確認する意味合いが強かった今回の同期との開発ですが、今後もやっていけそうに感じました。今は`React`、`Next.js`、`TypeScript`、`Docker`辺り一緒に勉強中です。

どなたかの参考になり、またインストールして楽しんでいただければ幸いです。
Group Edition と Professional Edition での Apex の使用

+ [Group Edition と Professional Edition での Apex の使用](https://developer.salesforce.com/docs/atlas.ja-jp.packagingGuide.meta/packagingGuide/dev_packages_apex_ge_pe.htm)

アプリケーションには、Apex で記述されたクラス、トリガ、メールサービスなどのビジネスロジックが含まれます。一般的な規則として、Apex は GE および PE ではサポートされておらず、これらのエディションでは実行できません。ただし、ISV アプリケーションの一部として開発され、管理パッケージに含まれている Apex は、デフォルトで Apex をサポートしていない GE および PE でも実行できます。

Salesforce の使用資格のあるパートナーであり、アプリケーションがセキュリティレビューに合格する必要があります。セキュリティレビューに合格すると、適切な権限は自動的に有効になります。

GE または PE で Apex を使用する場合、次のような重要な考慮事項があります。

+ GE および PE のユーザは、アプリケーションの Apex を作成または変更することはできません。可能なのは、既存の Apex を実行することのみです。
+ Apex コードが、DE、EE、UE、または PXE のみに存在する機能に依存する場合、アプリケーションのインストールは失敗します。
+ Apex メソッドを Web サービスとして公開する予定がある場合は、REST を使用します。SOAP Web サービスとして公開されている Apex クラスは、外部 Web アプリケーションから GE または PE に呼び出すことができません。
+ GE または PE では、Web サービスをコールアウトするために Apex を使用することができます。たとえば、外部 Web サービスに Web サービスコールアウトを行う予定がある場合、管理パッケージが承認されていれば、これらのクラスは GE または PE で機能します。

以下でもできないと議論されています。

+ [Professional Edition で apex クラスとトリガーを作成する方法](https://developer.salesforce.com/forums/?id=906F0000000BW0nIAG)
VisualStudioのショートカット

最近VisualStudioのショートカットを使うようになりました。
なんで今まで使わなかったのかと思うほど便利でした。。
良いものがあれば随時追加していきたいと思います。
※ちなみにVisualStudio2022、C#の場合です。

■便利ショートカット（個人的に）
・Ctrl+-：戻る
・Ctrl+Shift+-：進む
・Shift+F12：全ての参照を検索
・F8：検索結果進む
・Shift+F8：検索結果戻る
・Ctrl+R、Ctrl+G：不要なusingを消す。
※特にShift+F12は便利。今までgrepで検索してたので時間が掛かってました。。。

■あったらいいなと思う機能。
・沢山ソースを開いた状態で、自分が見たいソース以外を閉じる機能。
　なぜ必要かというと、沢山のソースの中から自分が見たいソースを調べるのは時間が掛かるからです。
　特にソースが数百個であり、同じ名前のソースが複数あるような環境です。
　いちいち自分が見たい処理のソースファイル名まで覚えてられないので、
　ソリューションツリーから開きなおすにしても時間が掛かるし、
　Ctrl+Tabで現在開いている一覧を見ても、即時にどれか探すのが大変なのです。
※同じような悩みを持っている方はいるのだろうか。。ブックマークを使うべきでしょうか。。
Javaで何か作ってみる(2022/11/12 Day23)

## 今日やった事
- 本当何もしなかった。
## 参考にしたもの
- 特になし。
## 所感
- 今日は本当何も勉強しなかった、ただただ反省。。。
## 明日の予定
- 引き続き、Mac環境でのJava開発環境構築を進めていく。
Javaで何か作ってみる(2022/11/11 Day22)

## 今日やった事
- Mac環境で、VSCodeでJavaプログラムが実行出来るように開発環境を構築した。
## 参考にしたもの
- [Visual Studio CodeでJavaプログラム開発環境構築](https://qiita.com/jsj05543/items/da54e5db258bc9d2538a)
- [Java環境構築(Adoptium(旧:AdoptOpenJDK))](https://zenn.dev/sasakiki/articles/54f68ee1576380)
## 所感
- やり方は、Windows環境と同じように、JDKインストール、VSCodeの拡張機能の追加、PATHの追加で出来ると思ったが、PATHの追加がうまくいかなかった。
## 明日の予定
- 明日以降も、Mac環境でのJava開発環境構築を進めて行こうと思う。
カスタマーユーザがメールアドレス自分で変更した際、ユーザ名も同様に変わる処理


+ [ExperienceCloud ユーザ情報の変更について](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000JeYh8SAF)


画面からユーザオブジェクトの特定の項目を修正した時にトリガーが発火しないことがあるようです。これに該当するとApexでも処理できないかもしれません。

Updates to certain user fields do not fire a trigger on the User object
以下はRESTful APIでユーザ名を更新しようとしていますが、うまく行かなかったみたいです。

[How to update User.username?](https://developer.salesforce.com/forums/?id=9062I000000g8UXQAY)


```
trigger UserTrigger on User (before update) {
    
    for(User newUser : Trigger.new){
        User oldUser = Trigger.oldMap.get(newUser.Id);
        if (oldUser != null && oldUser.Email != newUser.Email){
            newUser.Username = newUser.Email;
        }
    }

}
```
UnityとCRMの連携（その１）

## メタバースが流行ってきた

ここ3年間は３D開発に関わってみて、デジタルツインとかメタバースはコンテンツビジネスだなーと実感した次第です。コンテンツ、自分で作るか、ネット上に公開されている無償・有償のものを使うか。。。

建設業界では設計図の３D化が進んでいて、それらはBIM(Building Information Modeling)とかCIM(Construction Information Modeling)と呼ばれています。[Blender](https://www.blender.org/)には[IFC規格のBIMを読み込むためのプラグイン](https://blenderbim.org/)があり、私も、それを使って、ネット上に公開されていたBIMをBlenderへ読み込み、テキスチャーを貼り付けて、Unity向けにFBXでエキスポートしたりしています。

<img src="https://araobp.github.io/blender-3d/modified/FZK-Haus-Cycles/Camera10.png" width=500>

昔、私はIP電話の専門家であったこともあり、こういう３Dのコンテンツとコールセンター・コンタクトセンターを結びつけたら面白いだろうなと思いつつあります。15年前、セカンドライフが流行っていた頃も、セカンドライフとコンタクトセンターを連携させたら面白いだろうなと思っていました。

しかし、現在は電話よりもチャットの方が主流な時代なので、３DコンテンツをチャットやCRMと連携させてみたい。そこで、週末の趣味として、住宅のBIMをUnityへ取り込み、SalesforceのCRMと連携させる実験を行なっている最中です（開発中）。

https://github.com/araobp/unity-chat

## Salesforce Chat REST API

Salesforceには[Service Cloud(CRM)](https://www.salesforce.com/jp/products/service-cloud/overview/)という機能があり、IP電話システムと連携（CTI連携）させることで、コンタクトセンターとして機能させることが出来ます。今回は電話は必要なく（すなわちIP電話システムと連携する必要なく）、チャットだけあれば良いので、Service Cloudに含まれるチャット機能を使うことにします。

Salesforceは<a href="https://developer.salesforce.com/docs/atlas.ja-jp.live_agent_rest.meta/live_agent_rest/live_agent_rest_understanding_resources.htm">チャットのREST API</a>を公開しています。今回、このREST APIを活用し、3DコンテンツとCRMをチャット経由で連携させます。

週末の趣味の活動ですので、今回も、Salesforceの開発者エディション（無償）を使います。チャットのエージェントは２名までです。

## 実験結果

今回試作したUnityのアプリは、住宅の３Dモデル内を訪問者が歩き回るものです。Unityが提供している[First Person Character Controller](https://assetstore.unity.com/packages/essentials/starter-assets-first-person-character-controller-196525)を活用しました。WASDキーで移動し、マウス操作で視線（前進する方向）を変えることが出来ます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194351/3c6e4fa2-0815-68eb-c9f1-e65316024bdb.jpeg" width=500>

画面右側にuGUIでチャットウィンドーをつくりました。ここからSalesforceのService Cloud側にいるエージェントとチャットする想定です。チャットメッセージ入力時はWASD操作を行わない様、Tabキーで、WASD操作モードとメッセージ入力モードの切り替えが出来る様にしました。

Unityのエディター画面上でアプリを動作させ、SalesforceのService Cloud側にいるエージェントとチャットで会話できること確認できました。

## あったら良いと思った機能

Unity側アプリとSalesforce Service Cloud間で画面共有出来ると良いと思いました。以前、Unityが提供している[RenderStreamingを実験](https://github.com/araobp/unity-excavator/blob/master/doc/RenderStreaming.md)したことありますが、WebRTCを使って、３Dモデルの中で訪問者が見ている部分をエージェントと共有出来ると良いです。

こういうのは、多分、SalesforceのCTI連携機能を活用し、WebRTCのサービスを提供しているとこ(WebRTCのSaaS)と連携すれば実現出来るものなのかもしれません。

## その２へ続く

ここまでがその１。次に、Salesforceのオブジェクト(チャットのトランスクリプトやケース）と連携可能か実験してみたいです。ここがCRM連携の部分。その２へ続く。。。
Rubyで設定ファイル読み込み

# はじめに
Rubyで設定ファイルの読み込み方法を調べたので、そのメモ書きになります。
Docker上でのRailsサーバーを使用しています。

# 設定ファイル用意
今回はtest.confファイルを以下内容で用意します。
```
[api]
key = ABC
```

# Gemfile
Gemfileに以下を追加します。
```
group :development do
  gem 'inifile'　★追加
```

# イメージの再構築
```
docker-compose build --no-cache
```

# ソース
```
require "inifile"　★追記

class Search < ApplicationRecord
  def self.searchApi()
    ini = IniFile.load("setting.conf")　★追記
    searcher.key = ini["api"]["key"]　★追記
```

# 起動
```
docker-compose up -d
```

以上で、設定ファイルが読み込めるようになりました。
パワーポイントにPDFを貼り付けると、背景透明になってしまった時の対処法

作成し、配布したPDF資料の説明をパワーポイントで行う場合、PDFデータをそのままパワポに貼り付ける。

ただ、そうした場合、PDFデータが背景が透明になってパワーポイントの背景の色が写ったり、影をつけたいときに文字一つ一つについてしまうことがあった。

PDFを書き出しするときに背景をつけるなどできるかもしれないが、その資料を作成したのが自分でない場合、それもできない。


そのような時にPDFを編集するソフトで白色を追加できたのでメモ

https://helpx.adobe.com/jp/acrobat/using/add-backgrounds-pdfs.html

の通りにやればできた。
NetBSDの時間

NetBSDの時間管理はFreeBSDと同じでタイマー割り込みでhardclock()をよぶ仕組みでした。

またプロファイル用にstatclock()というのもあるようですが、プロファイルを使わなければダミーでも良さそうです。

これとは別にtcというのがあって、登録した関数でカウンター値を返すし仕組みです。FreeBSDにもあります。

Comcertoはたくさんタイマーがあるので、それぞれTimer0,Timer1,Timer2で実装してみました。

https://dmesgd.nycbug.org/index.cgi?do=view&id=6768

tcの周波数はAHBのクロックの165MHzでした。ストップウオッチで計って確認しました。

デフォルトではhardclock()は10ms毎に呼びます。

おそらくhardclockだけでもいけるけど、10ms単位での時間しか出なくなるのでtcが必要なようです。

tcのtc_get_timecountは0から0xffffffffの値を返すようにします。タイマーがデクリメントで動いている場合は否定(~)にして返します。

逆だと以下のメッセージが出るようです。

```
[   4.5773560] WARNING: negative runtime; monotonic clock has gone backwards
```

割り込みコントローラーの前にタイマーがattachされると割り込みが受けられなくなると思ったのですが、タイマーの初期化はすべてのデバイスのプローブが送ってからタイマーはcpu_initclocks()で行うようです。

armv7以降は標準でタイマーが入り、共通ルーチンがあるので、個別に作る必要はありません。

タイマーの制御はあまりないので、複数のタイマーを一つのデバイスで制御する事も出来ますし、それぞれのタイマーを別々のデバイスにすることもできます。
MySQLの基礎（名詞と略語）

データ：Data
データベース：DataBase（DB）
データベース管理システム：Database Management System（DBMS）
データベースシステム：DataBase System（DBS）
データ定義言語：DDL（Data Definition Language）→create, drop, alter...
データ操作言語：DML（Data Manipulation Language）⇨(insert, update, delete...
データベース問合せ言語：DQL（Data Query Language）(select...)
データ制御言語：DCL（Data Contorl Languagegrant, comit, rollback...
【M1 Mac対応】Keycloakをdocker composeで構築

[yamaday0u](https://twitter.com/yamaday0u)です。

以前、[Docker（docker compose）でKeycloak環境を構築](https://yamaday0u.net/2022/08/25/docker%ef%bc%88docker-compose%ef%bc%89%e3%81%a7keycloak%e7%92%b0%e5%a2%83%e3%82%92%e6%a7%8b%e7%af%89/)という記事を投稿しましたが、このとき紹介したdocker-compose.ymlファイルには2つの課題がありました。

それは次のとおりです。

- M1チップのMacBookでは動かせない
- データの永続化ができていない

今回はその2つの課題を克服したdocker-compose.ymlファイルを作成したので、皆さんに紹介します。

## docker-compose.ymlファイルの内容

以下のようにdocker-compose.ymlファイルを作成しました。このファイルはぼくのgithubでリポジトリでも公開していますので、そちらもご参照ください。

```docker-copose.yml
version: '3'
services:
  keycloak:
    image: sleighzy/keycloak:latest
    container_name: keycloak
    ports:
      - "4000:8080"
    volumes:
      - ./data:/opt/jboss/keycloak/standalone/data
    environment:
     KEYCLOAK_USER: admin
     KEYCLOAK_PASSWORD: ${KEYCLOAK_PASSWORD}
```
## どのように変わったか
### imageの変更

1つ目の変更点はimageです。

以前はjboss/keycloak:16.1.1というimageを使っていたのですが、こちらはM1チップのMacBookには対応していませんでした。

そこでM1チップのMacBookが使用しているarm64アーキテクチャに対応しているimageを探していたところ、[sleighzy/keycloak](https://hub.docker.com/r/sleighzy/keycloak)というimageを発見したので、これを採用しています。

ただ代わりに、**IntelチップのMacBookには非対応**となってしまっているので、該当する方はご注意ください。

### データの永続化の実装

2つ目の変更点はvolumesを追加した点です。

データの永続化を実装するため、[KeycloakをDocker Composeで動かすサンプルコード](https://zenn.dev/kazuma_r5/articles/d464cd0bf380da)という記事を参考にしました。

ここでとても一番苦労したのですが、使用しているimageが違うためか、コンテナ側でデータを保存している場所が異なっていたので、その場所を探すのに時間を要しました。

最終的にはSTACK OVERFLOWの[Docker-compose volume doesn't save state of container for Keycloak](https://stackoverflow.com/questions/59278955/docker-compose-volume-doesnt-save-state-of-container-for-keycloak)という質問に対する回答を参考にしてデータの保存場所を見つけ出しました。

データの永続化を実装したことにより、`docker-compose down`でimageやvolumeが削除されても、`docker compose up`で再びコンテナを生成したときでも前回まで保存されたデータを復元してくれるようになりました。
堅牢なNIFの書き方: パフォーマンスの高いフォールト・トレラント・システムのためのElixirとCの併用〜その3アサーションを積極的に書く

この記事は[「Elixir Advent Calendar 2022」](https://qiita.com/advent-calendar/2022/elixir)2日目の記事です．また，この内容の講演がElixirConf EU 2023にacceptされました．

https://www.elixirconf.eu/talks/how-to-describe-robust-nifs/

パフォーマンスを必要とするシステムを実装する場合，Elixir からよりパフォーマンスの高い C コードを呼び出すメカニズムである NIF を使用することがあります．NIF は，C を呼び出すもう 1 つのメカニズムである Port よりも優れたパフォーマンスを発揮します．ただし，NIF がクラッシュすると，Supervisor の制御下であっても，Erlang VM 全体が異常終了するという欠点があります．この欠陥は，フォールト・トレラント・システムを構築する際の大きな障害となります．

[1つ目のポイント](https://qiita.com/zacky1972/items/b1cbac9a4f31cd60800a)をhttps://qiita.com/zacky1972/items/b1cbac9a4f31cd60800a に
[2つ目のポイント](https://qiita.com/zacky1972/items/fa52c07532c8d4c704b0)をhttps://qiita.com/zacky1972/items/fa52c07532c8d4c704b0 に示しました．


この記事では，堅牢な NIF を説明する 3 つ目のポイントを示します．

* **暗黙の前提条件を指定するアサーションを作成し， `Supervisor` が処理する例外を発生させます．**

アサーション(表明)というのはご存知ですか？ たとえばCだと次のようなプログラムがあったとします．

```c:mysqrt.c
#include <math.h>
#include <assert.h>

double mysqrt(double a)
{
  assert(a >= 0);
  return sqrt(a);
}
```

引数`a`に負の値を与えると，次のように異常終了(abort)します．

```
Assertion failed: (a >= 0), function mysqrt, file mysqrt.c, line 6.
zsh: abort      ./a.out
```

アサーションを用いることで，意図しない入力を与えたり，意図しない出力結果が得られたりした時に，プログラムを強制停止することができます．このような入力や出力によって，破滅的な結果を招くことを予防することになります．

Cの場合にはアサーションによって異常終了するのみですが，Elixirの場合には `Supervisor` を用いることで，アサーションによって意図しない入出力を強制停止した後で，プロセスを再起動して再び入力を受け付けられるようにすることができます．Elixirにはこの `Supervisor` が存在することで，アサーションをより実用的に積極的に使うことができます．

NIFの場合には，`assert.h`を用いる代わりに，アサーションで表明する条件で分岐した後，条件に反する場合にはその2に書いた例外を発生させる方法で強制停止させます．たとえば次のようにします．

```c
#include <math.h>
#include <erl_nif.h>

static ERL_NIF_TERM mysqrt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
  if(argc != 1) {
    return enif_make_badarg(env);
  }

  double a;
  if(!enif_get_double(env, argv[0], &a)) {
    return enif_make_badarg(env);
  }
  
  // assert(a >= 0);
  if(!(a >= 0)) {
    ERL_NIF_TERM reason = enif_make_string(env, "Assertion failed: (a >= 0), function mysqrt", ERL_NIF_LATIN1);
    return enif_raise_exception(env, reason);
  }
  
  return enif_make_double(env, sqrt(a));
}

static ErlNifFunc nif_funcs[] =
{
    {"mysqrt", 1, mysqrt}
};

ERL_NIF_INIT(Elixir.MySqrt, nif_funcs, NULL, NULL, NULL, NULL)
```

いかがだったでしょうか？ 些細なことでも質問があれば，遠慮なくコメントしてください！
一時的に使用するファイル作成時の CRTPF と CRTDUPOBJ の使い分け

## はじめに

ワークファイルを QTEMP に作成する際等、`CRTPF`や`CRTDUPOBJ`を使用することが多々あるかと思います。

この記事では、一時的に使用するファイルを作成する際に`CRTPF`と`CRTDUPOBJ`それぞれのできる事／できない事をまとめました。


## `CRTPF`と`CRTDUPOBJ`の比較表

| 状況                                         | CRTPF | CRTDUPOBJ |
| -------------------------------------------- | ----- | --------- |
| データのコピー                               | ×     | ○         |
| 複数ファイル同時指定（ワイルドカードの使用） | ×     | ○ ※1      |
| ファイル未作成時に使用                       | ○     | ×         |

※1：ワイルドカードを使用すると、複製されるオブジェクトが入っているライブラリー（FROM ライブラリー）にライブラリーリストを指定することが不可となる。


## おわりに

役割として`CRTPF`：物理ファイル作成、`CRTDUPOBJ`：複製オブジェクト作成、ですので、`CRTDUPOBJ`を使用する際は必ずファイルが作成されている必要があります。
また、`CRTDUPOBJ`はワイルドカードを使用することで複数のファイルを同時に指定することができます。
但しワイルドカードを使用した場合、複製元のライブラリーにライブラリーリストを指定できないため注意が必要です。

参考になれば幸いです。最後までお読み頂きありがとうございます。
堅牢なNIFの書き方: パフォーマンスの高いフォールト・トレラント・システムのためのElixirとCの併用〜その2 慣習に従ったエラー処理を書く

この記事は[「Elixir Advent Calendar 2022」](https://qiita.com/advent-calendar/2022/elixir)1日目の記事です．また，この内容の講演がElixirConf EU 2023にacceptされました．

https://www.elixirconf.eu/talks/how-to-describe-robust-nifs/

パフォーマンスを必要とするシステムを実装する場合，Elixir からよりパフォーマンスの高い C コードを呼び出すメカニズムである NIF を使用することがあります．NIF は，C を呼び出すもう 1 つのメカニズムである Port よりも優れたパフォーマンスを発揮します．ただし，NIF がクラッシュすると，Supervisor の制御下であっても，Erlang VM 全体が異常終了するという欠点があります．この欠陥は，フォールト・トレラント・システムを構築する際の大きな障害となります．

1つ目のポイントを[その1](https://qiita.com/zacky1972/items/b1cbac9a4f31cd60800a) https://qiita.com/zacky1972/items/b1cbac9a4f31cd60800a で示しました．

この記事では，堅牢な NIF を説明する2つ目のポイントを示します．

* **一般的な慣習に従ってエラー処理を実行します．**

ここでいう「一般的な慣習」というのは[Elixir Schoolのエラーハンドリング](https://elixirschool.com/ja/lessons/intermediate/error_handling#一般的な規則-0)での説明に準拠します．すなわち次のようなルールです．

* 正常終了した時には `{:ok, result}`のような形式にする．ここで`result`には結果の値が入ります．
* 通常操作の一環でエラーを返す場合には `{:error, reason}`のような形式にする．ここで`reason`にはエラー理由がアトムや文字列などで入ります．
* 通常操作とは認められないようなエラーを返す場合には，例外をスローします．

NIFもこの一般的な慣習に従うべきだと言えます．

# `{:ok, result}`を返す場合のプログラム例

```c
  ERL_NIF_TERM result;
  result = ...;
  return enif_make_tuple2(env, enif_make_atom(env, "ok"), result);
```

# `{:error, reason}`を返す場合のプログラム例

```c
  ERL_NIF_TERM reason = enif_make_string(env, "reason", ERL_NIF_LATIN1);
  return enif_make_tuple2(env, enif_make_atom(env, "error"), reason);
```

* `"reason"` の箇所に実際のエラーメッセージを入れます．
* Elixir側では`{:error, reason}`の形で受け取れはするのですが，`reason`にはErlangの文字列(CharList `~c'reason'`)の形式で入っている点に注意してください．
* Elixirの文字列を渡すこともできなくはないのですが，少々煩雑なCコードになるので，Elixirの側で適切に処理することをお勧めします．

# 例外をスローする場合

## ArgumentErrorを返す場合

```c
  return enif_make_badarg(env);
```

* Elixir側では`ArgumentError`がスローされることになります．

```elixir
** (ArgumentError) argument error
```

## エラーメッセージ`reason`をつけて返す場合

```c
  ERL_NIF_TERM reason = enif_make_string(env, "reason", ERL_NIF_LATIN1);
  return enif_raise_exception(env, reason);
```

* `"reason"`には実際のエラー理由を入れます．
* Elixir側では`ErlangError`がスローされることになります．

```elixir
** (ErlangError) Erlang error: 'reason'
```

* `reason`にはErlangの文字列(CharList `~c'reason'`)の形式で入っている点に注意してください．
* Elixirの文字列を渡すこともできなくはないのですが，少々煩雑なCコードになるので，次のような感じでElixirの側で適切に処理することをお勧めします．(前述の`ArgumentError`を先に処理する点に注意してください)

```elixir
  try do
    case NifModule.nif_func() do # NIF関数の呼び出しを入れます
      {:ok, result} -> {:ok, result}
      {:error, reason} -> {:error, List.to_string(reason)}
    end 
  rescue
    e in ArgumentError -> raise e
    e in ErlangError -> raise ErlangError, message: List.to_string(e.original)
  end
```

いかがだったでしょうか？ [ではその3に続きます．](https://qiita.com/zacky1972/items/23736bc430286b29f3c5)
https://qiita.com/zacky1972/items/23736bc430286b29f3c5
堅牢なNIFの書き方: パフォーマンスの高いフォールト・トレラント・システムのためのElixirとCの併用〜その1 関数呼び出しそれぞれに条件分岐を設ける

この記事は[「Elixir Advent Calendar 2022」](https://qiita.com/advent-calendar/2022/elixir)1日目の記事です．また，この内容の講演がElixirConf EU 2023にacceptされました．

https://www.elixirconf.eu/talks/how-to-describe-robust-nifs/


パフォーマンスを必要とするシステムを実装する場合，Elixir からよりパフォーマンスの高い C コードを呼び出すメカニズムである NIF を使用することがあります．NIF は，C を呼び出すもう 1 つのメカニズムである Port よりも優れたパフォーマンスを発揮します．ただし，NIF がクラッシュすると，Supervisor の制御下であっても，Erlang VM 全体が異常終了するという欠点があります．この欠陥は，フォールト・トレラント・システムを構築する際の大きな障害となります．

この記事では，堅牢な NIF を説明する1つ目のポイントを示します．

* **不確実な値を返す可能性がある関数呼び出しそれぞれに対し条件分岐を適切に設定します．**

では，具体例を示していきましょう．

関数`foo`を呼び出した時，正常終了した時には戻り値としてポインタが返ってくるが，失敗した時には`NULL`ポインタが返ってくる場合を考えます．さらに`foo`の戻り値を使って別の関数`bar`を呼び出すようなシチュエーションを考えます．

安直には次のようにプログラミングしたくなるかもしれません．

```c
  v = bar(foo(a, b, c));
```

しかし，もし`bar`に`NULL`ポインタを与えた時にセグメンテーション・フォールトを発生することもありえます．この時には，たとえElixirがSupervisorを設定していたとしても，NIFがセグメンテーション・フォールトで異常終了することでElixirのVMごと落としてしまいます．

そこで，次のようにプログラミングすべきです．

```c
  w = foo(a, b, c);
  if(w == NULL) {
    // 異常終了した旨をElixirに通知する．例えば次のようなコード
    return enif_make_badarg(env);
  }
  v = bar(w);
```

関数`enif_make_badarg`については https://www.erlang.org/doc/man/erl_nif.html#enif_make_badarg をご覧ください．一般に引数が不正だった旨の例外を発生させるための関数です．

このようなことを一般化すると次のようになるというわけです．

* **不確実な値を返す可能性がある関数呼び出しそれぞれに対し条件分岐を適切に設定します．**

いかがだったでしょうか？ [ではその2に続きます．](https://qiita.com/zacky1972/items/fa52c07532c8d4c704b0) https://qiita.com/zacky1972/items/fa52c07532c8d4c704b0
Rubyの総和を求めるinject(:+)は罠があるからsumにして空のケースもテストしよう

### 最初に

コミット権限をもらったRubyライブラリが古く、
`sum`のない時代に書かれたライブラリで`inject(:+)`で総和が求められていました。[^1]

[^1]: `reduce`と`inject`はエイリアスなので、`reduce`でも全く一緒です。

```ruby
a = [1, 2, 3]
p a.inject(:+) # => 6
```

このように要素が数値の配列であれば、総和を求めることができます。[^2] 

[^2]: 要素が整数の場合、`inject(:+)`の内部では`Integer#+`が使われます。


### 問題点

しかし、空の配列で`inject(:+)`を使うと、`0`ではなく`nil`を返してきます。

```ruby
a = []
p a.inject(:+) # => nil
```

`inject`は総和を求めるのに限られたメソッドではないので、「要素に何もないから数値の総和を求めたいのだろう」と勝手に決めつけたりせず、`:+`を使うことなく淡々と`nil`を返してきます。

この挙動を知らずに書かれているコードであったため、そのライブラリはバグっていました。

### 解決策

空の配列に対する総和を`0`にしたければ、単純に`sum`に置き換えると良いでしょう。

```ruby
a = []
p a.sum # => 0
```

なお、小数計算では`inject`よりも`sum`の方が誤差が少ないらしいです。
今のバージョンで、数値の総和を計算をするなら`sum`一択でしょう。

### 備考: もしも古いバージョンに対応するなら

メンテナンス期間の終わっている古いv2.4未満の話になりますが、
もし`sum`の使えないバージョンに対応する必要があるなら、
「引数を2個にして、最初の引数を`0`を指定」する方法があります。

```ruby
a = []
p a.inject(0, :+) # => 0
```
簡単に言えば、最初の引数から演算します。
最初の引数は空配列のときに返される値になるだけでなく、
要素があれば第1引数も他の数と同じように最初に足されます。

詳しくは、Rubyリファレンスマニュアルを見たり、別途調べたください。

### 備考: 総和以外のケースでも

`inject(:+)`という総和のケースでは`sum`に置き換えられますが、
その他の演算に関しては特別なメソッドは用意されていないです。

その他の場合でも、引数は2個とる必要がないか検討した方が良いでしょう。

例えば、要素の全ての積をとる総乗のケースです。

```ruby
p [2, 4].inject(1, :*) # => 8  (= 1 x 2 x 4)
p [].inject(1, :*) # => 1  (= 1)
```

総乗のケースでは、最初の引数を`1`にします。
もし、最初の引数を`0`にすると`0`になにかけても`0`なので、
返り値が必ず`0`になってしまいます……。

```ruby
p [2, 3].inject(0, :*) # => 0 (= 0 * 2 * 3)
```

### 最後に

#### 本当に言いたい大事なこと

総和を求めるだけに限らない話ですが、要素が`0`のような何もないケースは一般的でない処理で、意識してないと試し忘れたり、テストを書かなかったりするかもしれません。

しかし、`0`のようなケースこそ、エッジケースなのでバグりやすいです。

要素数が0個、1個、複数個のパターンで、テストは書くなり試した方が良いでしょう。
Mac で Ansible を使って Azure をいじる環境を整えてみた

## 背景と目的

https://learn.microsoft.com/ja-jp/dotnet/architecture/cloud-native/infrastructure-as-code

https://learn.microsoft.com/ja-jp/devops/deliver/what-is-infrastructure-as-code

https://learn.microsoft.com/ja-JP/azure/architecture/framework/devops/automation-infrastructure

IaC コードとしてのインフラストラクチャですが、マイクロソフトのドキュメントの色んなところに説明が書かれている通り、沢山のメリットがあります。宣言型の IaC には、ARM テンプレート、Bicep、Terraform、Ansible 等があります。命令型の IaC には、Bash、PowerShell 等があり、CLI でも反復可能で信頼性の高い Azure リソース作成ができます。それなのに未だに Azure ポータルのスクショの手順書とパラメーターシートを見ながら構築する方法が多いなぁと個人的に感じます。私個人は普段は Azure CLI を使うことが多く、Terraform も必要に応じて使いますが、Ansible は Python との絡みや実行環境を整えるのに苦労するので、一つの例として Mac で Ansible を使って Azure をいじる環境を整えてみました。

## Ansible 実行環境の情報

```bash:bash
# Mac のバージョン
$ sw_vers
ProductName:            macOS
ProductVersion:         13.0.1
BuildVersion:           22A400

# Python のバージョン
$ python3 --version
Python 3.9.1

# PIP のバージョン
$ pip --version
pip 22.3.1 from /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/pip (python 3.9)
```

## Ansible と Azure の Python パッケージをインストール

```bash:bash
# Ansible をインストールします
pip install ansible

# Ansible のバージョンを確認します
ansible --version

ansible [core 2.13.6]

# azcollection をインストールします
ansible-galaxy collection install azure.azcollection

# Azure の Python パッケージをインストールします
pip install -r ~/.ansible/collections/ansible_collections/azure/azcollection/requirements-azure.txt
```

## Ansible で Azure リソースを作成できるか試してみる

```bash:bash
# 環境変数をセットします
export AZURE_AD_USER=$(az account show --query user.name -o tsv)
export AZURE_PASSWORD="<your password here>"
export AZURE_SUBSCRIPTION_ID=$(az account show --query id -o tsv)

# リソースグループを作成します
ansible localhost \
  -m azure.azcollection.azure_rm_resourcegroup \
  -a "name=ansible-rg location=japaneast"

# リソースグループが作成されたか確認します
az group show -n ansible-rg -o table

Location    Name
----------  ----------
japaneast   ansible-rg

# リソースグループを削除します
az group delete -n ansible-rg --yes
```

## 参考

https://learn.microsoft.com/ja-jp/azure/developer/ansible/install-on-linux-vm?tabs=azure-cli

https://galaxy.ansible.com/azure/azcollection

https://docs.ansible.com/ansible/latest/scenario_guides/guide_azure.html

https://learn.microsoft.com/ja-jp/azure/developer/ansible/vm-configure?tabs=ansible

https://docs.ansible.com/ansible/latest/collections/azure/azcollection/index.html#plugins-in-azure-azcollection