OmniAICreator/Qiita-1.07M huggingface dataset:
ESP32のWiFi出力強度を調整してみた

現在ESP32を使用した製品を開発しているのだが
エミッション試験（EMI）をした際に4.8GHzが既定値以上の
ノイズ電波を出力していることが分かった。

どうも調べてみると2.4GHzの高調波による影響で
4.8GHzの値が高くなっているようだ。

しかもよくよく調べると2.4GHz自体も異常に高い・・・

**なんでだ？**

どうも2.4GHzの出力は、デフォルト時**19.5dBm**になってるらしい！


**19.5dBm**は高すぎる!!

通常のノートPCの出力が15dBm程度なのでこれは調整が必要だ！！

調整をするには「setTxPower」という関数を使えばいいらしい！
以下にサンプルを記載する。
```c
#include <WiFi.h>

const char* ssid     = "yourssid";
const char* password = "yourpasswd";

WiFiServer server(80);

void setup()
{
    Serial.begin(115200);
    delay(10);

    // We start by connecting to a WiFi network
    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);
    delay(500);
    WiFi.setTxPower(WIFI_POWER_15dBm);//←ここがWiFi出力を調整するところ

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();
}
void loop(){
}

```
今回はノートPCに合わせて出力を**15dBm**に設定した。
なおその他の設定できる値を以下に記載しておく
```c
    WIFI_POWER_19_5dBm = 78,// 19.5dBm
    WIFI_POWER_19dBm = 76,// 19dBm
    WIFI_POWER_18_5dBm = 74,// 18.5dBm
    WIFI_POWER_17dBm = 68,// 17dBm
    WIFI_POWER_15dBm = 60,// 15dBm
    WIFI_POWER_13dBm = 52,// 13dBm
    WIFI_POWER_11dBm = 44,// 11dBm
    WIFI_POWER_8_5dBm = 34,// 8.5dBm
    WIFI_POWER_7dBm = 28,// 7dBm
    WIFI_POWER_5dBm = 20,// 5dBm
    WIFI_POWER_2dBm = 8,// 2dBm
    WIFI_POWER_MINUS_1dBm = -4// -1dBm
```

みなさんも製品を作る際は、異常な放射ノイズを出す製品を
作っていないかきちんとエミッション試験をしてくれ！
【PHP】スタックとは？【基本情報】

# スタックとは？
格納した順序とは逆の順序でデータを取り出すことのできる（LIFO）データ構造。
データをスタックに格納することをプッシュといい、PHPでは、array_push()がある。
データをスタックから取り出すことをポップといい、PHPでは、array_pop()がある。

array_push()
→一つ以上の要素を配列の最後に追加する
array_pop()
→配列の末尾から要素を取り除く

# 参考文献
PHPマニュアル（array_pushのページとarray_popのページ）
https://www.php.net/manual/ja/function.array-push.php
https://www.php.net/manual/ja/function.array-pop.php
栢木厚，栢木先生の基本情報技術者教室（令和2年版），技術評論社，2020
Unity2021年版ラジオボタンの再現方法

# 1.記事を書こうと思ったきっかけ
　仕事でUnityのUIでWebであるようなラジオボタンの実装を要求されたわけですが、既出の情報が古いせいか、2021年版のUnityでそれを再現しようとして上手くいかず、数時間溶かしてしまったため、今後似たような案件が来た時のために備忘録を残しておこうという気になったからです。

# 2.作り方
## 2-1.Toggleを追加する
・ヒエラルキーウィンドウ→+ボタン→UI→Toggle
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167908/eca5d5e8-0138-fb36-cf85-9a6bd2f0b952.png)
　これでヒエラルキーウィンドウ上にUIとトグルが出現します。ラジオボタンですので複数から一つを選択するわけですから同様の手順でトグルをもっと召喚します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167908/56cf545b-27b0-38b5-eba9-c61da4c3f4e3.png)

## 2-2.召喚したToggleのどれか一つにToggle Groupコンポーネントを追加
　今回はToggle1にアタッチさせましたがこれもToggleならどれでもいいです。
・Add Component→Toggle Group
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167908/34b4ed44-0418-7c85-b70b-3487e89ca6b4.png)

　これでToggle1にToggleグループがアタッチされました。Toggle1のインスペクターウィンドウを下までスクロールしたらこうなってると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167908/66bc2302-bebd-fea3-ab8b-244ed51d1e36.png)

　ご覧の通り一番下にToggle Groupコンポーネントが追加されています。Allow Switch Offの項目はラジオボタンのチェック項目を全て未チェック状態にするかどうかを決めるための要素になってきます。こちらにチェックを入れるとチェック中の箇所を再度クリックすると全てのチェックが外れた状態にできます。

## 2-3.全てのToggleのインスペクタービューからIs Onの項目を探し、チェックを外す
　何も考えずに探して外しましょう。これを外さないと実行時に項目がチェック状態になっちゃってます。ラジオボタンをポチポチするどころの話じゃありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167908/ae92ad49-a09f-722b-aa7e-9617194db8b6.png)


## 2-4.全てのToggleのGroup項目をラジオボタンの選択対象となるグループ名で指定しておく
　既出の記事との相違点はここになってきます(それとも既出の情報が言葉足らずなだけか…？)。そのことはさておき、本題に戻りますと、ラジオボタンの選択項目として追加したい全てのToggleのGroup項目について先ほどToggle1に追加したToggle Groupコンポーネントで統一してひとくくりにしていきます。

　任意のToggleのインスペクターウィンドウを表示し、下の方にスクロールしていきますと、Groupの項目があります。右側の◎をクリックしてグループとして使えるリストを表示してみますと、Toggle GroupをアタッチさせてあるToggle1が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167908/1b49324d-b902-5670-a549-b4c5aa052344.png)

　このToggle1をダブルクリックしてGroupにToggle1を指定しましょう。指定したらこうなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167908/2f43072f-607c-ae60-0492-707922dcae5f.png)

　これを選択項目の対象となる全てのToggleで行いましょう。Toggle GroupがアタッチされているToggleも例外なくです。既出の情報ですと、Toggle GroupがアタッチされているToggleについてはGroupの項目の指定について特に何も記述がなく、指定しなくても大丈夫という印象を受けましたが、指定しておかないとToggle1だけグループから除外されてしまうという処理がされてしまいます。

　ともかく、上記の手順でUnityのUIでラジオボタンを再現することができるわけです。

# 3.まとめ
　やっぱりゲームエンジンなだけあってWebと違って面倒くさいです。しかも定期的なバージョンアップで仕様変わるし…。仕事である以上触ってますがWebが恋しくなります。
JetpackCompose BottomNavigation の基本的な構成


![Reflector Recording.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588914/2d744d55-4699-e0c5-c0ae-216c5210948e.gif)


# 構成

シンプルに構成します。

![スクリーンショット 2022-08-18 19.14.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588914/59a48ebe-9e3f-b6a0-f24b-fb8f0a4ff13f.png)

メイン画面を表示する部分は

<code>「NavHost」</code>、

それを表示切り替えする下側に並んだ操作部分は

<code>「BottomNavigation」</code>

です。

コードは以下のように構成できます。

```kotlin
@Composable
fun MainScreen() {

  val navController = rememberNavController()

  Column {

    NavHost(
      navController = navController,
    ) {
      composable(NavigationItem.HOME.route) {
        HomeScreen()
      }
      composable(NavigationItem.CRYPT.route) {
        CryptScreen()
      }
      // ...
    }

    BottomNavigation {
      val backStack by navController.currentBackStackEntryAsState()
      val current = backStack?.destination?.route
      NavigationItem.values().forEach { item ->
        BottomNavigationItem(
          // ...
        )
      }
    }

  }

}
```

