OmniAICreator/Qiita-1.07M huggingface dataset:
#Javascript #programming # 任意の1タブを1分毎に自動的にリロードする #Chrome 拡張機能

本内容を利用した場合の一切の責任を私は負いません。

# 機能
タイトル通り。
任意の1タブは、アクティブタブのことで、拡張機能を操作した時のタブ。
公式Appではないためか、拡張機能だけではService Workerがとめられてしまう。
デベロッパーツールと併用が必要です。

# バージョン
* OS
OS 名:                  Microsoft Windows 10 Home
OS バージョン:          10.0.19043 N/A ビルド 19043
システムの種類:         x64-based PC

* Chrome: バージョン: 100.0.4896.75（Official Build） （64 ビット）

# 準備
1. 下記のリポジトリをダウンロード
[https://github.com/github895439/KToolForChrome](https://github.com/github895439/KToolForChrome)

1. ダウンロードしたものを展開

1. Chromeの拡張機能を表示
Chromeの拡張機能の一覧が表示される。

1. 右上のデベロッパーモードをON
「パッケージ化されていない拡張機能を読み込む」ボタンが表示される。

1. 「パッケージ化されていない拡張機能を読み込む」で展開したトップフォルダ(KToolForChrome)を指定して読み込み
Chromeの拡張機能の一覧に本拡張機能が表示される。

1. 拡張機能一覧の本拡張機能に表示されているService Workerをクリック
デベロッパーツールが開き、Service Worker(background.js)のコンソールが表示される。
これを表示しておく必要があるため、自分は更にアイコン化している。

# 使い方
1. 自動的にリロードしたいタブを表示

1. ブラウザ右上の拡張機能アイコンを押下

1. ポップアップの「K Tool」を押下
自分は常時使うのでクリップを押して固定化しています。
固定化すると拡張機能アイコンの左に本拡張機能のアイコンが表示されます。

1. ポップアップの「automatic reload」チェックボックスにチェック入れ

1. 「SET」ボタンを押下
テキストボックスに「setting complete」と表示される。

1. 本拡張機能のアイコンを押下
ポップアップが閉じる。

# 補足
タブ識別はタブIDで行っているので同プロファイルの全Chromeウィンドウのタブが対象だと思います。
このため、一度設定するとそのタブがアクティブではなくても自動的にリロードされます。
任意の1タブとしたのは、サーバー、クライアント、回線負荷対策です。

# 主な履歴
YAMAHAルーターで特定機器の通信をキャプチャした（ポートミラーリングを用いてWiresharkでキャプチャする方法）

# Webカメラがどのくらい帯域を利用しているか知りたい
寝室の赤ちゃんを監視するため、[Webカメラ](https://store.google.com/jp/product/nest_cam_indoor?hl=ja)を導入しました。
カメラ自体はめっちゃ使いやすくて満足してるのですが、赤ちゃんが寝てる間など常につけっぱなしにしてるため「どのくらい家庭内LANの帯域を使ってるんだろう？」と気になったので、試してみたメモです。

# 用意したもの
- ポートミラーリング機能のついたルーター
    - 本記事はYAMAHA RTX830が対象
- USBの有線LANアダプタとLANケーブル
    - よくある[こういうの](https://www.amazon.co.jp/%E6%9C%89%E7%B7%9ALAN%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF%E3%83%BC-LUA4-U3-AGTE-WH-%E3%83%9B%E3%83%AF%E3%82%A4%E3%83%88Giga-%E3%80%90Nintendo-Switch%E5%8B%95%E4%BD%9C%E7%A2%BA%E8%AA%8D%E6%B8%88%E3%81%BF%E3%80%91/dp/B07KJ5NZN3/)
    - パケットを測定するPCとルーターをつなぐ
    - 測定マシンにLANポートが複数ついてればそれを使えばOK
- WIreshark
    - ネットワークアナライザー
    - 今回の使用Versionは3.6.3

# ルーターにポートミラーリングの設定をする
以下を参考に設定する。
http://www.rtpro.yamaha.co.jp/RT/manual/rt-common/setup/lan_port-mirroring.html

RTX830はLANポートが4つあり、今回は左から3つ（1,2,3ポート）の送受信パケットを一番右の4ポートでミラーリングするように設定した。

``` ssh
lan port-mirroring lan1 4 in 1 2 3 out 1 2 3
```

ちなみに以下のコマンドでポートミラーリングの解除が可能。

``` ssh
no lan port-mirroring lan1
```

# ミラーリングしたポートと測定PCをつなげる
RTX830の一番右側の4ポートと測定PCをLANケーブルでつなげる。

# Wiresharkでパケットキャプチャ
[Wireshark](https://www.wireshark.org/)はポピュラーなネットワークアナライザーです。

起動すると以下のような感じでどのアダプターをキャプチャするか聞かれるので、先ほどつなげたLANアダプタを選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22110/5e7a1396-a1d7-f9e3-02aa-b2f12f81ee62.png)

そうすると早速キャプチャが開始される。
正しくポートミラーリングの設定ができてればモリモリとパケットが増えていく様がうかがえるはず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22110/3ebf8bd4-ee62-a4b2-1ce1-701c66d99f6c.png)

止めたいときは赤い四角の停止ボタンで！

# データのフィルタリング
このままだとポート1,2,3が通信している内容がすべてキャプチャされて可視化している状態なので、目当ての機器のパケットだけ抽出したい。
機器に割り振られているIPアドレスかMACアドレスでフィルタする。

```
eth.addr == 00:00:5e:00:53:00
```

```
ip.addr == 192.0.2.1
```


# 解析
ここまでだけでも、Wiresharkに目当てのパケットがモリモリ溜まっていく様が見えて楽しい😊
が、定量的な測定ができないため、Wiresharkの機能を使ってグラフで表示してみる。

メニューの `統計→入出力グラフ` を開く。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22110/cfd045e6-fa0b-9362-b46d-9f3833463c10.png)

すると、今フィルタリングされているパケットのみを捉えたグラフが生成される。
StyleとY軸の値はお好みで変更すると良い。

---

こんな感じで今後別の機器が家庭のネットワークに増えても、同じノリで測定することができるはず。
家でもネットワーク上のパケットを監視することができるんだ！ということがわかると安心できるので精神衛生上良い👍
【統計検定準1級対策②】ベルヌーイ分布の確率関数，期待値，分散，母関数の導出過程

## 結論
>確率関数
>```math
>f(x) = 
>\left\{\begin{array}{ll}
>1-p & x = 0 \\
>p & x = 1 \\
>\end{array}\right.
>=p^x(1-p)^{1-x} \ \ (x = 0,1)
>```
>期待値，分散
>```math
>E[X] = p, \ \ V[X]= p(1-p)
>```
>母関数
>```math
>G(s) = ps+(1-p)
>```

## 期待値の導出
期待値の定義：$\displaystyle E[X]=\sum_{x}xf(x)$から，
```math
\begin{align*}
E[X] &= \sum_{x=0}^{1}xf(x)\\
&= 0\cdot(1-p) +1\cdot p\\
&= p\end{align*}
```

## 分散の導出
分散は偏差の２乗の期待値 $\left(\displaystyle V[X]=E[(X-\mu)^2]\right)$ だから，
```math
\begin{align*}
V[X] &= E[(X-\mu)^2]\\
&= \sum_{x=0}^{1}(x-p)^2f(x)\\
&= (0-p)^2(1-p) + (1-p)^2p\\
&= p(1-p)\\
\end{align*}
```

【別解】
関係式：$V[X]=E[X^2]-(E[X])^2$ から，
```math
\begin{align*}
V[X] &= E[X^2]-(E[X])^2\\
&= \sum_{x=0}^{1}x^2f(x) - p^2\\
&= 0^2\cdot(1-p) + 1^2\cdot p - p^2\\
&= p - p^2 = p(1-p)
\end{align*}
```
## 母関数の導出
確率母関数の定義：$G(s)=E[s^X]$ から，
```math
\begin{align*}
G(s) &= E[s^X]\\
&= \sum_{x=0}^{1}s^xf(x)\\
&= s^0(1-p) + s^1p\\
&= ps+(1-p)
\end{align*}
```

## まとめリンク
[【統計検定準1級対策】確率分布の確率関数，期待値，分散，母関数まとめ
](https://qiita.com/matsuda-blog/items/4573b08f75b3d3c49c16 "すべての主要確率分布まとめ")
そもそもUNIXコマンドとはなんぞやという事についてのアウトプット

そもそもUNIXコマンドのUNIXとはなんぞや？
→OS(Operation System)の一種。
始祖とも言えるほど古いOS
（windows macos ios  Android　<b>Linux</b>）の仲間

よく映画やアニメなどでハッカーがカタカタ操作している黒い画面
あのような感じで文字列を打ち込んで操作する時に使うコマンド
＝UNIXコマンド

・ではなぜこれを学ぶのか？
プログラムを作った！→でも本番環境で動くか不安だな→同じ環境でも動くかテストしてみよう！
さてこのサーバー（パソコン）にこのファイルを入れて実行してもらって...マウスとキーボードがないのにどうやってストレージ内を移動するんだ！？
と、いう時に操作を行う環境作りやスペース、移動時間などなどを短縮できるメリットがある為

ここで振り返ること
→UNIXは<b>始祖とも言えるほど古いOS</b>

MACに搭載されているMACOSやLinuxなどこれらは
<b>UNIXを元に作られているもの。</b>

...ということは「正式には別のOSだが根本は同じなのでUNIXコマンドで操作することができる！！」


大きな面での利点

・環境によって変わるが基本サーバーにはマウスやキーボードといった操作性を高めるツールが接続されていないため
その中で効率化を図るために便利。
・現実的ではない動作を行う時に使ったりする。
・上記の面からプログラマーからエンジニアまで幅広く浸透しているので作業効率的な面で覚えておく必要があるため


余談

<font size='1'>残念ながらWindowsでUNIXコマンドを使うことはできない... ←これはデフォ環境の話
（GitBashなど拡張ツールなどを使えばWindowsでもUNIXコマンドが使えるようになる。）←ここがWindowsの長所と利点


操作方法については次の記事。
e-StatにあるCSVをPythonを使ってまとめてダウンロードする

　[政府統計の総合窓口e-Stat](https://www.e-stat.go.jp/)に掲載されているCSVを一括でダウンロードしたくなったので、初学者の私がPythonを使ってプログラムを書いてみた。私がやりたい事はAPI使えればOKだったのだが、なぜか私が欲しい所はAPIが使えなかったので、CSVをダンロードすることにした。

# 使用した言語
- Python(3.9.10)

# 使用したモジュールたち
- requests
- bs4(BeautifulSoup)
- pandas
- os

# 今回取得したいCSV
- 平成29年度〜令和2年度 地域保健・健康増進事業報告 > 健康増進編 > 市区町村表 に掲載されているCSV

# ディレクトリ構成（最小）
    e-stat
        ├ csv
        ├ main.py
*GitHubでも公開しています。 URL:https://github.com/kawhi6key/e-stat_get_csv

# 実際のコード
```Python:main.py
import requests
from bs4 import BeautifulSoup
import pandas as pd
import os


# 令和２年度地域保健・健康増進事業報告 > 健康増進編 > 市区町村表
r2_url = "https://www.e-stat.go.jp/stat-search/files?page=1&layout=datalist&toukei=00450025&tstat=000001030884&cycle=8&tclass1=000001164286&tclass2=000001164291&tclass3=000001164293&tclass4val=0"
# 令和元年度地域保健・健康増進事業報告 > 健康増進編 > 市区町村表
r1_url = "https://www.e-stat.go.jp/stat-search/files?page=1&layout=datalist&toukei=00450025&tstat=000001030884&cycle=8&tclass1=000001155266&tclass2=000001155275&tclass3val=0"
# 平成30年度地域保健・健康増進事業報告 > 健康増進編 > 市区町村表
h30_url = "https://www.e-stat.go.jp/stat-search/files?page=1&layout=datalist&toukei=00450025&tstat=000001030884&cycle=8&tclass1=000001142306&tclass2=000001142315&tclass3val=0"
# 平成29年度地域保健・健康増進事業報告 > 健康増進編 > 市区町村表
h29_url = "https://www.e-stat.go.jp/stat-search/files?page=1&layout=datalist&toukei=00450025&tstat=000001030884&cycle=8&tclass1=000001126815&tclass2=000001126824&tclass3val=0"

# csvフォルダ下でcsvを格納するフォルダ名を指定する
datalist = {"2020":r2_url, "2019":r1_url, "2018":h30_url, "2017":h29_url}

for key, value in datalist.items():
    folderName = key
    url = value

    res = requests.get(url)
    soup = BeautifulSoup(res.text, "html.parser")

    # フォルダを作成
    os.makedirs(f'csv/{folderName}', exist_ok=True)

    # csvの取得
    links = soup.find_all("a", class_='stat-dl_icon')

    for link in links:
        csv_link = str("https://www.e-stat.go.jp")+str(link.get('href'))
        print(csv_link)
        df = pd.read_csv(csv_link, encoding="cp932")
        dataName = df.iloc[0,1]
        df.to_csv(f'csv/{folderName}/{dataName}.csv', encoding="cp932")
```

以上。お役に立てれば。
DAX workout - FORMAT function

モデルの *culture* はあとから変更したりできなけれどもね、すべてのモデルがいつも一緒と限らない。
# 2021-09 のアップデートで *locale_name* 引数の追加

https://powerbi.microsoft.com/ja-jp/blog/power-bi-report-server-september-2021-feature-summary/#post-17456-_Toc83328008

それまでは、モデル の *culture* に依存していたのだけど、FORMAT 関数 で明示的な指定が可能
Azure Analysis Service でも追加になってるはず。

https://docs.microsoft.com/en-us/dax/format-function-dax

>The format strings supported as an argument to the DAX FORMAT function are based on the format strings used by Visual Basic (OLE Automation), not on the format strings used by the .NET Framework. Therefore, you might get unexpected results or an error if the argument doesn't match any defined format strings. For example, "p" as an abbreviation for "Percent" isn't supported. Strings that you provide as an argument to the FORMAT function that aren't included in the list of predefined format strings are handled as part of a custom format string, or as a string literal.

書式文字列は VB と変わらんよということ。Power Query の書式文字列は .NET Framework。

https://dax.guide/format/


```text:DAX&#x20;Query&#x20;(特徴的なものだけ)
DEFINE
VAR D = dt"2022-04-09 16:11:55"
VAR N = 12345.67
EVALUATE
{
    ( "Currency",    FORMAT ( N, "Currency",    "ja-JP" ) ),
    ( "aaa",         FORMAT ( D, "aaa",         "ja-JP" ) ),
    ( "aaaa",        FORMAT ( D, "aaaa",        "ja-JP" ) ),
    ( "dddddd",      FORMAT ( D, "dddddd",      "ja-JP" ) ),
    ( "Long Date",   FORMAT ( D, "Long Date",   "ja-JP" ) ),
    ( "Short Date",  FORMAT ( D, "Short Date",  "ja-JP" ) ),
    ( "Long Time",   FORMAT ( D, "Long Time",   "ja-JP" ) ),
    ( "Medium Time", FORMAT ( D, "Medium Time", "ja-JP" ) ),
    ( "Era",         FORMAT ( D, "ge",          "ja-JP" ) ),
    ( "Era",         FORMAT ( D, "gge",         "ja-JP" ) ),
    ( "Era",         FORMAT ( D, "ggge",        "ja-JP" ) ),
    ( "Era",         FORMAT ( D, "gggee",       "ja-JP" ) )
}
```

|Value1|Value2|
|:--|:--|
|Currency|¥12,346|
|aaa|土|
|aaaa|土曜日|
|dddddd|2022年4月9日|
|Long Date|2022年4月9日|
|Short Date|2022/04/09|
|Long Time|16:11:55|
|Medium Time|04:11 午後|
|Era|R4|
|Era|令4|
|Era|令和4|
|Era|令和04|


```text:DAX&#x20;Query&#x20;(丸め)
DEFINE
    VAR N1 = 1001.4
    VAR N2 = 1001.5
    VAR N3 = 1002.4
    VAR N4 = 1002.5

EVALUATE
{
    ( "CurrencyN1", FORMAT ( N1, "Currency", "ja-JP" ) ),
    ( "CurrencyN2", FORMAT ( N2, "Currency", "ja-JP" ) ),
    ( "CurrencyN3", FORMAT ( N3, "Currency", "ja-JP" ) ),
    ( "CurrencyN4", FORMAT ( N4, "Currency", "ja-JP" ) )
}
```

|Value1|Value2|
|:--|:--|
|CurrencyN1|¥1,001|
|CurrencyN2|¥1,002|
|CurrencyN3|¥1,002|
|CurrencyN4|¥1,003|

# その他
https://powerbi.connpass.com/

- [Power BI 勉強会 - connpass](https://powerbi.connpass.com/)
- [Power BI Desktop を使い始めるには](http://qiita.com/PowerBIxyz/items/6c4735cb5b5712e70981)
- [Excel で Power Query を使い始めるには](http://qiita.com/PowerBIxyz/items/52e563037b855a099ca9)
VirtualBoxからvagrant用のboxの作り方

自分でカスタマイズしたboxファイルを使いたい

### VirtualBoxのVM（ゲストOS）で実施

ゲストOSを自分好みに設定する。


ゲストOSをシャットダウン
```
# shutdown -h now
```

### ホストOSで実施

box化したいゲストOSを確認してboxファイルを作成

```shell
$ VBoxManage list vms  # VirtualBoxにあるvmの一覧を表示
"ubuntu-1804_default_1645713644552_67272" {e6d4789d-4581-4fec-b596-6a4f0ff4d41c}
"rt01_1649081829316_95563" {b3d1bd7d-7680-4119-964d-c3984a500374}
"cent01_1649168567030_75777" {1123fed9-40d9-4e13-8c66-21e3ae1aedae}
"cent02_1649333353764_9447" {54d53a0a-0a07-4c60-8255-d272b82875ea}
"rh_test_default_1649484950362_67537" {7d5f1e17-585b-41bf-9b7c-936fdc0d6ef7}
```

`rh_test_default_1649484950362_67537`のvmをboxファイル化する

```shell
$ vagrant package --base $ vagrant package --base "rh_test_default_1649484950362_67537" --output my-rhel8.box
```

boxファイルができたら、vagrantに登録する。rhel8の名前で登録する場合。
```shell
$ vagrant box add my-rhel8.box --name rhel8
```
登録できたか確認する
```shell
$ vagrant box list
bento/ubuntu-18.04 (virtualbox, 202112.19.0)
centos/8           (virtualbox, 2011.0)
rhel8       (virtualbox, 0)
kun432/vyos        (virtualbox, 1.3-rolling-202010130117)

```
これで自作のboxをvagrantで利用可能になる

### はまったこと

ホストOSで`vagrant up`したとき、以下のエラーメッセージが出た。

```shell
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
```

その場合、ゲストOSにvagrantでログインして、vagrantユーザの公開鍵設定するとよい。

```shell
# su - vagrant
# mkdir ~/.ssh
# chmod 700 ~/.ssh
# curl -k -L -o ~/.ssh/authorized_keys  https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub
# chmod 600 ~/.ssh/authorized_keys
```
【Java】RestTemplate・WebClient・MockMvc 比較メモ

# まえがき
APIからAPIをコールする場合や、テストプログラム内からAPIをコールしたい場合に「何使えばいいの？」というところで以下の３つが挙げられる。

・[RestTemplate](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html)（org.springframework.web.client.RestTemplate）
・[WebClient](https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.html)（org.springframework.web.**reactive**.function.client.WebClient）
・[MockMvc](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/web/servlet/MockMvc.html)（org.springframework.**test**.web.servlet.MockMvc）

いずれもSpringFrameworkで提供されているやつだが、どういう時にどれを使えばいいのかちゃんと理解できていなかったので、この記事でまとめていく。

# 比較表
|   |特徴|
|---|---|
|RestTemplate|・Spring提供のAPIクライアントライブラリ<br>・**APIレスポンスが返ってくるまでスレッドは待機状態となる**。|
|WebClient|・**Spring WebFlux**提供のAPIクライアントライブラリ<br>・**APIレスポンスを待機せずスレッドは処理を進める**。|
|MockMvc|・**テスト時**のAPIコール用（パッケージ名に"test"が含まれているくらいだし）|

## Spring WebFluxって何？

>**リアクティブプログラミング**によって**ノンブロッキングで非同期なアプリケーション**を開発できるSpring Framework

### リアクティブプログラミング って何？

> データストリームと変更の伝播に関係する宣言型プログラミングパラダイム

「データストリームと変更の伝播」が一体何を指しているのか、下記の記事が分かりやすかったのでおすすめ。

https://speakerdeck.com/okapies/reactive-streams-ru-men-number-jjug?slide=19

### ノンブロッキングで非同期なアプリケーション って何？
・ノンブロッキングとは「**スレッド**をブロックしない(待機状態としない)」ことを指す。

・Tomcatは1リクエストを処理するのに1スレッドを割り当てるのだが、このリクエスト内で取得に時間のかかる外部APIをコールする処理がある場合に、この外部APIのレスポンスが返ってくるまでスレッドは待機状態となる。これが"スレッド"がブロッキングされている状態である。**Spring MVC（RestTemplate)ではブロッキングされる**が、**Spring WebFlux（WebClient）ではノンブロッキングを実現できる**。

・「外部APIのレスポンスを待たずに後続処理を続けられる」ことから、非同期なアプリケーションと呼ばれる。

https://www.kimullaa.com/entry/2018/04/25/214708

### ブロッキングとノンブロッキングの違い
実際にRestTemplate(ブロッキング)とWebClient(ノンブロッキング)で動作検証しているサイトで、わかりやすいサイトがあったので掲載させていただく。

https://footprints.link/articles/ja/n-machida/getting-started-with-spring-webflux-with-hands-on

# RestTemplate
下記参照。

https://www.baeldung.com/rest-template

# WebClient
下記参照。

https://www.baeldung.com/spring-5-webclient

# MockMvc
下記参照。

https://www.baeldung.com/integration-testing-in-spring
Oracle　権限の管理

ORACLEユーザと権限のまとめ

# 管理用ユーザ
- SYS
    - データベースの起動／停止を含むすべての操作を実行できる管理用ユーザ
    - SYSDBA権限(ロール)が付与されている
    - 削除不可
- SYSTEM
    - データベースの起動／停止などの一部を除き、ほぼすべての操作を実行できる管理用ユーザ
    - バックアップとリカバリもできない
    - SYSDBA権限(ロール)は付与されていない
    - 削除不可
 
# 権限とロール
## 権限
- システム権限（データベースに対して、どのような操作を許可するか）
    - CREATE SESSION
    - CREATE TABLE
    - CREATE TABLESPACE
    - CREATE USER
- オブジェクト権限（他のユーザが所有する特定のオブジェクトに対して、どのような操作を許可するか）
    - SELECT
    - INSERT
    - UPDATE
    - DELETE

- WITH ADMIN OPTION句
    - 他のユーザに「その」システム権限を付与
- GRANT ANY PRIVILEGE
    - 他のユーザに「すべての」システム権限を付与
- WITH GRANT OPTION句
    - 他のユーザに「その」オブジェクト権限を付与
- GRANT ANY OBJECT PRIVILEGE
    - 他のユーザに「すべての」オブジェクト権限を付与
## ロール
- 複数の権限を１つにグループ化したもの
- ロールの変更はそのロールが付与済のユーザにも反映される
- ロールにロールを付与する事もできる
### DDL文
```
CREATE ROLE <ロール名>;
DROP ROLE <ロール名>;
GRANT <権限> TO <ロール名>;
REVOGE <権限> FROM <ロール名>;
GRANT <ロール名> TO <ユーザ名>;
REVOGE <ロール名> FROM <ユーザ名>;
```

# 管理権限

- SYSDBA権限
    - 「インスタンスの起動と指定」「バックアップとリカバリ」を含む全ての管理操作を実行可能
    - すべてのユーザのデータにアクセス可能
    - SYSユーザで接続される
- SYSOPER権限
    - 「インスタンスの起動と停止」「バックアップとリカバリ」を含む管理操作を実行可能。ただし、「データベースの作成と削除」「不完全リカバリ」は実行不可。
    - ユーザのデータにアクセス不可
    - PUBLICユーザで接続される

# 権限分析
- DBMS_PRIVILEGE_CAPTUREパッケージ
    - 全データベース
    - ロール
    - コンテキスト
    - ロールとコンテキスト
[Typescript] オブジェクトの特定プロパティの型を上書きする型関数をつくる

# 成果物
```
/**
 * 特定のプロパティを上書きする型関数
 * Overwrite<Type, OverwritingType>
 */
export type Overwrite<T, U extends { [Key in keyof T]?: unknown }> = Omit<
  T,
  keyof U
> & U;
```

# 何がしたいか
```
type Person = {
  firstName: string;
  lastName: string;
  age: string;
};
```
例えば上記の様なオブジェクトがあとすると、 `age` プロパティだけ型を `string` から `number` へサクッと安全に変更できる型関数を作りたい。

**※ しかしプロパティの上書きは混乱を招くので、今回の例のような場合は設計を見直すべきです。**

私たちの場合、ORMにPrismaを使っているのですが、Jsonデータを取得するときに、 `any` 型になってしまう。そういった時に、jsonデータのみを自分たちで作った型に上書きしてあげたかった。

# 型関数を用いない上書き方法
```
type Person = {
  firstName: string;
  lastName: string;
  age: string;
};

type NewPerson = Omit<Person, "age"> & { // ①
  age: string; // ②
};
```

### 問題点
- 上書きしたいプロパティが増えるごとに ①、②に記述を追加する必要がある
- ② のプロパティは実質なんでも追加できてしまうため、安全性に欠ける & タイポも起こり得る
- 普通に冗長

# 型関数を用いた場合
```
/**
 * 特定のプロパティを上書きする型関数
 */
export type Overwrite<T, U extends { [Key in keyof T]?: unknown }> = Omit<
  T,
  keyof U
> & U;
```

```
type Person = {
  firstName: string;
  lastName: string;
  age: string;
};

type NewPerson = Overwrite<Person, {age: number;}>
```

どうでしょう、Overwriteを使うことで、安全に特定プロパティのみ上書きできたかと思います。
例えば、 `age` をタイポしてもちゃんとエラーがでてくれます。


Overwriteの実装はシンプルで、
1. 受け取る関数をジェネリクスで定義
	- 第一引数は対象のオブジェクト
	- 第二引数は対象のオブジェクトの特定のプロパティだけを指定できるよう extends で制約をつくる
2. Omitで対象プロパティを削除
3. 第一引数と第二引数をマージして返却



# 終わりに

少ししらべてみましたが、このシンプルな型関数がどこにも載っていなかったので、作って公開してみました。


活用シーンは限られますが、お役に立てれば👋


[✍️ iba_ragi](https://twitter.com/iba_ragi)
【Salesforce】リストビューで選択したレコードをフローに渡す方法

リストビューで選択したレコードだけに特定の処理をしたい時の実装方法です。

```page:Visualforce
<apex:page standardController="OBJ名" recordSetVar="OBJ名（複数形）">
　　　　　　　　// URLFORはリストビューのURLなどの遷移先URLを記載（例では商談のリストビュー）
    <flow:interview name="フローのAPI名" finishLocation="{!URLFOR('/lightning/o/Opportunity/list?filterName=Recent')}">
        <apex:param name="フローに渡すコレクション変数" value="{!Selected}"/>
    </flow:interview>
</apex:page>
```

リストビューでレコードを選択（複数可）
→VFでその選択したレコードの値をコレクション変数に格納
→そのコレクション変数を使ってフロー側で処理

VFをかませる都合上、Classic ランタイムになる点に注意してください。
https://help.salesforce.com/apex/HTViewHelpDoc?id=sf.flow_distribute_runtime.htm&language=ja
【Apex】例外処理は何が嬉しいのか

## はじめに

なんとなく「便利だな」とは思いつつ、ノリで使っていた例外処理。

何が嬉しいのか少し掘ってみました。

例はApexですが、他の言語でも同じ嬉しさはあると思います。

## 結論

ドキュメントの言葉を借りると、

>エラー処理を単純化できるから

というのが嬉しいポイント。

ここでいう「単純化」とは、僕なりに以下の意味だと解釈しています。
・記述量が少ない
・記述内容が脳に負担をかけない

例えば「エラーが発生したときは共通のエラー画面に飛ばしたい」とき、
例外処理のあるなしでどう変わるのか、見てみましょう。

## 例） 例外処理あり

```
private void method1(){
    try{
        this.method2();
    }catch(Exception e){
        // エラー画面に遷移する処理
    }
}

private void method2(){
    // NullPointerExceptionが発生するかもしれない処理
    this.method3();
}

private void method3(){
    // DmlExceptionが発生するかもしれない処理
}
```

上記のように書けば、

最上位のメソッドに例外処理を書いとくだけで、エラー画面に飛ばせます。
（記述量が少ない）

また、エラーの種類を考えなくてもcatchが捕まえて、エラー画面に飛ばしてくれます。
（記述内容が脳に負担をかけない）

## 例） 例外処理なし

```
private void method1(){
    this.method2();
}

private void method2(){
    // ① NullPointerExceptionが発生しそうなら、エラー画面へ飛ばす処理
    // NullPointerExceptionが発生するかもしれない処理
    this.method3();
}

private void method3(){
    // ② DmlExceptionが発生しそうなら、エラー画面へ飛ばす処理
    // DmlExceptionが発生するかもしれない処理
}
```

上記のように書くと、

①や②のように各メソッドにエラー画面へ飛ばす処理を書く必要があります。
（記述量が多い）

また、発生しそうなエラーを考えて、それに合わせた処理を書く必要があります。
しかも予想外のエラーが起こって、エラー画面へ飛ばすのが失敗するかもしれません。
（記述内容が脳に負担をかける）

## まとめ

例外処理がないと、思った以上にコード書くのが大変になるんですね。

こうやって普段やっていることの意味を紐解くのは楽しいです。

## 参考文献

[Exceptions in Apex](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_exception_definition.htm)
[Qiita]数式の下の無駄なスクロールバーを消す

:::note info

2022-11-15、<font color='#f00'>**Qiitaのシステムの改善により、数式の下の無駄なスクロールバーは出なくなりました**</font>。この記事は無意味になりましたが、**過去の記録としてそのまま残しておきます**。
:::

**ご注意：**　ここで書いている現象は、ユーザーの閲覧環境によって異なるのかもしれません。また、今後、Qiitaの投稿システムが変われば、ここの対策は無用の長物になってしまうことでしょう。以下は、2022-4-9時点での、私のパソコン上だけで確認した現象と対策です。皆さんの環境では通用しない内容かもしれません。もしそうでしたら、ゴメンナサイ。

**追記：　
　投稿結果を見たところ、やはり特定の条件だけで現れる現象のようです。お騒がせしております。この現象を確認できた環境は、Windows10下のEdgeとChrome。この問題の発生が全くないのが、iPadのSafariとWindows10下のFirefoxです。あとは未確認です。
　問題が発生しない環境で見ておられる方には、この記事の意味が伝わりにくいと思われますので、Windows10のEdgeでの問題部分のスクリーンコピーを添付しておきます。**
 
![スクロールバー全体.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/932484/e22bd048-ea7e-080b-7382-0bf1afca6b47.png)



### 困っていること
　Qiitaに投稿すると、**数式の下に予期しない横スクロールバー**が表示されることがあります。**例えばこんな（$\log$）感じです**。スクロールしなければ見渡せないほど長い式でもないのになぜ出てくるのでしょう。目障りだし、その部分だけ行間が広くなったりして読み難くて邪魔です。

　数式部分をクリックすると一旦は消えるので やれやれ と思いますが、同じ問題を抱える別の数式をクリックすると、その数式のバーが消えて、先の数式のバーはまた出現します。まるでモグラ叩きです。（殆どは筋金入りの不死身のモグラですが、中には、一度叩くと２度とは現れない根性無しのモグラもいます。しかし、根性無しでもリロードすればまた現れます）

　ネットをググってみると、スクロールバーを追加する方法については色々な記事が見つかりますが、消す方法についてはなかなか見当たりません。

### 具体的状況

　まずは、無駄なスクロールバーが現れるときの状況を確認しておく必要があります。

#### どんなときに現れるのか

■　**シンプル過ぎても出るケース**

　手の込んだことは何もしていないのに出てくるものがあります。（しかも、筋金入り）
　$\sum$　　$\log$
```
$\sum$　　$\log$
```
しかし、これらは、手を加えると出なくなることも多いようです。
　$\displaystyle\sum_{k=0}^n$　　$\log_e$
```
$\displaystyle\sum_{k=0}^n$　　$\log_e$
```
　ただし、無問題にみえる場合でも、同一書式のまま記述場所を変えるだけで、筋金入り や 根性無しの バー付き数式に変身するものもあるので安心はできません。

■　**手を加え過ぎて出るケース**

　個人的な拘りを捨てきれずに、余計なことをしても良くないようです。
　　$\theta=\tan^{-1}(\frac{y}{x})+\pi$
```
$\theta=\tan^{-1}(\frac{y}{x})+\pi$
```
これなら問題なかったところを、どうも$-1$（ここでも嫌なものが出てしまった！）のフォントサイズが大きすぎるということで、
　　$\theta=\tan^{\scriptsize{-1}}\(\frac{y}{x}\)+\pi$
```
$\theta=\tan^{\scriptsize{-1}}\(\frac{y}{x}\)+\pi$
```
としたまでは良かったのですが、今度は$-1$をもう少し左に寄せたいという欲を出すと、
　　$\theta=\tan^{\\!\scriptsize{-1}}\(\frac{y}{x}\)+\pi$
```
$\theta=\tan^{\\!\scriptsize{-1}}\(\frac{y}{x}\)+\pi$
```
あ～、嫌なものが出てきた・・・となってしまいます。

### 対策
　そこで、悪戦苦闘しながら見つけ出した解決法をここで披露します。理論的根拠も何もない行き当たりばったりの方法なので、再現性が悪かったり。環境に左右されるのかもしれませんがご容赦ください。

　特定のケースでしか効果が現れない小手先の対症療法も色々見つかりましたが、ここではこれらについては割愛します。今のところ、次に示す方法は、どんなケースでも効果が見られたオールマイティーの極め付きの対策です。

まずは、無対策の数式を再掲します。

$\sum$　　$\log$　　$\theta=\tan^{\\!\scriptsize{-1}}\(\frac{y}{x}\)+\pi$　　（無対策）

```
$\sum$　　$\log$　　$\theta=\tan^{\\!\scriptsize{-1}}\(\frac{y}{x}\)+\pi$　　（無対策）
```
数式の最初の部分に **\hspace{0.1ex} を挿入**します。　
**問題は見事に解決します。**

$\hspace{0.1ex}\sum$　　$\hspace{0.1ex}\log$　　$\hspace{0.1ex}\theta=\tan^{\\!\scriptsize{-1}}\(\frac{y}{x}\)+\pi$　　（対策１）

```
$\hspace{0.1ex}\sum$　　$\hspace{0.1ex}\log$　　$\hspace{0.1ex}\theta=\tan^{\\!\scriptsize{-1}}\(\frac{y}{x}\)+\pi$　　（対策１）
```
**\hspace{0.1ex}** は最後に挿入しても大丈夫です。　

$\sum\hspace{0.1ex}$　　$\log\hspace{0.1ex}$　　$\theta=\tan^{\\!\scriptsize{-1}}\(\frac{y}{x}\)+\pi\hspace{0.1ex}$　　（対策２）

```
$\sum\hspace{0.1ex}$　　$\log\hspace{0.1ex}$　　$\theta=\tan^{\\!\scriptsize{-1}}\(\frac{y}{x}\)+\pi\hspace{0.1ex}$　　（対策２）
```
　**\hspace{0.1ex}** は空白を表すTeXコマンドなので、数式の位置が水平方向に少々移動します。しかし、0.1ex (文字$x$の高さの0.1倍) 程度なのでそれほど気にはならないでしょう。もっと小さく 0.01ex としても良いものもありますが、例外もあって万全ではありません。
ラズパイでWifi接続時にパスワードを入力すると無効な引数ですと表示される

# 現象について
iPhoneのインターネット共有(デザリング)機能を使ってラズパイをネットに繋ごうと設定を試みた。
（当時のWifi名は「＜本名＞のiPhone」で設定されており、ラズパイ側に表示されるWifi名には文字化けのようなものが見られた。）
パスワードを入力後、OKをクリックすると「無効な引数です」というエラーが表示された。
[![Image from Gyazo](https://i.gyazo.com/9fe673a9cb924b1d6d8628451fac99e3.jpg)](https://gyazo.com/9fe673a9cb924b1d6d8628451fac99e3)

# 環境
iPhone11
Raspberry Pi 3 Model B
Raspberry OS 3.1.1 (2.4.0等、複数のバージョンで同様の現象確認)

# 原因
Wifi名に日本語が含まれることが原因。
Wifi名を日本語が含まれないものに変更すれば解決した。

# 解決方法
以下はiPhoneでの変更方法
設定 ➔ 一般 ➔ 情報 ➔ 一番上の名前がWifi名に使われている部分なので日本語が含まれないものに変更。
[![Image from Gyazo](https://i.gyazo.com/ee2589181e07ebfd4b8dcbb6a4f7fc5e.png)](https://gyazo.com/ee2589181e07ebfd4b8dcbb6a4f7fc5e)

ラズパイに戻り、再度Wifiの接続設定を試みると無事に接続された。
【Go】sqlxの使い方メモ

# はじめに
sqlxというライブラリを使ってみたのでメモ。

# sqlxとは
標準ライブラリ`database/sql`の拡張ライブラリです。
`database/sql`では、DBからとってきたデータをカラムごとにScan(型変換)して構造体にマッピングする必要があるのですが、カラム数が多いとこの部分の記述が非常に苦痛です。
この面倒な作業を勝手にやってくれたりするのが`sqlx`の役割です。

https://github.com/jmoiron/sqlx

↓`database/sql`を使った場合のScan処理の例

```go:customerRepositoryDb.go
type CustomerRepositoryDb struct {
	client *sql.DB
}

func (d CustomerRepositoryDb) FindAll() ([]Customer, error) {
	findAllSql := "select customer_id, name, city, zipcode, date_of_birth, status from customers"

	rows, err := d.client.Query(findAllSql)
	if err != nil {
		logger.Error("Error while querying customer table " + err.Error())
		return nil, err
	}

    customers := make([]Customer, 0)
	for rows.Next() {
      var c Customer
	  err := rows.Scan(&c.Id, &c.Name, &c.City, &c.Zipcode, &c.DateofBirth, &c.Status)
	  if err != nil {
 		logger.Error("Error while scanning customers " + err.Error())
 		return nil, err
 	  }
	  customers = append(customers, c)
	}
	return customers, nil
}
```
# 実装
以下が`sqlx`で同じ処理を記述したコードです。
`database/sql`だとあったクエリとScan処理の記述が、なんと`err = d.client.Select(&customers, findAllSql)`の一行で完結します。

```go:customerRepositoryDb.go
type CustomerRepositoryDb struct {
	client *sqlx.DB
}

func (d CustomerRepositoryDb) FindAll() ([]Customer, error) {
	var err error
	customers := make([]Customer, 0)
	
	findAllSql := "select customer_id, name, city, zipcode, date_of_birth, status from customers"

	err = d.client.Select(&customers, findAllSql)
	if err != nil {
		logger.Error("Error while querying customer table " + err.Error())
		return nil, err
	}

	return customers, nil
}
```
また、名前付きクエリの場合には、`err := d.client.Get(&c, customerSql, id)`のように、GETメソッドを使用することができます。

```golang
func (d CustomerRepositoryDb) ById(id string) (*Customer, *errs.AppError) {
	customerSql := "select customer_id, name, city, zipcode, date_of_birth, status from customers where customer_id = ?"

	var c Customer
	err := d.client.Get(&c, customerSql, id)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, errs.NewNotFoundError("customer not found")
		} else {
			logger.Error("Error while scanning customer " + err.Error())
			return nil, errs.NewUnexpectedError("unexpected database error")
		}
	}
	return &c, nil
}
```

# 参考資料

https://blog.p1ass.com/posts/go-database-sql-wrapper/
SwiftUIアプリでマークダウンテキストを表示する

この記事では、SwiftUIアプリ内でのマークダウン形式のテキストの表示について説明します。これは、コードに入力した文字列と、ユーザーが入力したテキストの両方に当てはまります。

## 使用可能なマークダウンフォーマット

現時点では、太字、イタリック体、リンク（リンクをクリックすると、Safariアプリが起動します）、コードのマークダウンが使用できます。

## コーディングする文字列の中でマークダウンを使用

コードファイルの中の文字列に直接マークダウンフォーマットを含めることができます。

```swift
Text("You can use **bold text**, an *italic* text, a [link](apple.com), or `a piece of code`.")
```

テキストはマークダウンフォーマットで表示されます。

![スクリーンショット 2022-04-09 14.16.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/4b164719-1b48-0ae8-1650-0cc5d1cc2306.png)

## 保存された文字列のマークダウンをレンダリングする

マークダウンテキストがコードに直接存在しない場合 (例えば、変数から、または保存された値から読み取られる場合)、マークダウンとしてレンダリングする必要がある。

拡張関数を`String`に追加することができる。

```swift
extension String {
    func getAttributedString() -> AttributedString {
        do {
            let attributedString = try AttributedString(markdown: self)
            return attributedString
        } catch {
            print("Couldn't parse: \(error)")
        }
        return AttributedString("Error parsing markdown")
    }
}
```

そして、テキストをマークダウンで表示するためには：

```swift
Text(itemTextContent.getAttributedString())
```

## SwiftでMarkdownエディターを作成する

これでユーザがマークダウン形式で入力すると、そのテキストがマークダウンとしてレンダリングされるMarkdownエディターを作成できます。

![simple-markdown-editor.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/3378b18c-cbe9-2b4a-e0c3-d45e0877fd46.gif)

```swift
import SwiftUI

struct ContentView: View {
    
    @State private var userEnteredText: String = ""
    
    var body: some View {
        List {
            Section("Enter some text here") {
                TextEditor(text: $userEnteredText)
            }
            Text(userEnteredText.getAttributedString())
        }
    }
    
}
```

---

:relaxed: [Twitter @MszPro](https://twitter.com/MszPro)

:sunny: 私の公開されているQiita記事のリストをカテゴリー別にご覧いただけます：
<img width="150" src="https://cdn.mszmagic.com/static-web-content/AppClipImage_small.png">
例外リスト

# 例外リスト
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
   　　   +-- StopIteration
   　　   +-- StopAsyncIteration
    　　  +-- ArithmeticError
     　　 |    　+-- FloatingPointError
      　 　|    　+-- OverflowError
      　　 |   　 +-- ZeroDivisionError
      　　+-- AssertionError
      　　+-- AttributeError
      　　+-- BufferError
      　　+-- EOFError
      　　+-- ImportError
     　　 |    　+-- ModuleNotFoundError
   　　   +-- LookupError
     　　 |   　 +-- IndexError
     　　 |    　+-- KeyError
      　　+-- MemoryError
      　　+-- NameError
    　　  |   　+-- UnboundLocalError
      　　+-- OSError
    　　  |    　+-- BlockingIOError
 　　     |    　+-- ChildProcessError
  　　    |    　+-- ConnectionError
   　　   |    　　|    +-- BrokenPipeError
    　　  |    　　|    +-- ConnectionAbortedError
     　　 |    　　|    +-- ConnectionRefusedError
    　　  |    　　|    +-- ConnectionResetError
   　　   |    　+-- FileExistsError
    　　  |    　+-- FileNotFoundError
     　　 |    　+-- InterruptedError
      　　|    　+-- IsADirectoryError
     　　 |    　+-- NotADirectoryError
     　　 |    　+-- PermissionError
    　　  |    　+-- ProcessLookupError
   　　   |    　+-- TimeoutError
    　　  +-- ReferenceError
    　　  +-- RuntimeError
     　　 |    　+-- NotImplementedError
     　　 |    　+-- RecursionError
     　　 +-- SyntaxError
     　　 |    　+-- IndentationError
    　　  |         　　　+-- TabError
   　　   +-- SystemError
  　　    +-- TypeError
  　　    +-- ValueError
  　　    |  　+-- UnicodeError
  　　    |   　   　   +-- UnicodeDecodeError
  　　    |   　   　   +-- UnicodeEncodeError
  　　    |   　   　   +-- UnicodeTranslateError
  　　    +-- Warning
      　　　     +-- DeprecationWarning
       　　　    +-- PendingDeprecationWarning
        　　　   +-- RuntimeWarning
        　　　   +-- SyntaxWarning
       　　　    +-- UserWarning
       　　　    +-- FutureWarning
      　　　     +-- ImportWarning
     　　　      +-- UnicodeWarning
     　　　      +-- BytesWarning
     　　　      +-- EncodingWarning
     　　　      +-- ResourceWarning
【Unity】ARでインジケータ表示

# インジケータって？

こういうの

https://twitter.com/soh_mitian/status/1512443329426096129?s=20&t=CiBg0kpAoazQu8DFMVzbXQ

ARで任意の場所にオブジェクトを置きたい時のターゲットインジケータってわけです。

# 作り方
ARFoundationを使うので、予めパッケージに追加しといて下さい。

## インジケータのプレハブを用意

こういうの
![スクリーンショット 2022-04-08 23.56.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1135021/e1272f6d-b8c0-2583-518f-db6c46b86496.png)

### インジケータオブジェクトを作成
ヒエラルキーで空のオブジェクトを作成します（適当にIndicatorとか名前つける）

空のオブジェクト配下にPlaneを作成します。

![スクリーンショット 2022-04-08 23.59.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1135021/40a9cbcf-8bd8-c511-4e0e-7d57fa8616ae.png)

Planeにインジケータとして表示したいテクスチャをドラッグ＆ドロップで貼り付けます。

## 必要なコンポーネントを追加

AR Plane ManagertとAR Raycast Managerを追加します。

![スクリーンショット 2022-04-09 0.04.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1135021/f99b43d1-271c-9dbd-ee62-98599b879119.png)

## スクリプト作成

解説めんどくさいから全部貼ります。

```csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

public class PlacementIndicator : MonoBehaviour
{
    private ARRaycastManager rayManager;
    private GameObject visual;

    void Start ()
    {
        // コンポーネントを入手する
        rayManager = FindObjectOfType<ARRaycastManager>();
        visual = transform.GetChild(0).gameObject;

        // インジケーターを非表示にする
        visual.SetActive(false);
    }
    
    void Update ()
    {
        // 画面の中央からレイキャストを発射します
        List<ARRaycastHit> hits = new List<ARRaycastHit>();
        rayManager.Raycast(new Vector2(Screen.width / 2, Screen.height / 2), hits, TrackableType.Planes);

        // AR平面に当たった場合は、位置と回転を更新します
        if(hits.Count > 0)
        {
            transform.position = hits[0].pose.position;
            transform.rotation = hits[0].pose.rotation;

            // ビジュアルが無効になっている場合は有効にする
            if(!visual.activeInHierarchy)
                visual.SetActive(true);
        }
    }
}
```

## スクリプトをIndicatorオブジェクトにアタッチ
さっき空のオブジェクトから作ったIndicatorオブジェクトに作ったスクリプトをドラッグ＆ドロップしてアタッチします。

![スクリーンショット 2022-04-09 0.09.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1135021/29b0e05b-ca1d-2915-b3ff-b26646bd58fc.png)

# おわり
セル関数のSUMIFSの使い方の応用（複数項目でのVLOOKUP的な使い方）　その２


# はじめに
EXCELのセル関数のSUMIFS関数を使って、
<font color=RED>**複数列でVLOOKUPを実行する**</font>ようなイメージ
あるいは別の表現では
<font color=RED>**SQLの LEFT JOIN を実現する**</font>ようなイメージ
または <font color=RED>**MATCH + INDEX関数の代替方法**</font>　
を実現する方法を思いついたので紹介します。

以下の記事の続きです。
先に以下の記事をご覧ください。

https://qiita.com/takahasinaoki/items/ffab40b1662ba6bf8223

上記の記事では、該当の列の属性が文字列の場合は使えないのですが、少し下準備をするだけで文字列の属性の列にも対応させることが出来る方法です。


# サンプル
C列に該当する値をG列から取得する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/435fd12d-ee63-fdb0-0c09-d3776d58e2ca.png)

# 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/2237e664-0c5e-fa75-5d3d-9f71bab69d2a.png)

# セル関数
・下準備としていずれかの列に(例ではH列) ROW()関数で行番号を表示させる　　```=ROW()``` 
・SUMIFS()関数を使って、該当の行番号を取得する　```SUMIFS(H:H,E:E,A2,F:F,B2)``` の部分
・INDIRECT()関数を使って、該当セルのアドレスの値を取得する　```=INDIRECT("G" & SUMIFS(H:H,E:E,A2,F:F,B2))```
・または　INDEX()関数を使って、該当のセルを指定する方法でも可　```=INDEX(G:G, SUMIFS(H:H,E:E,A2,F:F,B2), 1)```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/c921aafc-c6cf-ff3d-9f2d-1965c733f56a.png)


# 関連記事

https://qiita.com/takahasinaoki/items/ffab40b1662ba6bf8223

https://qiita.com/takahasinaoki/items/dc6834ea24d820446718
ディスクイメージに複数のパーティションがある時のマウント方法、をスクリプト化

お仕事や趣味の開発でイメージファイルをよく触ります。yocto の出力だったり、公式OSイメージだったり・・・
その中身を取り出したり、修正したりするのにいちいち SD カードに書いて操作するのは時間もかかるし面倒です。
イメージファイルを直接触りたいですね。

しかし「パーティションを含むイメージファイル」は設定なしでは mount コマンドでマウントできません。
どうしたらいいのでしょうか。

# 手順

こちらのページの手法でいけるようです。わかりやすい！

https://qiita.com/suzutsuki0220/items/38148dad5259a4dd9a6d

ざっくり書き出すと、
1) fdisk -l <imagefile> の結果を得る
2) 目標パーティションのセクタ開始位置を取得する
3) オフセットを計算する
4) 引数にセットしてマウント！

# スクリプト化
とはいえ、これを毎度手でやるのはちょっと・・・
手順はわかっているのでスクリプト化してしまいましょう。

ちゃんと libparted とか libfdisk を使ってバイナリコマンドにしたいところですが、
とりあえず bash スクリプトで書いてみました！

https://github.com/tkhshmsy/image-mount

```bash
usage： image-mount.sh <imagefile> [<part-num> <mount-point>]
```

* imagefile: イメージファイルのパス
* part-num: 何番目のパーティションをマウントするか
* mount-point: マウントする場所

引数が imagefile だけだと fdisk -l <imagefile> の結果をダンプします。
```
$ ./image-mount.sh imagefile.img
imagefile.img1 *     16384  186775  170392 83.2M  c W95 FAT32 (LBA)
imagefile.img2      196608 7448431 7251824  3.5G 83 Linux
```

パーティション番号とマウントポイントも追加するとマウントします。
もちろんマウントできる権限が必要です。
```
$ sudo ./image-mount.sh imagefile.img 2 ./mount/
imagefile.img1 *     16384  186775  170392 83.2M  c W95 FAT32 (LBA)
imagefile.img2      196608 7448431 7251824  3.5G 83 Linux
>> mount -o loop,offset=100663296 imagefile.img ./mount/

./mount/
合計 88
drwxr-xr-x 19 root     root      4096  3月  2 11:23 .
drwxrwxr-x  3 tkhshmsy tkhshmsy  4096  4月  7 16:57 ..
drwxr-xr-x  2 root     root      4096  3月  2 11:23 bin
drwxr-xr-x  2 root     root      4096  3月  2 11:22 boot
drwxr-xr-x  2 root     root      4096 11月  9 13:25 dev
drwxr-xr-x 41 root     root      4096  3月  2 11:23 etc
drwxr-xr-x  5 root     root      4096  3月  2 11:22 home
drwxr-xr-x 11 root     root      4096  3月  2 11:23 lib
drwx------  2 root     root     16384  3月  2 11:23 lost+found
drwxr-xr-x  2 root     root      4096 11月  9 13:25 media
drwxr-xr-x  9 root     root      4096  3月  2 11:22 mnt
drwxr-xr-x  8 root     root      4096  3月  2 11:22 opt
dr-xr-xr-x  2 root     root      4096 11月  9 13:25 proc
drwxr-xr-x  2 root     root      4096 11月  9 13:25 run
drwxr-xr-x  3 root     root      4096  3月  2 11:23 sbin
dr-xr-xr-x  2 root     root      4096 11月  9 13:25 sys
drwxrwxrwt  2 root     root      4096 11月  9 13:25 tmp
drwxr-xr-x 10 root     root      4096  3月  2 11:22 usr
drwxr-xr-x  9 root     root      4096  3月  2 11:23 var

partition 2 is mounted on ./mount/, remember umount when you're done to use.
```

# マウントできました！
これでクロス環境で開発中のアプリケーションのデプロイなどが簡単にできるようになると思います。
書き込み終わったら umount をお忘れなく。

よく使いたくなる？ものなので、別の解決策がありそうなものですが・・・
Ubuntu(WSL2)でAnacondaのインストール

# 環境
- WSL2
- Ubuntu-18.04

# Anacondaのインストール
## ダウンロードURLの取得
Anacondaの[公式サイト](https://www.anaconda.com/products/distribution#Downloads)から`Linux 64-Bit (x86) Installer`を右クリックして`リンクのアドレスをコピー`でURLをコピーする。
## インストーラの実行
`bash`や`Windows Terminal`で操作していく。
ダウンロードフォルダの作成。
```
$ cd ~
$ mkdir Download
$ cd Download
```
`wget URL`でインストーラのダウンロード
```
$ wget https://repo.anaconda.com/archive/Anaconda3-2021.11-Linux-x86_64.sh
```
`bash`でインストーラの実行
```
$ bash Anaconda3-2021.11-Linux-x86_64.sh
```
Enterを押し続けYesかNoか聞かれたらYesと答える。規約は`q`でスキップ可能。
コマンドを使用するためにパスを追加
```
$ echo "export PATH=~/anaconda3/bin:\$PATH" >> ~/.bashrc
$ source ~/.bashrc
```
condaのバージョン確認
```
$ conda -V
conda 4.10.3
```
ADR(Action-Domain-Responder)について簡潔にまとめてみた

# はじめに
ADRというソフトウェアアーキテクチャパターンがMVCよりも修正がしやすくて再利用性が高いということで調べてみたら結構良さそうだったからどんなものか忘れないために備忘録として記載する。

# ADRとは
Paul M. Jonesさんという方が提案したソフトウェアアーキテクチャパターンの一つです。
MVCと違って`1クラス1アクションクラス`なのでクラスが持つ責務がはっきりしているため、`再利用性が高くて保守もしやすい`です。

## 簡単な流れ

```ruby
HTTPリクエストから入力を収集(Action)
↓
ドメインを呼び出して入力情報を渡す(Action)
↓
結果を処理する(Domain)
↓
HTTP応答を作成(Responder)
↓
レスポンスを返す(Controller)
```

## Action
HTTPリクエストを受け取り、Domainからの処理結果をResponderに返す役割を果たします。
この中では特に処理を行わずにDomainやResoponderに値を渡したりする役割です。
みんなの橋渡し的な存在ですかね。
`Domain層で例外があったとしてもActionでは処理をしない`です。
Domainで独自の例外処理を行なって結果をActionに返すイメージです。

## Domain
渡されたHTTPリクエストに対して必要な処理を行い、結果を返します。
ビジネスロジックはこちらに書きます。
「この処理はDomainか？」と悩んでしまう場合があるかもですが、
`ストレージに触れるものはDomainに書け`とだけでも覚えておきましょう！

## Responder
Domainの処理結果を受け取り、必要な準備を行ってHTTP応答を構築するレスポンスを返します。


# 参考
[ADRという考えを取り入れてみて](https://www.slideshare.net/infinite_loop/adr-179015428)
[Action–domain–responder](https://en.wikipedia.org/wiki/Action%E2%80%93domain%E2%80%93responder)
[LaravelでのADR（Action-domain-responder）実装](https://www.ritolab.com/entry/164)
ラズパイにmavproxyをインストール

## 環境
RaspberryPi 4b
raspbian
mavproxy

## 事前確認
python3系のpipがインストールされているか確認し、無ければインストールする。
確認方法は以下コマンドを入力し、
```
pip3 --version
```
「コマンドがみつかりません」：インストールされていない。
「pip x.x from・・・」： インストールされている。

もし「コマンドがみつかりません」となった場合は以下実行。
```
sudo apt-get -y install python3-dev
```
```
sudo apt-get -y install python3-pip
```

## Mavproxy download and install
以下4ステップのコマンド入力のみでmavproxyのインストール完了する
```
sudo apt-get update
```
```
sudo apt-get install python3-dev python3-opencv python3-wxgtk4.0 python3-pip python3-matplotlib python3-lxml python3-pygame
```
```
pip3 install PyYAML mavproxy --user
```
```
echo "export PATH=$PATH:$HOME/.local/bin" >> ~/.bashrc
```
### 参考 
https://turtlechan.hatenablog.com/entry/2019/06/07/191450
https://ardupilot.org/mavproxy/
https://ardupilot.org/mavproxy/docs/getting_started/download_and_installation.html#linux
Gitlabでletsencryptの証明書の更新に失敗した時にやること

# はじめに

Gitlabをセルフホスティングしていると、どこかのタイミングでletsencryptの証明書の有効期限が切れることがあると思います。
本来は自動更新設定しておくべきですが、自分の場合は設定していたけどうまくいかなかったので期限が切れてから更新する羽目に。。

# やること

## gitlabをreconfigureする
[公式](https://docs.gitlab.com/omnibus/settings/ssl.html#manual-lets-encrypt-renewal)の解説に沿って、
以下のどちらかを実行します

```shell
sudo gitlab-ctl reconfigure
```

```shell
sudo gitlab-ctl renew-le-certs
```

## 上記を行なっても解決せず、Acme::Clinet::Error::AccountDoesNotExist と言われた時
エラー例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/2d7fc4ed-6dce-4d03-4222-bfb90cda3ae1.png)

一旦、acmeの証明書ファイルを消します。ただ、本当に消してしまうのは怖いのでmvファイルでbackupを取る形でデフォルト名のファイル(`account_private_key.pem`)を存在しない状態にします。
その後、設定の際読み込みを行います。

```shell
sudo mv /etc/acme/account_private_key.pem /etc/acme/account_private_key.pem.backup
sudo gitlab-ctl reconfigure
```
参考:
[GitLab – ACME AccountDoesNotExist](https://gbe0.com/posts/linux/server/gitlab-acme-account-does-not-exist/)

## ここまでやっても解決せず、以下のように Timeout during connect (likely firewall problem)と表示された場合

エラー例
```shell
letsencrypt_certificate[xxxxxxxxx.japaneast.cloudapp.azure.com] (letsencrypt::http_authorization line 6) had an error: RuntimeError: acme_certificate[staging] (/opt/gitlab/embedded/cookbooks/cache/cookbooks/letsencrypt/resources/certificate.rb line 41) had an error: RuntimeError: ruby_block[create certificate for xxxxx.japaneast.cloudapp.azure.com] (/opt/gitlab/embedded/cookbooks/cache/cookbooks/acme/resources/certificate.rb line 110) had an error: RuntimeError: [xxxxxxxxjapaneast.cloudapp.azure.com] Validation failed, unable to request certificate, Errors: [{url: https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/2125788808/DrHubA, status: invalid, error: {"type"=>"urn:ietf:params:acme:error:connection", "detail"=>"Fetching http://xxxxxxxxxxxxxx.japaneast.cloudapp.azure.com/.well-known/acme-challenge/xxxxxxxxxxxxxxxx: Timeout during connect (likely firewall problem)", "status"=>400}} ]
```

エラー文言からわかるように、firewall関連の問題と推察できます。
自分の場合は、AzureVMのネットワーク設定でIP制限をかけていたので、それが更新を邪魔していたようです。
エラーに表示されている`http://xxxxxxxxxxxxxx.japaneast.cloudapp.azure.com`へのリクエストが通るように,port80に対してのインバウンドIP制限を一時的に取っ払ってから、再度`sudo gitlab-ctl reconfigure`したところ、証明書を更新できました

おそらく、このIP制限によって自動更新もうまくいかなかったのでは？と考えています。今後検証予定。

# おわりに
いかがでしたでしょうか。あまりドンピシャなトラブルシューティング記事が見つからなかったので記事にまとめてみましたが、どなたかのお役に立てれば幸いです。
9回目　IPアドレス

今回はIPアドレスについて解説する
![IPアドレス1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/c6dcf0c5-0d99-4242-64a2-5136416ae6d8.png)

第一分岐点（IPアドレスの問題）
第二分岐点（問題の解決策）

### はじめに
IPアドレスとはネットワーク上の住所。
同じような数字をよく見かける気がしたので、調べた。
![IPアドレス2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/6958ea9e-656d-cc54-fcdf-afbd05c0445c.jpeg)

#### IPアドレスの読み方
IPアドレスは32ビットの数字で表される
192,168,000,002（10進数）
10111111，10101000,00000000,00000010(2進数)
のように8bit×4つの32ビット構成となっている。
ネットワーク部とホスト部に分けることができ、ホスト部では、ネットワーク内のコンピュータに割り振られる。電話番号でいうと0120ー11－2222　市外局番と市内局番と2222の番号といったイメージ

#### IPアドレスの分け方
クラス分けというものがありABCの3つに分けられる。
IPアドレスの最初の文字・・・ネットワークを構成するパソコンの台数
A、1～126・・・1600万
B、128～191・・・65000
C、192～223・・・254
127、224～255は通常のIPアドレスとしては使われていません。
サブネットマスクは255,255,255,0をIPアドレスと組み合わせて、分別する。本番環境と開発環境を分けるといったような際に利用されることがある。

#### IPアドレスの枯渇について
IPV4では2の32乗が理論上使用できるが、ネットワーク増加に伴いそれだけでは足りなくなってきたらしい。
そこで解決策としてあげられたものを2つ取り上げる
一つはプライベートアドレスとグローバルアドレスに分ける方法である。
プライベートアドレスは主にLAN内で使わるもので、パソコンやスマホなどLAN内のみで、通じるアドレスとなっている。住所の後の氏名に例えられる番号自体は重複することもあるが人自体は別人。
一方で、グローバルアドレスは主にWANなどのネットワークで利用されるもので、全世界で別々のアドレスがルータに割り振られている。住所に例えられる重複はしない。
このプライベートアドレスとグローバルアドレスを変換する機能がNATと呼ばれる。
（Network Address Translation）

### まとめ
ネットワークアドレスは、32ビットで表されるネットワーク上の住所である。利用するネットワークによって番号のふられ方が分けられており、一般の家庭であると192、168～～と続く形をよく目にする。IPアドレスネットワークの増加に伴い重複しないよう解決策がとられているので、それも勉強する必要がある。
きれいに書きたいPythonプログラミング、マジックナンバーについて

# まとめ
1. その意味や意図が記述した本人以外には自明では数値や文字列を**マジックナンバー**と呼ぶ。
2. **マジックナンバー**は、1.から意図が読みにくいので避けるべき。
3. 1.にもある通り数字だけでなく文字列でも**マジックナンバー**を避けるべき。

# 参考文献
1.は`Python`できれいなコードを書くためのヒントをまとめた書籍となっています。2.は、**マジックナンバー**の辞書的な意味を調べるのに使いました。

1. https://book.mynavi.jp/ec/products/detail/id=127578
2. https://e-words.jp/w/%E3%83%9E%E3%82%B8%E3%83%83%E3%82%AF%E3%83%8A%E3%83%B3%E3%83%90%E3%83%BC.html

# 具体例：数値のマジックナンバーについて
本記事ではまず、1時間15分の試験を今から始めた場合の試験終了時刻を求めた値を`time_limit`という変数に格納するような操作を考えます。

### よくないと思われるマジックナンバー(数値)の例
まずは、以下によくないと思われる例を用意します。一般的に`snake_case`に則って変数名を決めるため出てくる変数`time_limit`もそれに則りました。そしてこの`4500`という値について、`time`をインポートしていて変数も`time_limit`なのでなんらかの期限となる時刻と関係することまでは容易に伝わると思いますが、これが1時間15分の秒数であるというのは伝わりにくいかと思います。

```python
import time
time_limit = time.time() + 4500
```

### マジックナンバーを排除した例
次に、**マジックナンバー**を排除した例を記載します。`Python`だとなるべく定数として扱いたい変数は大文字で表記することが多く、追加した変数2つはそれに則りました。`SECONDS_PER_MINUTE`は1分に含まれる秒数を表し、`MINUTES_PER_TEST`は1試験時間に含まれる分数を表しています。それらを使って変数`SECONDS_PER_TEST`という1試験時間に含まれる秒数を格納する変数を作りました。これで、コードから`time_limit`が何を指すのかは見えやすくなったはずです。

```python
import time
SECONDS_PER_MINUTE = 60
MINUTES_PER_TEST = 75
SECONDS_PER_TEST = SECONDS_PER_MINUTE * MINUTES_PER_TEST

time_limit = time.time() + SECONDS_PER_TEST
```

また、当たり前ですが別の意図によって作られた同じ値を持つ変数は分けておかなければなりません。例えば上の場合`MINUTES_PER_TEST`は75ですが、`MINUTES_PER_TEST`が60だった場合`SECONDS_PER_MINUTE`と同じ値だから`SECONDS_PER_MINUTE`を`MINUTES_PER_TEST`のように扱うようなことは避けるべきです。

# 具体例：文字列のマジックナンバーについて
次に、`sakana`定食と'niku'定食のどちらを頼むかを`input()`で受け取って、もし受け取った値が`niku`の場合`niku定食は売り切れとなっています。申し訳ございません。`と表示するような操作を考えてみます。ここで受け取る値は、`sakana`と`niku`の2つの値のみを想定しているということにします。

### よくないと思われるマジックナンバー(文字列)の例
下記の場合はエラーとなりませんが、`niku`と受け取ってもそれは誤字で記述された`niki`ではないので何も返ってきません。変数`order`と比較することはできますが、誤字によってすり抜けてしまっています。ですので、誤字をしない以外という意識以外にも用意できるなんらかの工夫をしたほうがよいと思われます。

```python
order = input("sakana定食かniku定食を選んでください。")
if order = "niki":
  print("niku定食は売り切れとなっています。申し訳ございません。")
```

### マジックナンバーを排除した例
次に、**マジックナンバー**を排除した例を記載します。`NIKU`という変数を用意し、比較用に準備しました。同じような誤字をしてしまっていますが、この場合すり抜けることはなくエラーが発生するのでそれに対処する形で修正できます。このような単純な例だとそこまで深刻な話でもないのですが、受け取った文字列によって何らかの特別な操作が必要な場合このような工夫をしたほうがよいと思われます。

```python
NIKI = "niku"

order = input("sakana定食かniku定食を選んでください。")
if order = NIKI:
  print("niku定食は売り切れとなっています。申し訳ございません。")
```

# 感想
- そこまで強く意識していなかった部分なので、気をつけていきたい。
  - <del>リーダブルコードを積ん読にしてN年が経過しました。</del>

# 次にやる、この記事に関連すること

- 参考文献1.をもう少し読み込む
  - <del>リーダブルコ(死後強まる念)</del>
ラズパイ　シリアルポート(USBポート) 確認

## ラズパイでUSBに接続した部品のシリアルポート(USBポート）を確認する方法
①確認したい部品(該当部品）をUSBから外した状態で以下コマンド
```
ls /dev/ttyACM*
```
②確認したい部品（該当部品）をUSBに接続した状態で以下コマンド
```
ls /dev/ttyACM*
```

①で表示されず、②で表示された
ttyACM※ (※は数字）
が該当部品のシリアルポートです。
javascript同期処理用の簡単なテンプレ

# 主旨

普段jsを使いません。
なので、ネットに転がっている同期処理のソースコードは読みづらかったです。
健忘な自分にとってわかりやすい簡単なテンプレートを投稿しておきます。

# テンプレ本体

```javascript:temp.js

// ↓この行は無視。事前知識が必要なため。
const sleep = second => new Promise(resolve => setTimeout(resolve, second*1000));


// ↓ここからが主な部分。

// 実行したい処理を関数として定義する。
function f1() {
  console.log("f1");
}
function f2() {
  console.log("f2");
}
function f3() {
  console.log("f3");
}

// この関数の中に処理の流れを記述する。sleepは処理間の待ち時間。
async function work(_n) {
  f1();
  await sleep(_n);
  f2();
  await sleep(_n);
  f3();
}

// 待ち時間nを設定する。
const n = 3;
// 本処理を実行する。
work(n);

```

## 使い所

一度使ったらそれっきりの使い捨てスクリプトを書くときが使い所だと想定しています。

## 使い方

### 埋める点

テンプレですから、実際に使う際に埋める場所があります(埋める場所以外は見ない振りです。何か問題が起きたら見ればいいことです)。
下記3点を埋めます。

1. __各fの名前と中身 : 順番に実行したい関数を、自分のつけたい名前と中身で定義してください。__ 例では3個になっていますが、9個でも27個でも構いません。
2. __work関数の中身 : 処理したい順序で上から順に、実行したい関数を並べてください。__ 各関数の間にsleepを挟むことを忘れずに。
3. __nの値 : 処理と処理の間に挟みたい秒数は何秒ですか？ その秒数をnに格納してください。__ つまり、n秒ごとに各fを次々に実行します。例えば、上記コードでは3秒毎になっています。また、n=0とすれば、間隔を開けずに、単に各fを上から順番に実行します。

### 蛇足

ここまでのことを例え話にすると、食パンを食べたいと思ったときのことを考えるとよいです。

1. func1 : 食パンを買う
1. func2 : 食パンを袋から出す
1. func3 : 食パンを食べる

みたいにしてfuncの中身を実装して、順番が狂ってはならない手順を実行できます。

つまり、このテンプレを使うと、食パンを買ってないのに袋から出して食べてしまったり、食パンを袋から出さずに食べてしまうことを防げます。
お腹が空いていたらn=0です。あまり空いていないならn=72000です。

(追記：実行順序について次の投稿にて少し実験してみています。これによると、順番が狂う心配はせずに済みそうです。[【未完のメモ】jsのasync/awaitについての実験](https://qiita.com/cp3/items/e554e651c2eac6038da9)。ただ、テンプレのようにsleepにawaitを付けないとsleepが機能しないことははっきりしました。)

# 反省

動けばいいのでやっつけな作りです。
時間が作れたらベストプラクティスについて学ぶつもりです。
Flowからアラートメールをメールテンプレートから作成する時の注意


# Lightning Email templatesではContact and Lead objectsは使えない。

+ [Please, help to find what is the problem with my email template](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000Jfb4TSAR)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/f74911d1-594e-1857-df55-da0927686bba.png)


:::note
 Merge fields are not yet available for Contact and Lead objects (this is on Salesforce’s roadmap) in Lightning Email templates. Ref : https://www.salesforceben.com/your-complete-guide-to-salesforce-lightning-email-templates/


差し込み項目は、Lightning メールテンプレートの取引先責任者オブジェクトとリードオブジェクト (これは Salesforce のロードマップにあります) ではまだ使用できません
:::

# 以前の回答


 Error Message: core.email.template.TemplateRenderingException: We don't recognize the field prefix Recipient. Associate a record that matches the prefix or update the template to remove the merge field from the body, subject, or letterhead.

メールテンプレートを処理できませんでした。エラーメッセージ：core.email.template.TemplateRenderingException：フィールドプレフィックスRecipientを認識しません。プレフィックスに一致するレコードを関連付けるか、テンプレートを更新して、本文、件名、またはレターヘッドからマージフィールドを削除します。

どうもLightningのメールテンプレートでは　{{{Recipient.FirstName}}}が認識していないみたい。

数式フィールドを作って回避したようです。

[Flow - Email Alert to Case Contact](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000GeNIV)


# 同じような投稿

+ [Email Template Error in Flow](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000H0NmjSAF)
+ [Flow and Email Template on Contact Object](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000JdpTHSAZ)

+ [Error Message: core.email.template.TemplateRenderingException: Unable to retrieve object](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007ah9JZSAY)
【Ruby】def hoge=(fuga) という書き方

# 本題
Qiita や企業の技術ブログを見ていて，`def hoge=(fuga)` という書き方がありました．

```ruby
class Author
    def authors_attributes=(attributes)
        @person_attributes = Person.new(attributes)
    end
end
```

`hoge=` で一つのメソッド名を表しています．
値の設定専用のメソッド（つまりセッター）ということを表すために，よく使われる書き方みたいです！知りませんでした！

呼び出すときは，以下のような書き方だけではなく，

```ruby
Author.authors_attributes=(attribute)
```
以下のような書き方もできるみたいです．
```ruby
Author.authors_attributes = attribute
```

# 参考記事
https://teratail.com/questions/248629

下の記事では，セッターの関数名に`hoge=` という書き方が使われています．

https://qiita.com/k-penguin-sato/items/5b75be386be4c55e3abf

https://docs.ruby-lang.org/ja/3.1/doc/spec=2foperator.html#assign