まずは、シンプルに見通しよく構成できます。
[👉 【JetpackCompose】BottomNavigation の使い方](https://android.benigumo.com/20220818/bottomnavigation/)
CodeCommitのgit clone時にfatal: repository <リポジトリURL> not foundが出た場合の対処法

## 事象
複数のAWSアカウントでCodeCommitでリポジトリを作ってgit cloneしたところ、not foundのエラーが出力された。
```
$ git clone <リポジトリURL>
Cloning into '<リポジトリ名>'...
fatal: repository '<リポジトリURL>' not found
```

## 結論（対処）
namespaceを作って、そのnamespaceに対する認証情報を登録してあげる。
```
$ git -c credential.namespace=<任意のnamespace名> clone <リポジトリURL>
[windowsだとここで認証情報問われるので該当AWSアカウントで発行したCodeCommit用の認証情報を入力]
Cloning into '<リポジトリ名>'...
$ cd <クローンしたリポジトリのディレクトリ>
$ git config --local credential.namespace <2つ上のコマンドでクローン時に指定したnamespace名>
```

## 原因と解説
別AWSアカウントの認証情報が使用されていたため、エラーとなった。  
namespaceを設定することでnamespace内でのみ使用する認証情報が保存される。

## 参考
https://syunkan81.hatenablog.com/entry/2022/01/14/110000
ApresiaNPシリーズ　SDカード運用について

**はじめに**
---
自分がネットワークエンジニアになってから、Cisco機器より多く触れてきたAPRESIA Systems 株式会社製品のNPシリーズ。
NPシリーズの特徴の一つにSDカードによるバックアップの保存・運用があります。
今回はそのSDカードについて、運用や自分が実際試してきた運用について記事にしましたので、参考にしていただけたら幸いです。



***目次***
---
・SDカードの機能について
・SDカードの利用準備手順
・機器故障時の交換手順

***SDカードの機能について***
---
APRESIA Systems 株式会社の製品にはいくつかSDカードを用いて運用が可能なものがあります。
その一つにNPシリーズというものがあります。
NW機器が故障した際、通常、故障した装置と同じブートイメージファイルや構成情報を代替装置に設定する必要があり、手間や時間がかかります。
しかし、SDカードを用いることでこの時間が短縮でき、SDカードを代替装置に挿入して起動するだけで、故障した装置と同じ状態に設定された代替装置を簡単に起動することができます。


***SDカードの利用準備手順***
---
SDカードからブートイメージファイルや構成情報を読み込み、装置を起動させることをSDカードブートと言います
SDカードブートでは、ブートスクリプト、および動作に必要なファイルを、あらかじめSDカードにコピーする必要があり、準備を行うには、backup cloneコマンドを使用します。

装置にSDカードが挿入されている状態であれば、write memoryやcopy running-config startup-configコマンドを使用したとき、構成情報はデフォルトでは装置本体とSDカードの両方に保存されます。

<div class="code-frame" data-lang="text"><div class="highlight"><pre><code>ApresiaNP# write memory

Destination filename startup-config? [y/n]:  y

Saving all configurations to NV-RAM.......... Done.
Saving all configurations to SD-Card......... Done.
</code></pre></div></div>


注意点として、backup cloneコマンド実行時にSDカードには元々装置に存在しないファイルはコピーされません。

write memoryやcopy running-config startup-configコマンドを使用時の保存先は装置本体とSDカードで設定されているPrimary boot configで設定されているファイルとなっています。
そのため、装置のPrimary boot configを誤ってSDカードのファイルなどにしているとSDカードが抜けている状態だと起動してこなかったり、Secondary boot configから構成情報を読み取り起動するため注意が必要となります。
装置のboot imageやboot configは設定変更可能ですが、NPシリーズのSDカードは設定変更が出来ません。

<div class="code-frame" data-lang="text"><div class="highlight"><pre><code>ApresiaNP# show boot

Unit 1
*(Configured) 
 Primary boot image: /c:/AEOS-NP2000_R10501.had
 Primary boot config: /c:/primary.cfg
 Secondary boot image: /c:/AEOS-NP2000_R10501sec.had
 Secondary boot config: /c:/secondary.cfg
(SD Card) 
 Primary boot image: /d:/apresia-software.had
 Primary boot config: /d:/apresia-startup-config.txt</code></pre></div></div>

***機器故障時の交換手順***
---
機器が故障した場合、通常のネットワーク機器であれば一度ネットワークケーブルなどで管理端末やサーバなどと接続してからバックアップを移し、リストアを行ったりする必要があります。

Apresiaの機器でもそれらが可能ですが、SDカードで運用している場合、そのSDカードを新しい機器に差し替えるだけですぐに運用に移ることができます。

Apresiaの特性上、起動時にSDカードからConfig情報を読み取るため、機器にconfig情報がなくても問題ありません。
また、起動後に【write memory】などの保存コマンドを実行することで自動的に機器のstartup-configにも保存されます。
それ以外の構成情報についても【restore memory-card:】を実行することですぐに機器に構成情報がリストアされます。
リストアされる内容については【backup clone】コマンドと同様になります。

スタック時なども同様で、SDカードを差し替えることで自動でスタックに組み込まれます。
本来Masterで動いていた機器が故障した場合は、Catalystなどと同様にMemberとしてスタックに組み込まれますので、別でMasterに切り替える手順(preempt設定など)が必要になります。

以上が機器故障時の交換手順の説明になります。

***参考URL***
---
https://www.apresia.jp/products/ent/np/usersguide/management/top.html

***最後に***
---
今回はApresiaNPシリーズ製品のSDカードについて記事にしました。
今後、Apresiaに触れる方の参考になれば幸いです。
WSLからSSH先のRSSリーダーのブラウザで開くを手元のFirefoxで開く

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209562/ba223eac-2d5b-c308-7faf-2630c4ca92ba.gif)

## TL;DR

以前に通知ロジックを実装した．

https://qiita.com/anya-tokugawa/items/9d92d2788ff1e640f049

現在リモートの「mysrv」で色々作業しているが，ニュースみるとき，ブラウザ操作がめんどくさい．そこで，CLIのRSSリーダーである「`newsboat`」を入れたが，ウェブブラウザで見たいときにすぐ開けないと困る．

なので，リモートのLinux環境のリクエストに対し，手元で開くようにした．

## wsl-revshell-server.sh

スクリプトの大体のロジックは通知ロジックと同じ．アイコンの設定やアラームの設定箇所を消してそのままPowershell上で実行するように変更した．

今回は，特異箇所だけピックアップする．

1. powershellで実行する際は`start https://www.example.com` のように送ればデフォルトブラウザ（i.e. Firefox in me）で開かれる．
2. Port番号: 通知用のポートが`47123`なので，今回は`47124` を利用した．
3. sshコマンドのエイリアスについて

### 3. sshコマンドのエイリアス

前回は単純に，

```bash
# sshするときにプロキシ張る
alias ssh='ssh -R ${WSL_NOTIF_PORT}:localhost:${WSL_NOTIF_PORT}'
```

と実装した．これだと，`47124`が使えないので，

```bash
export SSH_OPTS="-R ${WSL_REVSH_PORT}:localhost:${WSL_REVSH_PORT} $SSH_OPTS"
alias ssh="ssh $SSH_OPTS"
```

とし，前回の実装は

```diff
diff --git a/custom-available.d/wsl-notification-server.sh b/custom-available.d/wsl-notification-server.sh
index b3b4d07..780b87a 100644
--- a/custom-available.d/wsl-notification-server.sh
+++ b/custom-available.d/wsl-notification-server.sh
@@ -100,4 +100,5 @@ wslnotify() {
   fi
   echo "$sound $text" | nc -w1 127.0.0.1 "$WSL_NOTIF_PORT"
 }
-alias ssh='ssh -R ${WSL_NOTIF_PORT}:localhost:${WSL_NOTIF_PORT}'
+export SSH_OPTS='-R ${WSL_NOTIF_PORT}:localhost:${WSL_NOTIF_PORT}'"$SSH_OPTS"
+alias ssh='ssh -R ${SSH_OPTS}'
```

こんな感じに変更．

## リモート側の設定

### ブラウザの起動コマンド

`~/.local/bin/www-browser` として下記のようなスクリプトを放り込んだ．

```bash
#!/bin/bash
echo "start $@" | nc 127.0.0.1 47124 2>/dev/null
```

### newsboatの設定

newsboatでブラウザ指定．

https://askubuntu.com/questions/1256425/how-to-open-newsboat-feed-in-browser

`~/.newsboat/config`

```config
browser "~/.local/bin/www-browser %u"
```

-----

上記で快適にRSSを読むことができそうだ．
cam2web 3Dカメラサーバーの自動起動設定

# はじめに
以前に紹介した、「Raspberry Pi, Nano Piを使った3Dカメラ ネットワーク サーバーの構築方法」の続きになります。
今回は、実際にRaspberry Pi4で自動起動するための手順について説明します。他のSBCでも同様に使えると思いますので、参考になればと思います。
SBCには、あまり詳しくはないのでいろいろと調べてみました。

https://qiita.com/nextEDGE-aeroTAP/items/6b81447aff41e9956787

# ライブラリパスの設定
自動起動するには、export LD_LIBRARY_PATH のように環境変数に毎回設定するのではなく、システム全体に設定します。
ここでは、ldconfigに登録します。

/etc/ld.so.conf.dに aerotap.conf を作成します。
```ruby:qiita.rb
sudo nano /etc/ld.so.conf.d/aerotap.conf
```

以下の行を記載して、保存します。( Raspberry Pi 32bitの場合)

```ruby:qiita.rb
/home/pi/cam2web-aeroTAP/src/core/cameras/aeroCAM/lib/linux_arm/
```
*64bitは、linux_arrch64を指定


ldconfig を実行して反映し、反映されていることを確認します。
```ruby:qiita.rb
sudo ldconfig
sudo ldconfig -p | grep aero
```

# 自動起動設定
自動起動の設定は、systemdを使います。
まず、/etc/systemd/system にcam2web.serviceを作成し、下記を記載します。

```ruby:qiita.rb
[Unit]
Description=cam2web

[Service]
Type=simple
WorkingDirectory=/home/pi/cam2web-aeroTAP/src/apps/linux
ExecStart=/usr/bin/bash -c 'sleep 30;/home/pi/cam2web-aeroTAP/src/apps/linux/cam2web -device:"aeroTAP 3D USB GS Camera"'
Restart=on-failure
StandardOutput=null

[Install]
WantedBy = multi-user.target
```
:::note info
ExecStart= では、システム起動後30待機させています。
-device:"" は、接続しているカメラの名前を記載します。
:::

以下のコマンドを実行して、正しく開始できるか確認します。
```ruby:qiita.rb
sudo systemctl start cam2web.service
```

以下のコマンドを実行して、正しく状態を確認します。
```ruby:qiita.rb
sudo systemctl status cam2web.service
```
正しく設定されていれば、これをsystemdに登録します。

```ruby:qiita.rb
sudo systemctl enable cam2web.service
```

以上で完了です。再起動してください。



# 参考文献

[systemdによる自動起動（Linux）](https://www.souichi.club/technology/systemd/)
DNS Abuse とは

## 勉強前イメージ

なんて読むんやろ

## 調査

### DNS Abuse とは

アビューズと読み、DNSやドメイン名の登録手続きが関連した不正行為のことを指します。
どういう行為があるかというと以下の様なものがあります。

- 迷惑メール送信に利用
- マルウェアでの利用
- 海賊版サイトでの利用
- ドメインハイジャック

上記の利用が不正行為ということからDNS Abuseの範囲は広くどこからどこまでがDNS Abuseかはまだ定義されていませんが
基本的には不正行為になるものは該当するような感じになっています。

## 勉強後イメージ

書いてある行為以外にもいろいろあったので
詐欺とかに使ったり、そういうのは基本的にアウトだと思う

## 参考

- [DNS Abuseとは](https://www.nic.ad.jp/ja/basics/terms/dns-abuse.html)
役に立つ覚書

mapとfilterを使っただぶり削除の処理

```js
    const noDuplicationTimeList = resultEntries
      .map((elem) => elem)
      ?.filter(
        (element, index, self) => self.findIndex((e) => e === element) === index
      )
```

```js
    const categoryName = resultEntries
      ?.filter(
        (element, index, self) =>
          self.findIndex((e) => e === element) ===
          index
      )
      .map((elem) => elem)
```
【Rails】ヘッダーのドロップダウンをレスポンシブ対応

# はじめに
[こちら](https://qiita.com/vaza__ta/items/921b748df585bbbb4300)の記事で、ヘッダーをレスポンシブ対応するため、overflow-x: autoを実装した。
それにより表示領域から溢れた時はスクロールバーが表示されるようになった。

しかし、それによってドロップダウンの表示もスクロールバーが表示されるようになってしまった。
![scroll1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684787/c1bfb901-6074-ca79-6b91-1229582efdc9.gif)

そこで、スクロールバーに対応するoverflow-xの適応を、ウィンドウサイズの横幅が750px以下の時にのみにすることにした。理由としては下記となる。
・約770px以下からbootstrapによってヘッダーの表示フォーマットが変わる
・それ以下の750px以下であれば、overflowを設定してもドロップダウンがスクロールバー表示にならない
![scroll2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684787/b5ed4352-66a9-f6e6-5cf4-d18728d99c61.gif)

# 環境
| No |    項目     |   内容    |
|---:|-------------|------------|
| 1  |      OS       |   Mac     |
| 2  |       Ruby      |   2.6.3   |
| 3  |       rails      |      6.0.4 |
4|bootstrap-sass| 3.4.1　
5|sass-rails|5.1.0

# 実装
[こちら](https://study-hobby.com/2021/05/31/%E3%80%90rails%E3%80%91%E3%82%B9%E3%83%9E%E3%83%9B%E3%80%81pc%E3%81%A7%E7%94%BB%E9%9D%A2%E8%A1%A8%E7%A4%BA%E3%82%92%E5%A4%89%E3%81%88%E3%82%8B%E3%81%AB%E3%81%AF%EF%BC%9F%E3%80%9C%E3%83%AC%E3%82%B9/#toc2)の記事を参考に実装する。
# htmlのheadタグにviewportを追加する
```html:layouts/application.html.erb
<%# width=device-widthにてブラウザの大きさをデバイスに合わせる。initial-scaleは画面の拡大率 %>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
```
# cssファイルに適用したいスタイルを書く
　今回は、750px以下でoverflowの設定を適用することにする。
```css:custom.scss
  // 画面サイズが750px以下の場合
@media (max-width: 750px) {
  .navbar-right {
    overflow-x: auto;
  }
}
```
# おわりに
これで、750px以上では特にレスポンシブ対応せず、750px以上でスクロールバーを表示させることで、ドロップダウンのスクロールバー表示を防いだ。
今回bootstrapとの共存させているため、複雑になってしまったが、もっとシンプルな方法もあるかと思う。
Chrome開発者ツールを利用して、Workatoのジョブ実行数やタスク実行数をJSON形式や表形式でさくっと取得する

# はじめに
日々のメンテナンスや契約管理の際、Workatoのジョブ実行数やタスク実行数をさくっと取得したい場合があります。
このような場合は、次のコードをChrome開発者ツール上で実行することでJSON形式、あるいは表形式でその結果を取得することができます。
取得した結果は、Excelやスクリプト上へ読み込んで利用することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/7e8e726a-0610-ad7a-6b89-9d86b6cf365d.png)

# 手順
## 1. Workatoへログインします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/334c4c51-1535-44b9-66c3-426a7a97fab6.png)

 
## 2. Chrome開発者ツールを開き、コンソールへ以下のコードを入力し、実行します。

### コード
|変数|値|
|:-------|:---------|
|startDate |開始日時(ISO8601形式)|
|endDate |終了日時(ISO8601形式)|
|sortTerm|ソートキー|
|sortDirection|昇順(asc)・降順(desc)|


```javascript

const baseUrl = 'https://app.workato.com/dashboard/flows.json';
const startDate = '2022-07-01T00:00:00.000+09:00';
const endDate = '2022-08-01T00:00:00.000+09:00';
const sortTerm = 'action_count';
const sortDirection = 'asc';
const url = baseUrl 
    + '?started_at_from=' + startDate
    + '&started_at_to=' + endDate 
    + '&sort_term=' + sortTerm
    + '&sort_direction=' + sortDirection;
let offset = 0;

let result = (await (await fetch(url)).json()).result;

// JSON形式で出力
console.log(result.flows);

// 表形式で出力
console.table(result.flows);
```

## 3. 出力結果を右クリックし、「objectをコピー」をクリックします。
コピーした内容がクリップボードに格納されます。コピー後、テキストエディタ等へ貼付して利用してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/5683e476-6457-2617-b1cb-5e4cda09e44e.png)
【Swift】CocoaPodsに自作ライブラリを登録する時躓いた

ライセンスめんどくさいし自分でも作れるんじゃね？と思いQRReaderを作成。
配布にCocoaPods(遺産なんて言わないで)を採用。
結果出来たが、少し躓いたのでメモ

#### 今回作ったライブラリ
今後も更新します。

https://github.com/kirasoga/QRReader

#### 下記の記事を参考にさせていただきました。

https://qiita.com/taji-taji/items/e23373f9b8124de728a2

めちゃくちゃ参考にさせていただきました。ありがとうございます。

## はじめに
上記の投稿で、自分の理解の及ばなかった箇所を備忘録として作成。
上記の記事に沿って作成します。

## 1. ライブラリの作成
ここは順調

## 2. Githubに公開
ここは順調

## 3. podspecファイルの編集
### podspecの内容チェック

`pod lib lint SampleLib.podspec`
このコマンドでpodspecの内容をバリデーションチェックしてくれる
1. `s.description`はなくても大丈夫
2. `s.summary`の初期値は'A short description of [ライブラリ名].'
`s.summary`はこの文字列ではダメなので、しっかりと説明を書く必要がある。
3. `s.swift_version`を指定する必要がある。
以下は5.0の例
`s.swift_version = '5.0'`

4. Cocoapodsが悪いのか、`s.ios.deployment_target`がちょっと低い。
自分で考えて手動で変えてあげる必要がある。(変えなくてもOK)

## 4. README.mdの編集
ここは順調

## 5. 自作ライブラリファイルの配置
ここは順調

## 6. 動作確認
CocoaPodsで自動で作られたものが色々ずれる。
`AppDelegate.swift`については補完が出るので修正
その他、自作ライブラリのバージョンが9.3(俺調べ)だったので、考えてあげる
(あげる必要がない時は、動作確認用のバージョンを13.0から9.3まで下げる必要がある。)

## 7. CocoaPodsにアカウント登録
ここは順調

## 8. git tag でバージョン付け
ここは順調

## 9. 最終確認
この時点で、gitにtagをつけていないとダメ。
バリデーションチェックする前にpush。。。？って思ってあげなかったらしくった。
gitにpushとtag付けが完了したら`9`を実施。

## 10. CocoaPodsへ公開

`pod trunk push [ライブラリ名].podspec`

## 11. 運用
`8~10`は、ライブラリ更新の度に行う必要がある。
#### 注意点
・tagは値を変えること。
・`s.version`はtagと同じ値にすること

## 最後に
この記事めちゃくちゃ細かく書かれてたので、すごくわかりやすかったです。
ありがとうございました。

https://qiita.com/taji-taji/items/e23373f9b8124de728a2

## 最後に
iOSアプリ開発をしています。
主にSwiftですが、最近は熱が入ってきてFlutterも🦾
色々やってます。もし良かったら見てってください。

https://sogablog.net/
エニーキャスト とは

## 勉強前イメージ

ユニキャストとは？

## 調査

### エニーキャスト とは

1つのIPアドレスを複数のサーバで共有する仕組みで、通信はIPアドレスを持ってる複数のサーバのうち
ネットワーク的に一番近いサーバと通信を行います。
また、複数のサーバで共有するIPアドレスのことをエニーキャストアドレスを言います。

エニーキャストを使うことで以下のような効果があります。

- 冗長化や負荷分散ができる

複数の拠点・ホストに同じIPアドレスを振ることで、冗長化や負荷分散ができます。

- 応答時間の短縮

複数の拠点で同じIPアドレスを設定しておくと、
近いホストが応答を行うので、応答時間の短縮をすることができます。

- DoS攻撃・DDoS攻撃の局所化・抑制

DoS攻撃は1箇所であれば一番近いホストへアクセスがされるので他のサーバへの被害はありません。
また、DDoS攻撃は複数のホストに分割されるので負荷が分散され効果を抑制できます。

エニーキャストはDNSのルートサーバで使用されていて
世界で13台あるサーバで一番近いルートサーバでアクセスがされるようになっています。

## 勉強後イメージ

xxキャストアドレスとかよく聞くけどそれの仲間だね。
確かに近いほうが応答も早いし・・・・

## 参考

- [IP Anycast（アイピーエニーキャスト）](https://jprs.jp/glossary/index.php?ID=0108)
- [エニーキャスト 【anycasting】](https://e-words.jp/w/%E3%82%A8%E3%83%8B%E3%83%BC%E3%82%AD%E3%83%A3%E3%82%B9%E3%83%88.html)
Vitest に関するTIPs/トラブルシューティング (WIP)

## 概要

Vitest に関するTIPs/トラブルシューティングをまとめる。

## TIPs

### 完全なスタックトレースを出させる

node_modules 内のスタックトレースを出してくれず、デバッグが難しい時がある。
2022.8.18 現在、 printError の options を直接いじるしか無さそう。

```js
// node_modules/vitest/dist/chunk-vite-node-externalize.*.mjs
async function printError(error, ctx, options = {}) {
  options = {...options, showCodeFrame: true, fullStack: true};  // <==== 追加
  const { showCodeFrame = true, fullStack = false, type } = options;
```

関連： [feat: error log improvements by sheremet-va · Pull Request #1202 · vitest-dev/vitest](https://github.com/vitest-dev/vitest/pull/1202)
クリックジャッキングを理解しきれていない気がするのでもう少し中身を理解したい

# 現時点での自分のクリックジャッキングに関する認識
「なんか上にiframeとかで罠サイト被せて、利用者にクリックさせて勝手なことさせるやつでしょ？」(分かってる)
「iframe使わせんかったらいいじゃん？どうやるかあんまり分かってないけど」(分かってない)
「使いたい場合は…んー…」(全く分かってない)

# 実際問題、クリックジャッキング攻撃されるサイトってどんなの？
**クリックだけでなんか大事な処理ができるサイト**だったらなんでもやばいと。
ということは、
- マウスみたいなの(ポインティングデバイス)だけで大事な操作ができないようにする
- 外からiframeが入らないようにする

これで防げる、気はするのはなんとなくわかった。

# 具体的な対策方法
これの対策としてframeおよびiframeでの参照を制限する**X-Frame-Options**というものがあるそうで。
このX-Frame-Optionsというレスポンスヘッダは
- **DENY**(とにかく全部拒否)か
- **SAMEORIGIN**(同一生成元ならOK、Qiitaならqiita.comのiframeだけ読める)か

の２択らしい。
指定していない場合普通にiframeなんでも読み込んじゃうよう？(未調査)ですのでやばいですね

あとは
- 重要な操作の前にパスワード入力を要求する

とかも対策にはなりそうな。一般的なブラウザなら概ねX-Frame-Optionsは対応してるようなので、よっぽどマイナーなブラウザ使ってなきゃここまでしなくてもいいのかもしれない。ここまでするかどうかは、多分そのページで行う処理の重要度によるんだろうか

# 設定の仕方

サーバー側でもページ側でも設定できるらしいが、設定の仕方によっては二重出力されたり二段出力されたりするようで。
その結果DENYで設定したはずなのに特定のブラウザからだとSAMEORIGINになってたりとかするようです。

ページ側でやると抜け漏れ発生しそうなのでサーバー側で設定するのが安全なのかな。
別に全ページ出力しても問題ないようですし。
ただ同じサイトの中でiframeを使ったり使わなかったりする場合は個別設定したほうがいいと。
あとApacheだとmod_headersが導入されてないと設定ができないようなので、そうなったら必要なページ、あるいは全ページに入れておく感じになる感じかな。

# その他事項
あれ、HTTPヘッダってめっちゃ大事じゃね？？？(今更)
近いうちに調べて自分なりにかみ砕きたい

[徳丸本]((https://wasbook.org/))と各種Webサイトを見て回りながら自分なりの解釈を垂れ流してみましたが、いかんせんセキュリティに関して多分知見が足りなさすぎるので…
突っ込みどころとかがありましたらコメント等でご指導頂けますと幸いです。
【Firebase】デフォルト以外のサイトにアプリをdeployする方法

Firebase Hosting は複数のサイトを作成、登録できます。
Hostingタブの`別のサイトを追加`からサイト名を入力して作成できます。

![second.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697067/3ee8be29-f86c-8a56-b18e-2412580b6139.png)

新しく作成した`second-my-site`に対して、プロジェクトをdeployする方法を記載します。

ちなみに、デフォルトで作成されているサイトは削除することができず、問題が発生した場合などに、プロジェクト自体を作り直す必要があります。
新しく追加したサイトは削除が可能となっています。

### .firebaserc, firebase.json の編集

`.firebaserc` の`targets`に作成した`second-my-site`を設定します。

```json:.firebaserc
{
  "projects": {
    "default": "PROJECT_NAME"
  },
  "targets": {
    "PROJECT_NAME": {
      "hosting": {
        "content": ["second-my-site"]
      }
    }
  },
  ...
}
```

先程指定した`second-my-site`にdeployする設定を`firebase.json`に記述します。

```json:firebase.json
"hosting": {
    "target": "content",
    "public": "build",
     ...
```

### デプロイする
あとはdeployコマンドを実行すれば、`second-my-site`にデプロイされます。
```
firebase deploy
```
Slack の絵文字をいい感じに作成できるツールを見つけた話

# はじめに

チャットツールの [Slack][slack] に自分の思い通りで見やすい絵文字を追加したい。そんな欲望にかられ、手軽にアイコンを作成できるツールを探しました。

見つけました。

[Figma][figma] です。

# Figma とは

[Figma][figma] とは Web UI デザインツールで、Webブラウザのみで動かすことができます。無料版もあるので手軽に利用できます。

# どうしてアイコンを作成できるのか?

[Figma][figma] では自由なデザインでボタン等のパーツを作成することができます。さらに、作成したパーツを画像ファイルとしてダウンロードできます。

ってことは自由にアイコンを作成できますね！

# やってみた

まずは 50×50 ぐらいの Frame を作成して...
![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/2c10b009-c048-cab0-d7a1-19e5a5fcc1bc.jpeg)

こんなかんじで...
![002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/efff4fae-d348-0215-0807-1ccac7c68c0d.jpeg)
![003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/708a9929-b7dc-2e0c-49db-a54d54a7c06f.jpeg)
![004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/5764b6f4-4d41-8086-de4e-1e58cbe3ef07.jpeg)
![005.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/c388fe74-d33a-cbdf-18d0-6af88254eba6.jpeg)
椅子ができました！

そして...
![006.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/45bd7127-5daa-0e07-f7f8-e99da2e90f44.jpeg)
![007.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/97fbe624-5393-893f-1c40-e959e1678bc0.jpeg)

よいしょ💨 よいしょ💨

![008.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/56e0b5f1-f16e-0978-c088-766cc80cb4a1.jpeg)
![009.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/944e299d-f0cb-d1f0-7412-5e7cf5a7b3d1.jpeg)
![010.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/cac1d7a4-1b5d-c544-dc13-9ac5adaa75c5.jpeg)
着席中アイコンの出来上がりです！

最初に作成した Frame を選択して、右メニューの「Export Frame 1」ボタンをクリックすると画像ファイルをダウンロードできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/c35f600b-b4f4-7c7e-a0a1-0a60ffff1d27.png)

あとは [Slack][slack] に登録するだけですね！

# まとめ

[Figma][figma] の使い方としては邪道かもしれませんね。ごめんなさいです🙇‍♂️。

[Slack][slack] の絵文字は仕事中のちょっとした気分転換にもなるので、このように目的に沿ったアイコンを手軽に作成できると便利かなぁと思います😀。


[slack]: https://slack.com/
[figma]: https://www.figma.com/
Amazon EC2のストレージボリューム（EBS）

# EBSとは
**Amazon Elastic Block Store**(Amazon EBS)
永続的なブロックストレージボリューム。EC2インスタンスと組み合わせて使う。
ストレージ:データを保存する先。SSDやHDDがある。
**ブロックストレージボリューム**とは、データをバイトのブロック単位で保存する方式で、ディスクに保存するときの最も一般的な方式。
一方で、同じAWSサービスであるAmazon S3は**オブジェクトストレージ**と呼ばれる方式を採用。
EBSではHDDとSSDを選択できる。
**HDDとSSDの違い**
|項目|HDD(ハードディスクドライブ)|SSD(ソリッドステートドライブ)|
|-|-|-|
|読み書き速度|普通|**速い**|
|値段|普通|**高い**|
|消費電力|**やや大きい**|普通|
|衝撃に対して|弱い|**強い**|
|故障|冗長化されている|冗長化されている|
# EBSのボリュームタイプ
HDD、SSD共にIOPS保障やスループット最適化などのボリュームタイプがあり、パフォーマンスとの料金バランスを見て選択
# EBSの機能と料金
**EBSの機能**
|機能|内容|
|-|-|
|エラスティックボリューム|ボリュームの大きさを簡単に調整できる|
|スナップショット|その時点でのデータを丸ごと保存する|
|データライフサイクルマネージャー|スケジュールに従ってスナップショットを作成・削除する機能|
|最適化インスタンス|特定のインスタンスタイプを最適化インスタンスとして、読み書きを高速化する機能|
|暗号化|データボリューム、ブートボリューム、及びスナップショットを暗号化する機能。KMS（AWS Key Management Service）が使用できる|

料金は**単価** × **確保時間** 
使っていようがいまいが、確保した容量でお金がかかる。
サーバーが停止していても料金がかかる。単価はディスクによって変わる。
M1 Mac のDocker Desktopが重いのを改善してみる　

# Docker Desktop でのエラー
以下のエラーで起動できない時がある。。動作も遅い。。
```
Error number 28 means 'No space left on device'
```
dfコマンド確認しても別に以上はなさそう。
### 環境　
|  |  |
|:-:|:-:|
|OS|MacBook Air (M1, 2020)|
|チップ|M1|
|メモリ|16G|
|Docker Desktop|4.11.1|

# やったこと
### メモリを増やす

Docker Desktopを開いて　Preferences > ResourcesのMemory
初期値の２GB→８GBにあげる
「Apply & Restart」をクリックし、メモリ使用量を適用させる

これで軽くなる人もいるらしいが変わらず・・

### disk imageのお掃除
Docker Desktopを開いて　Preferences > ResourcesのDisk image sizeを確認
```
Disk image size:5６ GB (54.4 GB used)
```
増えていたのでリセットするため使っていないイメージをクリーンアップ
下記コマンドで未使用のコンテナー・ネットワーク・イメージをすべて削除（ボリュームは削除されません）
```
$ docker system prune
```
ほんとにコンティニューしますか？って聞かれたくない場合は末尾に-fをつける
ボリュームも削除する場合は末尾に--volumesをつける

すると
![1660809390.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685449/de0122c3-cffb-96ac-2b98-18a425e4e814.png)

## virtiofsを設定する

Virtiofs は、仮想マシンがホスト上のディレクトリ ツリーにアクセスできるようにする共有ファイルシステムです
Preferences > Experimental Features
以下にチェックを入れます。
「Use the new Virtualization framework」
「Enable VirtioFS accelerated directory sharing」

:::note info
macOSのバージョンが12.2以上で使えるのでチェックがクリックできない場合はバージョンを確認してください
:::

[virtiofs公式サイト](https://virtio-fs.gitlab.io/)

これでだいぶ軽くなり、エラーもでなくなりました

参考サイト
[Docker for Mac が遅い(怒)](https://www.y-hakopro.com/entry/2021/07/11/175236)
[使用していない Docker オブジェクトの削除（prune）](https://docs.docker.jp/config/pruning.html)
[メモリ使用量を引き上げたらDockerの動作がサクサクになった話](
https://techtechmedia.com/docker-trouble-solution/#:~:text=%E5%8D%81%E5%88%86%E3%81%9D%E3%81%86%E3%81%A7%E3%81%99%E3%80%82-,%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%92%E5%A2%97%E3%82%84%E3%81%99%E6%96%B9%E6%B3%95,%E5%BC%95%E3%81%8D%E4%B8%8A%E3%81%92%E3%82%8B%E3%81%A0%E3%81%91%E3%81%A7%E5%8F%AF%E8%83%BD%E3%81%A7%E3%81%99%E3%80%82)
[Docker for Macの新しいファイルシステムVirtioFSを試してみた](
https://zenn.dev/takc923/articles/1eb61e531e3704)
GakuNin RDMデータ解析機能の使い方

# はじめに

GakuNin RDMデータ解析機能とは、PythonやRの実行環境を比較的簡単に作り、それをブラウザ上で使うことができるサービスです。JDCat分析ツールという別名もあります。Google Colabと似ている部分もありますが、違いも沢山あります。

GakuNin RDMおよびGakuNin RDMデータ解析機能については公式の[ユーザーマニュアル](https://support.rdm.nii.ac.jp/usermanual/)に詳しく書いてありますので、興味のある方は、まずはそちらを参照して下さい。

ここでは自分が使ってみて分かりづらかった点などを中心にまとめます。

# GakuNin RDMとの関係

GakuNin、GakuNin RDM, GakuNin RDMデータ解析機能はそれぞれ別物です。以下の表にまとめます。

| 名前 | 内容 |
|----------------|------------|
| GakuNin (学認) | 認証サービス | 
| GakuNin RDM    | データ管理基盤 |
| GakuNin RDMデータ解析機能 | 計算環境 |

GakuNin RDMはGakuNinで認証すると使えるデータ管理基盤です。DropboxやGoogle Driveのようなファイル置き場として私は使っています。[ムーンショット型研究開発事業](https://www.jst.go.jp/moonshot/)がきっかけで使い始めましたが、まだ利用者が少ないようです。

GakuNin RDMデータ解析環境は**GakuNin RDMとは別物**です。連携しているだけです。公式ページをちゃんと読めば書いてあることですが、分かりづらかったので改めてまとめます。そもそもGakuNin RDMデータ解析機能の英語名称はGakuNin Federated Computing Services at NIIであり、RDMが入っていません。

GakuNin RDM (以下、RDM) では、プロジェクトという単位でデータを管理します。RDMのプロジェクトからGakuNin RDMデータ解析環境 (以下、CS) の解析環境を新規作成すると、**その時点でプロジェクト内にあったファイルのコピー**が解析環境に作られます。以後、CS側でファイルを変更してもRDM側には影響がありません。

このため、RDMに置いたデータをCS側の操作ミスで消してしまったり上書きしてしまったりすることはありません。逆に、途中で解析対象のデータをCSに追加したい場合は、手動でアップする必要があるようです。

CS側の計算結果などをRDMに保存したい場合は、もちろん一旦ダウンロードしてからRDMにアップすれば良いのですが、CS側のホーム直下に**resultという名前のフォルダ**を作成し、その中に結果ファイルを入れておくと、ボタン一つでRDMに書き込まれます。この部分はユーザーマニュアルに詳しく書いてあるのでそちらを参照して下さい。

注意が必要なのは**ソースコード** (ipynbファイル) です。CSのデータは**30日間使っていないと消されます**。出力ファイルをRDMに保存しておくだけでなく、ソースコードも定期的にバックアップしておく必要がありそうです。

# 解析環境の作成

1. GakuNin RDMのプロジェクトを開く
1. アドオン > GakuNin Federated Computing Services > 有効にする
1. 上メニューに「解析」が登場するので選択
1. 基本イメージを以下の2つから選択
    1. Python + R
    1. Data Science Notebook (**こちらを推奨**)
1. 新しい解析環境を作成
1. 終わるまで待つ (下の黒い部分にログが流れている、server running at...で終わり)

基本イメージでPython+Rを選んでしまうと、numpyもpandasも一切入っていないpython環境になります。もちろん、追加パッケージの指定で一通り指定しても構いませんが、インストールに結構な時間がかかります。予め用意されているイメージを利用するのが良いと思います。

足りないパッケージは後からも追加できます。ノートブック内で`!pip install <package_name>`のような感じのコードを実行すればOKです。

# 起動

アイコンは3つ並んでいます。Pythonの場合、**左と中央のどちらを選んでも構いません**。UIが違うだけで、編集内容なども共有されています。また、解析環境名の右のURLは、左のアイコンと同じ動作です。

| 位置 | アイコンの文字 | 意味 |
|------|------|-----|
| 左 | Jupyter | Jupyrer Hub & Jupyter Notebook (旧UI) |
| 中央 | lab | Jupyter Lab (新UI) |
| 右 | R | R Studio |

私は普段CUIで作業しているので、Jupyter Notebook, Jupyter Hub, Jupyter Labのことをあまりよく分かっていません。どうやら、CSの中で1つ目と2つ目を切り替えるには、URLの/treeを/labに手動で書き換えるしかないようです。もちろんRDMから開き直すという手もあります。

もしプログラミングの授業などでの利用する場合は、混乱を避けるため、どちらか一方のUIのみ使うよう受講者に指示しておいた方が良さそうです。

あとは、ipynbファイルがあれば開き、なければ新規作成で、計算環境を使えます。

# 個人的な感想

使っていないと30日で消えること、変更履歴を管理しづらいことを考えると、プログラミング中級以上の人の開発環境には向いていないかもしれません。一方、プログラミング未経験者や初心者にとっては便利そうです。とはいえ、今はまだGoogle Colabの方が情報も豊富で敷居も低い気がします。今後利用者が増えれば状況が変わるのではないかと思います。
Red Hat OpenShift Developer Sandboxの取得

# はじめに
お客様とお話させていただく際、「OpenShiftを簡単に試せる環境はありますか？」というご質問をよくいただきます。
そこで今回はOpenShiftを簡単に試すことができる「Red Hat OpenShift Developer Sandbox」の取得方法についてご紹介させていただきます。
カスタマーポータルのアカウントが必要になりますので、未取得の方は[こちら](https://qiita.com/ynagashi/items/d22e3bca1519d13fcd21 "こちら")の記事を参考に、まずはアカウントを作成してください。

OpenShift Developer Sandboxは機能が一部制限されており、OpenShiftのすべての機能を使えるわけではありません。
また、OpenShift Developer Sandboxには、
・RAM: 7GB
・ストレージ: 15GB
・使用期限: 30日
といった制限もございます。



#
まずはじめに、[こちら](https://developers.redhat.com/developer-sandbox "こちら")にアクセスし、「Start your sandbox for free」をクリックします。
![00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/b12f69c3-42bc-23f1-e181-ce26ca3b7581.png)

Red Hatカスタマーポータルアカウントでログインします。
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/1ed94e72-8220-a66a-5791-47e13b5db89a.png)

Red Hatカスタマーポータルアカウントに電話番号が登録されていない場合、電話番号の登録が必要となりますので、電話番号を入力し、「Send Conde」をクリックします。
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/9f048e34-890f-540a-4e67-fb2639dc61b2.png)

すると、先程入力した電話番号にショートメッセージでVerification Codeが届きますので、そちらを入力し、「Verify Code」をクリックします。
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/fa252306-4cec-e09a-c4ff-ad4ea8e77bae.png)

「Start using your sandbox」をクリックします。
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/cc524a17-757b-c816-9ea1-a3b62300e207.png)

「DevSandbox」をクリックします。
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/2364b971-2d89-bffb-1dee-c01be40f25a6.png)

契約条件に同意する場合は、同意するにチェックを入れ、「送信」をクリックします。
![07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/1942af56-3292-649f-1183-45ddb47a557b.png)

これでOpenShift Developer Sandbox環境を取得できました！
![08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/97dfcd6a-bae3-48fd-4154-822df5d095c7.png)

以上となります。
AWS Lambda + API Gatewayでエラーになったら確認すること

Lambda + APIGatewayでREST APIを構築し、いろんなエラーに遭遇しました。
確認すべき箇所をメモしておきます。


## 403 {"message":"Forbidden"}

### → <font color="PaleVioletRed">**リクエストURLは正しいでしょうか**</font>
API Gatewayはpath+ステージ名を付けたりします。
このステージ名が抜けてるとForbiddenになりますので、確認してみてください。

構成
```
https://{APIのID}.execute-api.{リージョン}.amazonaws.com/{ステージ名}/{リソース名}
```

例
```
https://api-id.execute-api.us-east-2.amazonaws.com/default/pets?id=4&type=dog
```
### → <font color="PaleVioletRed">**リソースポリシーが間違っていないでしょうか**</font>
リソースポリシーが真っ白だとエラーになります。
左メニューの「リソースポリシー」を確認してみてください。

例えば全部許可するなら以下のように書きます。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:ap-northeast-1:000000000000:api-id/*"
        }
    ]
}
```
`"Resource"`にはarnを入れてくださいね。
設定後は<font color="Crimson">必ずAPIをデプロイ</font>しましょう。


## 502 Bad Gateway

### → <font color="PaleVioletRed">**API Gatewayに問題はないかもしれません...**</font>
APIGatewayをトリガーにしてLambdaが動き、Lambdaでエラーが発生した場合、502エラーが返ってきます。
なので、APIGatewayに問題はないかもしれません。
Lambda側のCloud Watchログなどを確認して、Lambdaの問題なのかAPIGateWayの問題なのかを切り分けてみてください。

### → <font color="PaleVioletRed">**エンドポイントがプライベート設定なのでしょうか**</font>
左メニュー「設定」 > エンドポイントの設定　を「プライベート」にしているとVPCの設定が求められます。
「プライベート」にするなら正しいVPCが設定されているかを確認してみてくださいね。
「リージョン」ならVPCの設定は必要ありません。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284077/de8a9f16-cbc1-cdcd-a5db-96f15d3679e4.png)


### → <font color="PaleVioletRed">**API keyが有効になってますでしょうか**</font>

左メニュー「リソース」 > 対象リソース名のメソッド > 「メソッドリクエスト」　をクリックして、APIキーの必要性が「false」になっていることを確認してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284077/8f8f5200-2f4f-b253-3305-18b87d6c7071.png)

もしAPI Keyを設定するなら、
左メニューの「APIキー」からAPIを作って、ヘッダーに`x-api-key`の項目名で設定しましょう。
また、左メニューの「設定」で「API キーのソース」が「ヘッダー」になっていることも確認してください。
設定後は<font color="Crimson">必ずAPIをデプロイ</font>しましょう。



## そのほか
### → <font color="PaleVioletRed">**リソースのデプロイをお忘れではないでしょうか...**</font>
これまでの内容でも赤文字で記載していますが、リソースやリソースポリシーをいじったら必ずデプロイしましょう。
私はこれをやってなくて1時間溶かしました😆


## 参考
参考にさせていただきました。

- [AWS API Gateway デベロッパーガイド　HTTP API のルートの使用](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/http-api-develop-routes.html)
- [API Gatewayとlambdaを使ってみる](https://qiita.com/miyuki_samitani/items/f01f1bd49334f97fe84c)
- [Amazon API Gateway でのプライベート API の作成](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-private-apis.html)

以上
.Net6ではstringもNull許容にしないとPostでバリデーションエラーになる

# .net core3.1の頃のプログラムを.net6に移行したら…

**APIで何故か400エラーが…！**

クライアント（react）からaxiosでサーバー側（.net6）にPOSTリクエストするだけのなんてことない普通のAPIです。

## API Testerで叩いてみる

返ってきたレスポンスを見てみます。

```json
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-xxxxxxxxxxxxxxxxxxxx-xxxxxxxxx-00",
  "errors":{
    "Text":[
      "The Text field is required."
    ],
  }
}
```


**validation errors**　ばりでーしょんえらー？？
なぜ？？:disappointed_relieved:

**The Text field is required.**
必須入力にした覚えなんかないけども…

## そういえば.net6になってからこれを良く見るぞ:astonished:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149339/5735163d-2c53-671b-6ae6-1d73bfafcef9.png)

string型もnull許容型にしないとダメよん！と指摘（怒られてはいない！笑）されるので
visual studio君のいう通りに直しておりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149339/ffa7ef7c-c01a-8510-bf79-1dd47937ad97.png)

**なるほど…「Null許容しない＝必須やで」ということなのか:anguished:**

コンパイルエラーにはならないのが詰まるミソですねこれ。

## Null許容型に変えてみる

修正前

```c#
public string Text { get; set; }
```

修正後
```c#
public string? Text { get; set; }
```

## 結果

**200！OK！！** ！:point_left:

なんてことない問題だったんですが、
なんでや！！と詰まったのでメモメモ。

もし同じ現象で困ってる方がいましたら、ちょっとでも参考になれば幸いです。
thymeleaf th:eachで2次元配列表示

thymeleaf th:eachで2次元配列表示

		<div>
			<table border="1">
				<tr th:each="ppp,ix : ${ dispAry }">
    				<th:block th:each="sss,jx : ${ppp}">
     					<td th:text="${dispAry[__${ix.index}__][__${jx.index}__]}"></td>
    				</th:block>
				</tr>
			</table>
		</div>
インスタンスタイプ

# インスタンスタイプとは
**インスタンスタイプとは、マシンの用途**。
CPU、メモリ、ストレージ、ネットワークキャパシティーなどが用途によって組み合わせられる。
**用途は主に5つの種別があり、それぞれ複数のインスタンスタイプが存在する**。
**インスタンスタイプの用途とタイプ名**
* 汎用
インスタンスタイプ：A1、T3、T2、M5、M5a、M4、T3a
* コンピューティング最適化
インスタンスタイプ：C5、C5n、C4
* メモリ最適化
インスタンスタイプ：R5、R5a、R4、X1e、X1、ハイメモリ、z1d
* 高速コンピューティング
インスタンスタイプ：P3、P2、G3、F1
* ストレージ最適化
インスタンスタイプ：H1、I3、D2
# インスタンスタイプとインスタンスサイズ
インスタンスタイプを選択後、**インスタンスサイズ**を選択する。インスタンスサイズは簡単にいうと、**性能**です。
ex)T2という一時的に性能を上げるバースト機能に対応したインスタンスタイプには、「nano」「micro」「small」「medium」「large」「xlarge」「2xlarge」「4xlarge」の８種類のサイズがある。
よって、インスタンスを選択するときは、**「t2.micro」のようにタイプとサイズを選択する。
**主なインスタンスタイプ**
|用途|インスタンスタイプ|内容|
|-|-|-|
|汎用|T2,T3,M5,M4|一般的なサーバー。負荷が一定のサーバーの時に使う。バースト機能に対応しているタイプ|
|コンピューティング最適化|C5,C4|計算機能が高いサーバー|
|メモリ最適化|X1e,X1|メモリのアクセス速度を向上したサーバー|
|メモリ最適化|R4|大容量メモリを搭載したサーバー|
|高速コンピューティング|P3,P2,G3,F1|機械学習等で使えるGPUを搭載しているタイプやグラフィック機能が高いタプ|
|ストレージ最適化|H1,I3,D2|ストレージを最適化したタイプ。I3はSSDベース|
FQDN等が制限されたネットワーク環境化でPhoton Cloud が使えない

## 公式回答

https://forum.photonengine.com/discussion/19985/can-we-get-any-additional-information-on-photon-cloud-ports
FQDN や IP は自動で決まり変わることがあるので、サーバのリスト化はできない。もし固定するなら独自サーバを構築するか Enterprise Cloud を契約せよ、とのこと。

## 公式ドキュメント

https://doc.photonengine.com/ja-jp/realtime/current/connection-and-authentication/regions

LB経由ではなく、いったん Region Master Server で Game Server の情報をもらう仕組みっぽい。
たしかにそれだと接続ごとに IP 等の情報は変わるし、リスト化できない

## 何で困るか

~~社員がサボれないように~~社内ネットワークで FQDN アクセス制限していたりすると、Photon Cloud を利用したアプリが提供できない
【Flutter】アプリアイコンを変更する

##  初めに
Apple Store や Google Play Store にアプリを表示させる場合、当然のことながら、自分独自のアイコンを作成して表示させる必要があります。
今回は作成したアイコンをアプリアイコンとしてホーム画面に表示させる方法を紹介します。

## flutter_launcher_icons
今回は [flutter_launcher_icons](https://pub.dev/packages/flutter_launcher_icons) というパッケージを使用します。
このパッケージはアプリのアイコンを変更する際に使用されるパッケージです。

## 準備
まずは、パッケージのバージョンを「 pubspeck.yaml 」に記述します。
このパッケージを使用するのは開発段階であるため、`dependencies` ではなく、 `dev_dependencies` に追加します。

パッケージのバージョンは、特に制約がなければ最新のバージョンで問題ありません。
```yaml: pubspeck.yaml
dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_launcher_icons: ^0.10.0
```
Pub get をして準備は完了です。

## 実装
次にプロジェクト内に画像を保存するためのディレクトリを作成し、そこにアプリのアイコンとして使用した画像を配置しましょう。

`image_path` には画像のパスを指定します。

以下では `assets` ディレクトリに `sample_logo.png` という画像を指定しています。
なお、アプリのアイコンに使用する画像の形式は png 形式が推奨されています。

```diff_yaml: pubspeck.yaml
dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_launcher_icons: ^0.10.0

#  追加
flutter_icons:       
  android: true
  ios: true
  image_path: "assets/sample_logo.png"
```

`android: true` `ios: true`
このように記述することで、android, iOS の両方で指定したアプリのアイコンが使用できるようになります。
<br>
次にターミナルで以下のコードを実行しましょう。
```terminal: Terminal
flutter pub run flutter_launcher_icons:main
```
これで以下のように、ホーム画面に表示されているアプリのアイコンが変更されたかと思います。
<img width=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/1e572e42-7f0e-442e-77e8-4e1b28ce975b.png">

### Android と iOS で別のアイコンにする
```diff_yaml: pubspeck.yaml
flutter_icons:       
  android: true
  ios: true
  image_path_android: "assets/sample_logo.png"
  image_path_ios: "assets/other_sample_logo.png"
```
`image_path_android` `image_path_ios` で別々の画像を指定することで、Android と iOS で別のアイコンを表示させることができるようになります。

### Android のバージョンの指定
```yaml: pubspeck.yaml
min_sdk_android: 21
```
上のように指定することで Android の最低バージョンを指定することができます。
デフォルトの値は 21 に設定されています。

### アイコンの背景色を変更する
```yaml.pubspeck.yaml
adaptive_icon_background: "#ffffff"
```
上のようにすることでアプリのアイコンの背景色を指定することができます。
なお、背景色はカラーコードで指定する必要があります。

### アイコンの背景画像を変更する
```yaml.pubspeck.yaml
adaptive_icon_background: "assets/background_image.png"
```
先述した `adaptive_icon_background` では背景色以外にも、画像のパスを指定することで、アイコンの背景画像を指定することもできます。

### アイコンの前に画像を表示させる
```yaml: pubspeck.yaml
adaptive_icon_foreground: "assets/foreground_image.png"
```
アイコンの手前にも画像を表示させることができます。
なお、 `adaptive_icon_background` と `adaptive_icon_foreground` は同時に記述されている必要があり、どちらかが記述されていないと画像や背景色が反映されないので注意しましょう。

## あとがき
最後まで読んでいただきありがとうございました。

今回は Android、iOS のみの実装でしたが、Web、Windows の設定も可能です。

実際に、上で示した画像ではアイコンの線が細いと感じたため、アイコンの修正を行いました。
アプリをリリースする前の段階であってもまた、アイコンを表示させてみて、新たに気づくこともあるかと思います。

以上です。

参考にしていただければ幸いです。
誤っている箇所があればご指摘いただければ幸いです。

### 参考にしたサイト
https://pub.dev/packages/flutter_launcher_icons
Salesforceのケースビューを表示や非表示をする方法

こんにちは。本橋孝昭です

今回はケースレコードにある
・すべての更新
・状況変更
・テキスト投稿
・活動ログ

をページから非表示したり並び替えをする方法をお伝えします

場所としてはこちらです
![ケースフィードの方法.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/12fabbbf-58b5-4ad1-2442-8e3fb9b9453b.png)


## 前提
ケースのページレイアウトで
「フィードベースのレイアウト」にチェックがされているページレイアウトが割り当てられている場合、表示されます


![フィード01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/42ab669f-a20d-2365-16dd-28706862b3f6.png)

もしも「フィードベースのレイアウト」にチェックがされているページレイアウトが割り当てられていない場合は表示されません
![前提01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/68db90f2-f673-6e33-45e8-f70910a77535.png)


なお、ページレイアウトを作成してから「フィードベースのレイアウト」にチェックをする設定はできないのでご注意ください。

## 設定方法
さて、「フィードベースのレイアウト」にチェックがされているページレイアウトのみ右上に
・フィードビュー
があるのでクリックします
![フィードビュー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/f75073d6-c326-58b4-406f-7e2d4543f0ae.png)

こちらの「フィード条件オプション」から選択したいものを選択したり非表示することが可能です

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/f8649521-4406-5349-c7c6-b6ab2754b5fb.png)
Pythonメモ

# 初めに
Pythonメモ（自分用）
動作環境：WindowsOS

- [Python準備](#python準備)
- [スクリプト作成](#スクリプト作成)
- [開発環境(IDLE)用意](#開発環境idle用意)
- 対話モード
- [演算](#演算)
- [変数](#変数)
- [](#)
- [](#)
- [](#)
- [](#)

【勉強用サイト】

https://www.javadrive.jp/python/

https://www.python.jp/train/index.html

## Python準備
1. ダウンロード

https://www.python.org

2. インストール
Add Python x.x.x to PATH　にチェックを入れること
3. インストール確認
コマンドプロンプトで以下を実行
```:問題なし
>python -V
Python x.x.x
```
※Pythonとしか表示されない場合うまくいってない
```:問題あり
>python -V
Python
```
解決策

https://www.out48.com/archives/5720/

⇒OS再起動は不要

■補足
- Python実行環境
・ローカル（自分のPCなど本体にインストールする。今回はこっちを実施）
・クラウド（ブラウザでプログラミングできる環境を提供しているサービスがある。無料のものもあり）

https://colab.research.google.com/

- Pythonディストリビューション使い分け
公式以外からも、Pythonが配布されている。それぞれ特色がある。

https://atmarkit.itmedia.co.jp/ait/articles/2203/23/news027.html

## スクリプト作成
１. テキストファイルにコードを書いて、拡張子を「.py」にする
例：sample.py
```python:ファイルに以下の内容を記述
print('Hello, World!')
```
２. コマンドプロンプトから.pyファイルを実行
```
>cd C:\hogehoge　　※ファイル配置場所に移動
>cd/d D:\hogehoge　※異なるドライブへ移動する場合
>python sample.py　※実行コマンド。引数にファイル名を指定する
Hello, World!　　　※実行結果
```

## 開発環境(IDLE)用意
1. スタートボタン→アプリ一覧のPythonフォルダの中にIDLEがいるので起動
2. IDLE操作
IDLEが起動すると、文字が羅列している状態で表示される。かまわず「>>>」が表示されている行にコードを書きEnterを押すと、次の行に実行結果が表示される。
```:こんなんが記載されているので、コードを実行してみる
　 Python 3.10.6 (tags/v3.10.6:9c7b4bd, Aug  1 2022, 21:53:49) [MSC v.1932 64 　　bit (AMD64)] on win32
　 Type "help", "copyright", "credits" or "license()" for more information.
>>>print('Hello, World!')　←実行するコード
　 Hello, World!　　　　　　←実行結果
```

■補足
開発環境は色々便利なのがあるが、簡易のIDLEがPythonに搭載されているのですぐ使える。
最初に起動したのは1文づつ実行する場合に便利。複数行まとめて実行したいときはnew fileからrun。

## 演算
| 演算         | 式     | 整数どうしの計算結果 | 例            |
|:------------:|:------:|:-----------------:|:---------------:|
| 足し算       | a + b  | 整数              | 1 + 2 　>>> 3   |
| 引き算       | a - b  | 整数              | 1 - 2 　>>> -1  |
| 掛け算       | a * b  | 整数              | 1 * 2 　>>> 2   |
| 割り算       | a / b  | float型*          | 2 / 2 　>>> 1.0 |
| 整数除算     | a // b | 整数              | 3 // 2　>>> 1   |
| 余りを求める | a % b  | 整数              | 5 % 3 　>>> 2   |
| べき乗       | a ** b | 整数              | 1 + 1 　>>> 2   |

*Pythonでは小数点などの実数をfloat型と呼ぶ
※float型どうしの計算はfloat型になる

## 変数
変数名 = 値

## 関数、モジュール
- 関数
特定の処理のこと。
- モジュール
関数を機能毎に分類したもの。～型という。
- 組み込み関数
モジュールをインポート出ずに使える関数。
```
>>> import モジュール名   　※モジュールを呼び出し
>>> モジュール名.関数名() 　※呼び出したモジュールの関数を指定
```
https://docs.python.org/ja/3/library/functions.html

https://docs.python.org/ja/3/py-modindex.html

## メソッド
文字列などのデータには、そのデータを操作するための、専用の 関数 が結びついています。
```
変数を指定
変数名.メソッド名(引数)
```
steps functionでtraining jobを実行する


# 背景
* AWS Step FunctionsでAWS APIを利用してAWS Serviceを操作できる
* APIのパラメーターは、SDKと違いある

# SageMaker CreateTrainingJob
![スクリーンショット 2022-08-18 16.33.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13451/47a4bdef-fe95-3cdf-5a30-e2b0a719a080.png)


# APIパラメーター

```
{
  "AlgorithmSpecification": {
    "TrainingImage": "{AWS::AccountId}.dkr.ecr.ap-northeast-1.amazonaws.com/{repository_name}:latest",
    "TrainingInputMode": "File"
  },
  "InputDataConfig": [
    {
      "ChannelName": "train",
      "ContentType": "text/csv",
      "DataSource": {
        "S3DataSource": {
          "S3DataDistributionType": "FullyReplicated",
          "S3DataType": "S3Prefix",
          "S3Uri.$": "s3://{bucket_name}/path/"
        }
      }
    }
  ],
  "OutputDataConfig": {
    "S3OutputPath.$": "s3://{bucket_name}/path/"
  },
  "ResourceConfig": {
    "InstanceCount": 1,
    "InstanceType": "ml.m5.4xlarge",
    "VolumeSizeInGB": 5
  },
  "StoppingCondition": {
    "MaxRuntimeInSeconds": 3000
  },
  "RoleArn": "${TrainingRole}",
  "TrainingJobName.$": "xxxxxx",
  "VpcConfig": {
    "SecurityGroupIds.$": "$.security_group",
    "Subnets.$": "$.subnets"
  }
}
```

# 注意点

```
  "InputDataConfig": [
    {
      "ChannelName": "train",
```

* チャンネルネームが上記のように、「train」を決めると、SM_CHANNEL_TRAININGのパスは'/opt/ml/input/data/train'になる
* 参照：https://github.com/aws/sagemaker-containers#list-of-provided-environment-variables-by-sagemaker-containers
curlコマンドの代わりにPowerShellを使う

お客様のWindowsにて特定サービスのAPI操作が必要になりました。
いつもならPostmanを入れれば楽なのですが、今回はそういう訳にもいかないためPowerShellで行いました。その際のメモになります。

BOXのAPIで検証します。
フォルダ情報を取得
GET
https://api.box.com/2.0/folders/:folder_id

`curl -i -X GET "https://api.box.com/2.0/folders/0" \
     -H "Authorization: Bearer <ACCESS_TOKEN>"`

https://ja.developer.box.com/reference/get-folders-id/

検証用のトークンを発行します。
![123.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752288/90548288-ecc0-4acc-330a-d79619b1766b.png)


先程のcurlをPowerShellで置き換えると下記になります。

`$token =　“<ACCESS_TOKEN>"`

`$headers = @{"Authorization" = "Bearer " + $token}`

`$url="https://api.box.com/2.0/folders/0"`

`Invoke-RestMethod -Uri $url -Method Get -Headers $headers -ContentType "application/json" | ConvertTo-Json`

Jsonの結果を取得していることを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752288/362e2b60-90eb-855b-8bc5-25b70ae19490.png)

BodyにJsonを入れたコマンドサンプルは以下になります。

`$body = '{"aaa": "bbb"}'`

`Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body -ContentType "application/json" | ConvertTo-Json`

以下エラーが発生することがあります。

***Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send.***

デフォルトでTLS1.0で設定されていますが、WebにはTLS1.2が要求されるためエラー発生します。解消するにはTLS1.2のプロトコルを有効化してから、コマンドを実行します。

`[Net.ServicePointManager]::SecurityProtocol = "Tls, Tls11, Tls12, Ssl3"`


以上となります。
見て頂きありがとうございました。
TypeScriptのエラーハンドリングはResult型を使うのが良さそうだと思った話

## はじめに

TypeScriptのエラーハンドリングの方法について、なにか良い方法はないかと探していたら、以下記事を見つけた。

https://qiita.com/frozenbonito/items/e708dfb3ab7c1fd3824d

この記事に書かれている方法を取り入れてコードを書いてみたら、個人的にとてもスッキリしたので、布教したい。😭

## Result型を使うと例外スローの苦しみから開放される

この方法の何が良いのかを説明すると、（といっても、上記記事に書いてある通りなのだが）標準的な「例外をスローさせる」方法だと以下に苦しみを感じていた。

 - 型安全でない（型から例外がスローされるかわからない）
 - 扱いづらい（スローされた例外は、catchして扱わなくてはならない）
 - テストが辛い（Jestで言えば、 `toThrow()` , `toThrowError()` 等を使って評価しなくてはならない）

これらの苦しみは、Result型を使って「エラーオブジェクトを返す」と全てクリアになる。

## Result型の使い方

まずはResult型を作る。

```ts
type Result<T, E extends Error> = Success<T> | Failure<E>;

class Success<T> {
  readonly value: T;

  constructor(value: T) {
    this.value = value;
  }
  isSuccess(): this is Success<T> {
    return true;
  }
  isFailure(): this is Failure<Error> {
    return false;
  }
}

class Failure<E extends Error> {
  readonly error: E;

  constructor(error: E) {
    this.error = error;
  }
  isSuccess(): this is Success<unknown> {
    return false;
  }
  isFailure(): this is Failure<E> {
    return true;
  }
}
```

次にエラーレスポンスを返す形式も決めておく。

たとえば、エラーが発生した時に必要な情報をオブジェクトに集約させておくと便利。

Errorオブジェクトに対して以下を追加しておくと、フロントとのエラーの連携や追跡に役立つ。

 - functionName ⇒ エラーが発生した関数名
 - statusCode ⇒ HTTPのステータスコード
 - code ⇒ 開発者側で認識するエラーコード

```ts
class ErrorResponse extends Error {
  readonly name: string
  readonly message: string
  readonly stack?: string

  constructor(
     readonly functionName: string = 'unknown functionName',
     readonly statusCode: number = 500,
     readonly code: string= 'APP_UNKNOWN_ERROR', 
     readonly error: Error = new Error('unknown error')) {
       super()
       this.name = error.name
       this.message = error.message
       this.stack = error.stack
     }
}
```

自身で作成した関数であれば、以下のように `new Failure()` を返り値に設定すれば良い。

```ts
function foo(m: string): Result<string, ErrorResponse> {
  if (m === 'm') {
    return new Success('success')
  } else {
    return new Failure(new ErrorResponse(foo.name, 500, 'APP_FOO_FUNCTION_ERROR'))
  }
}
```

なにかしらサードパーティ製ライブラリをつかった実装で `new Failure()` を返り値に設定したい場合は、 `try-catch` を使って `new Failure()` を返り値に設定する。

```ts
function bar(m: string): Result<string, ErrorResponse> {
  try {
	// なにかしらサードパーティ製ライブラリをつかった実装
  } catch(err) {
    if (err instanceof Error) {
      return new Failure(new ErrorResponse(bar.name, 500, 'APP_ERROR', err))
    }
    return new Failure(new ErrorResponse(bar.name))
  }
}
```

こうしてエラー発生時にオブジェクトを返すことで、テストにおいてもエラー用のマッチャー（`toThrow()` , `toThrowError()`）を使用しなくてよくなり、 `toBe()` や `toEqual` を使用して評価することができる。

```ts
const result = foo('a')

expect(result.isFailure() ? result.error.statusCode : undefined).toBe(500)
expect(result.isFailure() ? result.error.code : undefined).toBe('APP_FOO_FUNCTION_ERROR')
```

 

## おわりに

`try-catch` を使って例外をスローさせる方法は、人類には早すぎたのではないだろうか🤔🤔🤔

例外はResult型のエラーオブジェクトで返しましょう。🤗🤗🤗