OmniAICreator/Qiita-1.07M huggingface dataset:
プロ野球チームが大型連敗をする確率をChat GPTで聞いたPythonのコードで求めてみた

先日、
プロ野球の世界では福岡ソフトバンクホークスが12連敗、
北海道日本ハムファイターズが13連敗、
これが同一リーグ・同一時期に発生するという事態が発生しました。

プロ野球の長い歴史において、
同一リーグ・同一時期に発生することは史上初めてのようで、
ファイターズファンとしては「なんだこれ...」と思いながら連敗脱出まで見届けていました。

さて。このような大型連敗をする確率はどのぐらいなのでしょうか。
Pythonで求めてみました。

### 前提条件
・両チームとも、昨年の試合数と勝率を元に計算。→ソフトバンクは141試合・0.539、日ハムは140試合・0.421

<strong>...といっても、正直Pythonはちょっと学んだことがあるものの、全く持って実践レベルではありませんので、思い切ってChat GPTに聞いちゃいました。</strong>

```
12連敗する確率を計算するためには、試合の結果がランダムで、連敗率が一定であると仮定します。この場合、12連敗が生じる確率は、二項分布を用いて計算できます。

Pythonでは、`scipy`ライブラリの`binom`モジュールを使用して、二項分布を計算できます。以下のコード例では、連敗率が0.5（50%）と仮定して計算しています。

from scipy.stats import binom

# 試合数
total_games = 143

# 連敗数
num_losses = 12

# 連敗率（成功率の逆数として定義します）
loss_rate = 1 / total_games

# 二項分布を使って12連敗が生じる確率を計算
prob_12_losses = binom.pmf(num_losses, total_games, loss_rate)

print(f"12連敗する確率: {prob_12_losses:.6f}")

上記のコードでは、`binom.pmf`関数を使用して12連敗が生じる確率を計算し、結果を小数点以下6桁で表示しています。連敗率が0.5（50%）の場合は、0.012282という確率が得られるかもしれません。

連敗率が異なる場合は、`loss_rate`の値を変更して計算することができます。
```
最初に聞いたところ上記の回答が出てきましたが、
ライブラリをを入れていないとかかんとかでエラーが発生。
ソフトを入れるのは面倒なので、ライブラリを使用せずに計算しました。

最終的なコードを使用し、このような結果となりました。
# ソフトバンクの場合
```Python:qiita.py
# 勝率
win_rate = 0.539

# 連敗数
num_losses = 12

# 試合数
total_games = 141

# 連敗率を計算
loss_rate = (1 - win_rate) ** num_losses

# 141試合中で12連敗する確率を計算
prob_12_losses_in_141_games = loss_rate * total_games

print(f"{total_games}試合中で12連敗する確率: {prob_12_losses_in_141_games:.6f}")
```
```Python:qiita.py
141試合中で12連敗する確率: 0.012991
```
# 日ハムの場合
```Python:qiita.py
# 勝率
win_rate = 0.421

# 連敗数
num_losses = 13

# 試合数
total_games = 140

# 連敗率を計算
loss_rate = (1 - win_rate) ** num_losses

# 140試合中で12連敗する確率を計算
prob_13_losses_in_140_games = loss_rate * total_games

print(f"{total_games}試合中で13連敗する確率: {prob_13_losses_in_140_games:.6f}")
```
```Python:qiita.py
140試合中で13連敗する確率: 0.115067
```
ソフトバンクの場合は0.01%、日ハムの場合は0.1%という結果に。

両方とも余裕で柳田選手や万波選手の打率より遥かに低いですが、
0.01%は「10,000人に1人」、0.1%に至っては「1,000人に1人」と同様。

日本武道館で開催されるライブの収容人数が10,000人、
大きめのライブハウスや小さめのホールのキャパが1,000人なので、
そこまで低い数字ではないといえます。

さらに、1年あたりリーグ戦は750試合、交流戦は108試合、合計858試合開催されます。6年分に換算すると、5148試合ですので、試合数を考えれば大型連敗が発生しても不思議ではないといえます。（実際、2017年以降では巨人、ヤクルト2回、西武などで2桁以上の連敗が発生）
# 同時発生する確率は？
さて、同一リーグにおいて大型連敗が2つ同時に発生する確率はどのぐらいなのでしょうか。本気で計算したい場合、リーグの球団数なども変数に入れる必要がありますが、今回は簡単に

```
0.1%*0.001%=0.0000001%

```
かけあわせて計算しました。

人に換算すると、1億人に1人の割合となり、ここまで来ると日常生活では天文学的な数値となります。そりゃー、プロ野球史上初となるわけですね！


最後に：超初心者の投稿ですので、間違いなどありましたらすみません。
AWSのS3 バケットのアクセス権限設定について

AWSサービスのS3で静的ウェブサイトホスティングのバケットのアクセス権限設定について勉強をしたので自身の理解・復習また文章力の向上のためアウトプットさせていただきます。


<h1>はじめに</h1>
S3で静的webサイトのホスティングを実践してみました。

<h3>S3とは</h3>

S3(Simple Storage Service)とはAmazonが提供する「スケーラビリティ」「データ可用性」「セキュリティ」および「パフォーマンス」を提供するオブジェクトストレージサービスです。ストレージのディスク管理や冗長化の心配の必要が無い便利なサービスなので本業などに専念可能です。Amazon S3を使用してWebやアプリのデータのバックアップ、動画・画像の格納に利用でき、AWSと連携させることで幅広い用途が可能。容量にかかわらずデータを保護で、アクセス管理機能もあるので各種要件に合わせたデータアクセスが可能。

<h3>静的ウェブサイトホスティング機能とは</h3>
S3に保存したデータはHTTP/HTTPSでアクセス可能なので、Webサーバーのように静的Webサイトとして公開することが出来ます。本来は公開するには別途サーバーが必要でしたが、S3を使用することで簡単に公開が可能で、手間やコストも軽減できます。ただし、S3は静的なwebサイトはほホスティング可能ですが、動的なサイト(WordPress)などはホスティング不可です。

静的ウェブサイトホスティングは<a href="https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/WebsiteHosting.html" target="_blank">こちら</a>を参考にしてください。

<h1>アクセス制限までの手順</h1>

参考サイトや他の方の記事を参考に静的サイトを公開するためにバケットポリシーに以下の記述を入れ込みました。
```
{
"Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1551163442413",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "【作成したバケットARN】/*"
    }
  ]
}
```
こちらで静的サイトにアクセスすることに成功し閲覧可能の状態になりました。

次に「指定のIPアドレスのみアクセス可能」の制限設定の記述を入れ込みます。
まず、<a href="https://repost.aws/ja/knowledge-center/block-s3-traffic-vpc-ip" target="_blank">【こちら】</a>を参考にして以下を入れ込みました。
```
{
　"Sid": "Stmt1551164678580",
	"Effect": "Deny",
	"Principal": "*",
	"Action": "s3:*",
	"Resource": "【作成したバケットARN】/*",
	"Condition": {
	  "NotIpAddress": {
		  "aws:SourceIp": "【自身のIPアドレス】"
		}
	}
}
```
<h1>ここで少し詰まったこと</h1>
<h3>アクセス制限がうまくいかずアクセスができない</h3>

入れ込み内容も問題なく入れ込みできてはいたのですが、なぜか指定したIPアドレスからアクセスが出来ませんでした。

<h1>原因</h1>
<h3>【"Effect": "Deny"】の入れ込み方法を勘違いしていた</h3>

「Effect」について調べた結果
Allow:許可を与えるポリシー
Deny:拒否するポリシー
上記の認識でいたので

【"Effect": "Deny",】拒否のポリシーで【"NotIpAddress"が自身のIPアドレス】でしたので
『自身のIPアドレス以外を拒否をする』と勘違いをしてしまい

【"Effect": "Allow"】の記述を削除し【"Effect": "Deny"】の記述のみ入れ込んでいました。。。


<h1>アクセス制限設定の完了</h1>
その後何記事も調べて解決に至り、アクセス制限が確認できた記述が以下になりました

```
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "Stmt155116344",
			"Effect": "Allow",
			"Principal": "*",
			"Action": "s3:*",
			"Resource": "【作成したバケットARN】/*",
			"Condition": {
				"IpAddress": {
					"aws:SourceIp": "【自身のIPアドレス】"
				}
			}
		},
		{
			"Sid": "Stmt155116467",
			"Effect": "Deny",
			"Principal": "*",
			"Action": "s3:*",
			"Resource": "【作成したバケットARN】/*",
			"Condition": {
				"NotIpAddress": {
					"aws:SourceIp": "【自身のIPアドレス】"
				}
			}
		}
	]
}
```

*【作成したバケットARN】は編集ページの上部に表示されています。

<h1>動作確認</h1>
作成したバケット>「静的ウェブサイトホスティング」>「バケットウェブサイトエンドポイント」に許可したIPアドレスからアクセスしホスティングした静的webサイトが表示され、
許可させていないIPアドレスからアクセスをし、アクセス拒否されると動作確認完了になります。

<h1>まとめ</h1>
別途サーバーを用意したりするコスト・手間などが省けて静的サイトの公開するのみでしたらS3を使用するのはとても手軽で便利だと思いました。


最後まで読んでいただいた方、ありがとうございました。
Gitのpre-pushフックでmainブランチへの誤pushを防ぐ方法

# はじめに
<!-- 発端や概要を記載 -->
ブランチの切り替えを忘れてしまい、誤ってmainブランチに直接pushしてしまった経験はありませんか？ GitHubなどではリポジトリの設定を変更することで、mainブランチへのpushを制限できますが、その設定がなされていない場合でも、ローカル環境で特定のブランチ（例えばmain）へのpushを防ぐ対策があります。Gitでは、特定のアクションが起こる前後に実行されるスクリプト、つまり「フック（hook）」という機能を利用することで、このような問題を未然に防ぐことが可能です。今回は、pre-pushフックを用いて、mainブランチへのpushを防止する方法を紹介します。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [方法](#Chapter1)
1. [結果](#Chapter2)
1. [おまけ](#Chapter3)


<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 方法
リポジトリのルートディレクトリに移動します。

```言語名:bash
cd /path/to/your/repository
```

.git/hooksディレクトリにpre-pushという名前の新しいファイルを作成します。

```言語名:bash
touch .git/hooks/pre-push
```

ファイルに実行権限を付与します。

```言語名:bash
chmod +x .git/hooks/pre-push
```

pre-pushファイルを開き、以下の内容を追加します。
```言語名:bash
nano .git/hooks/pre-push
```

ファイルが開いたら、以下のスクリプトを追加します。
```言語名:bash
#!/bin/bash

protected_branch='main'

while read local_ref local_sha remote_ref remote_sha
do
    if [ $protected_branch = ${remote_ref:11} ]; then
        echo "Cannot push to $protected_branch"
        exit 1
    fi
done
```
最後に、pre-push ファイルに実行許可を与えるために以下のコマンドを実行します。
```言語名:bash
chmod +x .git/hooks/pre-push
```

<a id="#Chapter2"></a>
# 結果
application.scssをmainブランチへpushしようとすると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3527138/6c9282aa-3599-3c6b-f882-5c8987c9bbc1.png)

このようなエラーが表示されpushができない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3527138/82e00b41-a26d-c930-e7c0-129ee6ee0bb8.png)

<a id="#Chapter3"></a>
# おまけ
プロテクトするブランチを追加することもできます
```言語名:bash
#!/bin/bash

protected_branches=("main" "develop")

while read local_ref local_sha remote_ref remote_sha
do
    for branch in "${protected_branches[@]}"; do
        if [ $branch = ${remote_ref:11} ]; then
            echo "Cannot push to $branch"
            exit 1
        fi
    done
done
```
C言語の添字

```c
#include <stdio.h>
int main(void){
    char str[2][8] = {
        // 0行目の6文字
        // (0,0)(0,1)(0,2)(0,3)(0,4)(0,5)
        {'p','a','i','z','a','\0'},
        // 1行目の8文字
        // (1,0)(1,1)(1,2)(1,3)(1,4)(1,5)(1,6)(1,7)
        {'A','t','C','o','d','e','r','\0'}
    };
    printf("%s %s",str,str[1]);
}

```
ブラウザ
paiza AtCoder
GC9A01丸型液晶とM5StampS3をLovyanGFXで使う方法

以前[「Waveshare RP2040-LCD-1.28」](https://qiita.com/masaya3/items/f469ca80e8c1e133d405)と内容はほぼ同じですが、今回は液晶単独＋M5StampS3の備忘録

製品情報はこちら
ドライバ：**GC9A01A**
インターフェース：**SPI**

製品は、探しせばAliExpressとかでよく出てくるやつです。

![IMG_4711.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/632da4aa-a00b-8152-557f-ee20a5e35627.jpeg)


M5StampS3の使い方はこちらとかをご参考ください

https://qiita.com/n0bisuke/items/ce6bec53d1def34497e3



### LovyanGFXを使ってみる 

GC9A01ドライバに対応するLGFX作ります。

前回記事にした[「Waveshare RP2040-LCD-1.28」](https://qiita.com/masaya3/items/f469ca80e8c1e133d405)とほぼ同じなので、こちらのGC9A01ドライバを修正して対応します。

#### 配線

1.27ピンなんて半田付けできないのです。
2.54ピンを使用。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/ab879d93-9987-df01-8d3a-b7d58f078d84.png)


#### 変更点

###### ポート番号

|GPIO  |TYPE |
|---|---|
|GP9  | DC |
|GP7  | CS |
|GP15  | SCL |
|GP13  | SDA |
|GP12  | RST |

バス制御の設定
```CPP
auto cfg = _bus_instance.config();    // バス設定用の構造体を取得します
cfg.pin_sclk   = 15;
cfg.pin_miso   = -1;
cfg.pin_mosi   = 13;
cfg.pin_dc     = 9;
```

```CPP
auto cfg = _panel_instance.config();    // 表示パネル設定用の構造体を取得します。
cfg.pin_cs           =    7;  // CSが接続されているピン番号   (-1 = disable)
cfg.pin_rst          =    5;  // RSTが接続されているピン番号  (-1 = disable)
```

#### LGFXクラス
ポート等を設定したLGFXクラスは以下の通り

```CPP
class LGFX : public lgfx::LGFX_Device
{
    lgfx::Panel_GC9A01      _panel_instance;
    lgfx::Bus_SPI       _bus_instance;   // SPIバスのインスタンス
    lgfx::Light_PWM     _light_instance;
  public:
    LGFX(void)
    {
      { // バス制御の設定を行います。
        auto cfg = _bus_instance.config();    // バス設定用の構造体を取得します。
        cfg.spi_host   = SPI2_HOST;
        cfg.spi_mode   = 0;
        cfg.freq_write = 80000000;
        cfg.pin_sclk   = 15;
        cfg.pin_miso   = -1;
        cfg.pin_mosi   = 13;
        cfg.pin_dc     = 9;
        _bus_instance.config(cfg);
        _panel_instance.setBus(&_bus_instance);
      }

      { // 表示パネル制御の設定を行います。
        auto cfg = _panel_instance.config();    // 表示パネル設定用の構造体を取得します。
        cfg.pin_cs           =    7;  // CSが接続されているピン番号   (-1 = disable)
        cfg.pin_rst          =    5;  // RSTが接続されているピン番号  (-1 = disable)
        cfg.panel_width      =   240;  // 実際に表示可能な幅
        cfg.panel_height     =   240;  // 実際に表示可能な高さ
        cfg.offset_x         =     0;  // パネルのX方向オフセット量
        cfg.offset_y         =     0;  // パネルのY方向オフセット量
        cfg.readable         =  true;  // データ読出しが可能な場合 trueに設定
        cfg.invert           =  true;  // パネルの明暗が反転してしまう場合 trueに設定

        _panel_instance.config(cfg);
      }

      setPanel(&_panel_instance); // 使用するパネルをセットします。
    }
};
```

### 動かしてみる

こちらも時計を出す。やっぱり丸はかっこいいね。

![IMG_4710.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/a751fe61-1d91-4a35-fe7c-e72ca2522128.jpeg)


### まとめ
9月にM5Stackから丸型がでるそうなので、丸型欲しい方はそっちを待ってもいいかも。
Flutterのcontext.mountedについて

# はじめに
備忘録的に残します。
ミスや補足があればご指摘お願いします。

# context.mountedとは
`context.mounted`は現在のWidgetがツリーに取り付けられているかをチェックするための手法。
Widgetが取り付けられていればtrueとなり、そうでなければfalseとなります。

# 使用例
非同期処理のが終了した時にその結果を反映させたい場面があるかと思います。例えば、処理が終わったタイミングでダイアログをpopしたい場合などです（今回はその用途で使いました。ignoreを使わずに、if(context.mounted)を用いることで、エラーを回避できたりします。
```dart:サンプルコード
Future<void> nyan() async {
  var pyoe = await feadCat(); // 何らかの非同期処理
  if (context.mounted) {
    setState(() {
      // 状態の更新
    });
  }
}
```

正し、これを多用するよりも根本的な問題を解決する方法を探した方がよさそうに感じましたっ！
App Runner のカスタムドメイン追加時にwwwサブドメインもまとめて追加する方法

# やりたいこと

App Runnerのカスタムドメインで設定したドメインに、`www`サブドメイン付きでアクセスしても同じサイトを表示させてあげたい

要するに……
```
https://test.com/
https://www.test.com/
```
このどちらで来ても同じサイトを表示したい、というケースの対応方法を解説します。

*注）　同じサイトを表示するだけで、いずれかにリダイレクトするものではないです*

# 手順

## 1. App Runnerでアプリケーション公開

今回は、ここは済んでいる前提で。

## 2. カスタムドメインの設定

注意ポイントです。
2023/08/06時点では、コンソールからでは、メインドメインと`www`サブドメインの両方をまとめて設定することができません。
APIで、サポートされているということなので、今回はboto3(python)で設定を進めます。

https://docs.aws.amazon.com/ja_jp/apprunner/latest/dg/manage-custom-domains.html

また、既にカスタムドメインを設定している場合、現状、**変更**ができないようで、後から`www`サブドメインにも対応できる設定書き換えよう、ということはできませんでした。
そのため、自分は設定済みのカスタムドメインを一度、削除してから再度、API経由で設定をし直しました。
その際に、紐付けていたドメインでは数時間弱アクセスできない可能性があるので、ご注意ください。

では、boto3のコードです。

```Python
import boto3
import json

my_session = boto3.Session(profile_name='YOUR_PROFILE_NAME')
client = my_session.client('apprunner')

arn = 'arn:aws:apprunner:ap-northeast-1:000000000000:service/~~~~~~~'

response = client.associate_custom_domain(
    ServiceArn=arn,
    DomainName='test.jp',
    EnableWWWSubdomain=True
)

print(json.dumps(response, indent=2))
```
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apprunner/client/associate_custom_domain.html


**EnableWWWSubdomain**を**True**にするのが重要です。
ここの値をTrueにすることで`www`サブドメインの設定もまとめて出来るようになります。

## 3. Route53でレコードの設定をする

AWSコンソールに戻って、App Runnerのカスタムドメインの「DNSの設定」を確認すると、コンソールからGUI操作でサブドメイン作成したときは表示されなかった`www`サブドメイン用のCNAME レコードが表示されています。（「1. 証明書の検証を設定する」という項目に計3つのCNAMEが表示されているかと思います。）

次に、ALIASレコードを設定します。
App Runnerのカスタムドメインの「DNSの設定」の「2. DNS ターゲットを設定する」には、メインドメインの設定しか書いていませんが、`www`サブドメインも同様に、`www.test.com`のようなAレコードを作成してメインドメインと同じALIASレコードを登録します。

設定の反映まで少々時間がかかりますが、だいたい数時間程度で反映されるかと思います。

---

公式ドキュメント読まないと気づけない機能だったので、コンソールにもAPI経由では可能です、とか書いておいて欲しいですね……地味に需要があって、追加された機能だと思うので。
そのうち、コンソールからの設定はもちろん、後付けで設定もできるようになるのかな。
App Runnerの今後の機能拡張に期待です!!
SwiftUIで数式を入力する方法

はじめに
=
SwiftUIを学び始めてなんとなく要領がつかめてきた所で,
「そういえばSwiftUIで数式を表示する方法ってあるのかな」と考えて探していました.
UIKitであれば「iosMath」があったのですが、SwiftUIでは使えなさそうな感じ.
そこで, SwiftUIでも数式を入力する方法が見つかったのでここにアウトプットしておきます.

開発環境
=
macOS Ventura13.4.1  M1チップ
Xcode 14.3.1

使用するパッケージ
=
今回使用するパッケージは「LaTexSwiftUI」というものです.

詳細は以下より↓
https://github.com/colinc86/LaTeXSwiftUI

導入方法
=
Xcodeを起動したら「File」→「Add Packages...」で, 
「Search or Enter Package URL」に「 https://github.com/colinc86/LaTeXSwiftUI 」　 
を入力してパッケージをインストールします.

プログラムの例
=
ここではいくつかの簡単な使用例を載せておきます

まず使用するファイルでライブラリをインポートします.
```Swift
import LaTeXSwiftUI
```
基本的な使い方
-

数式を入力する時はLaTeXを使います.
```Swift:ContentView.swift
import SwiftUI
import LaTeXSwiftUI

struct ContentView: View {
    var body: some View {
            LaTeX("$x = \\frac{-b \\pm \\sqrt{b^2-4ac}}{2a}$")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

```
実行した時のSimulatorの写真↓

<img width="200" alt="Simulator Screenshot - iPhone 14 Pro - 2023-08-05 at 23.31.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3523017/e211f457-3132-e0cd-cd00-23a4b3d9041a.png">

色を変えたりする
-

LaTexはTextでサポートされる修飾子を使うことができるので, 
Textと同じように文字の色を変えたりできます.

```Swift:ContentView.swift
import SwiftUI
import LaTeXSwiftUI

struct ContentView: View {
    var body: some View {
            LaTeX("$x = \\frac{-b \\pm \\sqrt{b^2-4ac}}{2a}$")
            .foregroundColor(.red)
            .font(.title2)
            .frame(width: 300)
            .border(Color.blue)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```
実行した時のSimulatorの写真↓
<img width="200" alt="Simulator Screenshot - iPhone 14 Pro - 2023-08-05 at 23.31.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3523017/13757eb7-792e-b683-2dd4-f796de57b476.png">

文字も含めた使い方
-
デフォルトの状態では文字を含めたものを入力すると数式だけがレンダリングされます.
文字も含めてレンダリングしたい場合は修飾子を付けます.
```Swift:ContentView.swift
import SwiftUI
import LaTeXSwiftUI

struct ContentView: View {
    var body: some View {
        VStack{
            Text("式①")//デフォルト状態
            LaTeX("Euler's identity is  $e^{i\\pi}+1=0$.")
            
            Text("式②")//onlyEquationsを明示
            LaTeX("Euler's identity is  $e^{i\\pi}+1=0$.")
                .parsingMode(.onlyEquations)
            
            Text("式③")//文字も含めてレンダリング
            LaTeX("\\text{Euler's identity is } e^{i\\pi}+1=0\\text{.}")
                .parsingMode(.all)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```
実行した時のSimulatorの写真↓
<img width="200" alt="Simulator Screenshot - iPhone 14 Pro - 2023-08-06 at 00.21.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3523017/c9e48e26-a8c2-87ee-ce4c-7dcea54f3756.png">

おわりに
=
ここでは簡単に数式を入力する方法を述べました.
どれくらい実用的なものかは分かりませんが,
色々入力してみると楽しいのではないかと思います.
他にも機能はあるらしいので実際にgithubを参考にしてみてください.
LaTexの入力方法は以下のサイトなどを参考にしていただければ良いと思います.

https://texwiki.texjp.org/?LaTeX%E5%85%A5%E9%96%80

ちなみに上のサイトに記載されているものをそのままコピー&ペーストすると
エラーが起こります.
必ず「\」を追加して入力するようにしてください
ex)πを表したい時は「\pi」ではなく「\ \pi」にする
せんせー、スマートコントラクトってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/7f59d21b-0564-377b-a326-47169950dc66.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/319ddbbb-e9dd-5833-688d-5808a705af9b.png)

せんせー、スマートコントラクトってなに？

# スマートコントラクトとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/754ad1db-cf66-be94-8f33-137d3e28f1cc.png)

スマートコントラクトは、ちょっと難しいかもしれないけれど、
友達との約束をコンピュータが助けてくれるようなものだと考えるとわかりやすいかもしれないです。

友達とおもちゃを交換する約束をしたとき、その約束をちゃんと守ることが大切でしょね。
でも、どちらかが約束を忘れてしまうこともあるかもしれないです。

ここでスマートコントラクトが登場します。
スマートコントラクトはコンピュータのプログラムで、約束をしっかり記録しておいて、
約束したことがちゃんと実行されるように助けてくれるんです。

このプログラムは、約束したことがちゃんとできたときだけ、
次のステップに進むようにできているから、約束を忘れる心配がないんです。

例えば、大人たちがお金の取引をするときにも使われることがあります。
売り買いの約束をスマートコントラクトで記録しておけば、
約束がちゃんと守られることをコンピュータが確認してくれるから、安心して取引ができるです。

だから、スマートコントラクトは、約束を守るための特別なコンピュータの助け手みたいなものなんです。

# まとめ

スマートコントラクトは、約束を守るための特別なコンピュータの助け手みたいなもの
せんせー、サテライトイメージングってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/7f59d21b-0564-377b-a326-47169950dc66.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/319ddbbb-e9dd-5833-688d-5808a705af9b.png)

せんせー、サテライトイメージングってなに？

# サテライトイメージングとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/754ad1db-cf66-be94-8f33-137d3e28f1cc.png)

サテライトイメージングというのは、宇宙に飛んでいる人工衛星が、地球の上から写真を撮ることです。

君が遊び場で高い滑り台の上に登って、下を見たことがありますか？
すごく高いところから見ると、遊び場の全体がよく見えるよね。人工衛星もそれと同じで、
地球のすごく高いところから、地球の写真を撮るんです。

人工衛星が撮った写真は、森や山、川、町など、いろいろな場所の様子を見ることができます。
天気の予報をするときや、自然災害が起きたときの対策をするときなどに、とても役立ちます。

例えば、大きな台風が来るとき、人工衛星の写真を見て、どこに台風が向かっているのかを早く知ることができます。
それから、人々に早く知らせて、安全に避難する手助けをすることができるんです。

だから、サテライトイメージングは、地球の様子を上から見ることで、
みんなの安全や自然を守るためにとても大切なことなんです。

# まとめ

サテライトイメージングというのは、宇宙に飛んでいる人工衛星が、地球の上から写真を撮ること
【VSCode】折りたたみ箇所の色を変更する


## はじめに
VSCodeでコードを折りたたむと折りたたんだ行が以下のように強調表示されます。

![スクリーンショット 2022-08-30 17.34.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/4c033e55-7fda-6757-2295-e6da4ee0720d.png)

この強調表示の色の変更方法について記載します。

## 変更方法
`stting.json`に以下のように追記することで強調表示の色を変更できます。

```~/Library/Application Support/Code/User/settings.json
{
  "workbench.colorCustomizations": {
    "editor.foldBackground": "#ffffff07"
  },
}

```

![スクリーンショット 2022-08-30 17.36.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/7bca5a93-35e6-c12e-79c8-8bda52908448.png)

また強調表示しないようにするには以下を追記します。

```~/Library/Application Support/Code/User/settings.json
{
  "editor.foldingHighlight": false,
}

```
![スクリーンショット 2022-08-30 17.38.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/62cbefa3-cdc7-c20a-8a71-63fb4b7eafc7.png)
AWS Certified Developer - Associateを１週間で合格しました。


DVAの受験を受けてきて、無事合格しました。

![スクリーンショット 2023-08-05 22.11.10 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1225450/238dd0f2-8d6d-4cbd-69b4-61935f3a42cd.png)

合格するまでのプロセスや勉強方法を備忘録として投稿して、受験を考えてる方に参考になればと思います！

https://aws.amazon.com/jp/certification/certified-developer-associate/


# 前提知識

- ３年前にSAA、CLFを取得済（更新忘れて失効。。。また頑張る。）
- AWS歴４年弱だが、業務ではリリース時くらいしかAWSを操作しない。
- Lambda,API Gatewayは個人的に色々触ったことはある。


# 目的
バッチが欲しかったから。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1225450/2e21dab5-eb0b-be4a-bdbc-c3f5af04c7d6.png)

というのは半分冗談で、
業務で新規サービスをAWSで開発することとなり、アーキテクチャ構成を考えたり、CI/CDを導入して開発効率を上げなきゃなーと思い、知識習得のためDVAを取得しました。
他には、できるだけ運用・保守をしたくないので、マネージドサービスとサーバレスサービスを積極的に導入したいという動機もありました。

# スケジュール
2023/7/30 DVA申し込み
2023/7/30 ~ 8/4 勉強期間
2023/8/5 試験。合格！！

※中々ハードスケジュールでした。。。

# 勉強方法、スケジュール

## 教材
TechStock様様です。。。

https://techstock.jp/

## スケジュール
1. 会員登録（プロフェッショナルプラン）　
※8/5時点 ¥4,580 90日間
1. AWS認定本試験モードを実施
点数: 615 点
正解率: 63.08%
1. コース内のセクション問題をひたすら解く。
１日3時間（１日平均１5セクションくらい）
時間の都合上１周しかできませんでした。
予定だと本試験モードを受けてどれだけアウトプットできているか確認したかったです。。
↑次回の教訓

## 勉強中のポイント
1. 間違った問題をもう一回解く。
特に重要だなと思ったのは、
**間違った選択肢がなぜ間違ってるかを細分化する。そして言葉で説明できるようにする。**
ことかなと。
1. 問題文で求められていることは何か明確にする。
コスト最適化、アーキテクチャの変更なし、最短で、○○に影響なく、マネージド、◯◯性、などの言葉にアンテナを貼る。

# 試験当日
あまり悩んで時間が過ぎて時間切れの心配があったので、一瞬でも迷ったらフラグをつけました。
全て解き終えて90分残ってたので、フラグをつけた問題をペーパー用紙に図解しながら落ち着いて解き直しました。

# 要点
記憶と個人的感想が含まれておりますが、ここは理解しておくべきこと。
全てを網羅できていないので、↑の教材の問題にチャレンジしてみてください！！

- API Gateway(Canary、Stage、Resource、API Key)
- 暗号化（サーバサイド、クライアント、S3暗号化）
- S3(S3イベント通知、Transfer Acceleration、バケットポリシー)
- 認証情報(Secrets Manager、Systems Manager Parameter Store)
- Beanstalkのデプロイ方法
- Cognito（ユーザープール、IDプール）
- Lambda(/tmp、リソース枯渇、レイヤー、エイリアス、バージョン）
- SQS(FIFO、可視性タイムアウト、ロングポーリング、デットキュー）
- IAM（ロール、ユーザー、ポリシー）
- DynamoDB(GSI、LSI、DAX、Stream、WCU、RCU)
- ECS（タスク定義、サービス）
- Code３兄弟
- Elasticache（Redis、Memcashed）
- CloudFormation(SAM、Stack、組込関数）

# 最後に
最後まで閲覧ありがとうございます。
今回は仕事が繁忙期で帰りが遅い中だったので、体力も脳みそもギリギリでした。。。
次回はもう少し余裕をもって試験日程を決めたいと思います。
次回はSysOpsを取得予定です。
資格マニアと言われないように業務でも活かしていきたいと思います！！
Plasmo に Chakra UI を導入する

Plasmo に Chakra UI を導入してみました。この記事では、その導入方法について記します。

[Plasmo](https://www.plasmo.com) はブラウザ拡張機能を開発するためのフレームワークです。詳細は次の記事が分かりやすく解説していたのでそちらをご覧ください:

https://zenn.dev/nado1001/articles/plasmo-browser-extension

今回使用したコードはこちらのリポジトリにあります:

https://github.com/yamamoto-yuta/plasmo-with-chakraui

## 動作環境

今回使用した動作環境は次の通りです:

- Node.js (v18.16.0)
- Plasmo (v0.82.0)
- Docker (v24.0.2)
- Docker Compose (v2.19.1)

docker-compose.yml は次のように記述しました:

```docker-compose.yml
version: '3'

services:
  app:
    image: node:18.16.0
    volumes:
      - .:/usr/src/app
    working_dir: /usr/src/app
    tty: true

```

Plasmo プロジェクトの作成は次のコマンドで行いました:

```
$ docker compose run --rm app npm create plasmo
```

作成完了後、プロジェクトディレクトリ内へ docker-compose.yml を移動しました（これをしておかないと、 `docker compose run` のとき毎回 `cd <PROJECT_DIR>/` しないといけなくて面倒なので…）。

## Chakra UI のインストール

公式ドキュメント[^1]にあるインストールコマンドを Docker コンテナ内で実行すれば OK です。

[^1]: [Installation - Chakra UI](https://chakra-ui.com/getting-started)

```
$ docker compose run --rm app npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
```

## Popup に Chakra UI を使う

Popup に Chakra UI を使う場合、 `<ChakraProvider>` 内でコンポーネントを記述していけば OK です。

サンプルコード:

```popup.tsx
import { ChakraProvider } from "@chakra-ui/react"
import { Button } from "@chakra-ui/react"

const IndexPopup = () => {
  return (
    <ChakraProvider>
      <Button colorScheme="teal">Button</Button>
    </ChakraProvider>
  )
};

export default IndexPopup;
```

動作結果:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489030/3a0eeea4-a925-55a0-1bd3-b66050ded602.png)

ボタンのデザインから、ちゃんと Chakra UI の Button になっていることが確認できます。

## Content Scripts UI (CSUI) に Chakra UI を使う

CSUI にカスタムスタイル（今回の場合 Chakra UI ）を適用したい場合、 `<style>` を 返す `getStyle()` 関数を export します。

https://docs.plasmo.com/framework/content-scripts-ui/life-cycle#custom-styles

Chakra UI は内部で Emotion を利用している [^2] ので、公式ドキュメントのサンプルコードがそのまま参考になります。

https://docs.plasmo.com/framework/content-scripts-ui/styling#css-in-js

[^2]: [Comparison - Chakra UI](https://chakra-ui.com/getting-started/comparison#the-runtime-trade-off-%EF%B8%8F)

今回、公式ドキュメントをもとに作成したサンプルコード:

```content.tsx
import createCache from "@emotion/cache"
import { CacheProvider } from "@emotion/react"
import { ChakraProvider } from "@chakra-ui/react"
import { Button } from "@chakra-ui/react"

const styleElement = document.createElement("style")

const styleCache = createCache({
  key: "plasmo-mui-cache",
  prepend: true,
  container: styleElement
})

export const getStyle = () => styleElement;

const CustomButton = () => {
  return (
    <CacheProvider value={styleCache}>
      <ChakraProvider>
        <Button colorScheme="teal">Button</Button>
      </ChakraProvider>
    </CacheProvider>
  )
}

export default CustomButton
```

動作結果:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489030/1196e13e-787f-45ce-f548-aa662fd343a3.png)

ボタンのデザインから、ちゃんと Chakra UI の Button になっていることが確認できます。

## 結び

この記事では、 Plasmo に Chakra UI を導入する手順について記しました。

Plasmo は公式ドキュメントが充実している上にサンプル実装が豊富なので、つまづいたら色々調べる前にまずこの2つを確認しに行くのが解決への近道だなと思いました（自戒）。

https://github.com/PlasmoHQ/examples
[Troubleshooting]Kubernetesのnamespacesが消えないときの対処法

```bash
helm uninstall 2.0.0 -n jupyterhub
```
などで不要なものを消そうとおもってもSTATUS Terminatingと表示されて消せないとき

### まずすべきもの
対象の全podとserviceを削除してからuninstallする
しないと干渉する
```bash
kubectl delete networkpolicy --all -n ${name}
kubectl delete pods --all -n ${name}
```

### それでもごみが残ってしまうとき

```bash
kubectl get namespace ${name} -o json>t.json
```
でt.jsonに情報を出力した後、内部のspec finalizersを空欄にする
```json
  "spec": {
    "finalizers": [
    ]
  },
```
その後kubernetesに反映させる

```bash
kubectl proxy &
curl -k -H "Content-Type: application/json" -X PUT --data-binary @t.json http://127.0.0.1:8001/api/v1/namespaces/${name}/finalize
```

### 参考
[Command to delete all pods in all kubernetes namespaces](https://stackoverflow.com/questions/33509194/command-to-delete-all-pods-in-all-kubernetes-namespaces)

[How to Delete a Kubernetes Namespace {Standard & Force Removal}](https://phoenixnap.com/kb/kubernetes-delete-namespace)

[[小ネタ]Kubernetesで消せないNamespaceが発生した場合の対処方法 | DevelopersIO](https://dev.classmethod.jp/articles/k8s-namespace-force-delete/)
Intel MacBook のローカルとコンテナ実行を比較する

## はじめに

環境構築のお手軽さ（やり直しやすさ）から、よく Docker コンテナ上で Livebook を起動しています

ローカル環境の OS が Linux であればコンテナを使っていてもパフォーマンスはほぼ変わりません

しかし、 Linux 以外の OS の場合、間に一つ仮想マシン（VM）を挟んでいるため、遅くなってしまいます

しかも VM に割り当てられるリソースは限られるため、重い処理では更に顕著に差が出るはずです

![スクリーンショット 2023-08-06 1.47.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/eafe67ea-837c-d7a4-322a-c1e33d39257c.png)

どの程度の差が出るのか Livebook で検証してみます

## 実行する処理

Nx の様々なバックエンドによる行列の加算処理を計測の対象とします

`Benchee.run` によって、IPS（Instructions Per Second 1秒間に何回処理を実行できたか）を計測します

```elixir
bench = fn backend ->
  tensor =
    {200, 200}
    |> Nx.iota(type: :f64, backend: backend)

  Nx.add(tensor, tensor)
end
```

```elixir
Benchee.run(%{
  "binary" => fn -> bench.(Nx.BinaryBackend) end,
  "exla" => fn -> bench.(EXLA.Backend) end,
  "torchx" => fn -> bench.(Torchx.Backend) end,
  "evision" => fn -> bench.(Evision.Backend) end
})
```

詳細な内容は以下の記事を参照してください

https://qiita.com/RyoWakabayashi/items/45edc8ddbccba139a5ba

`Nx.BinaryBackend` を使っている場合は単純に Elixir で 40,000 回足し算を行っています

`Evision.Backend` なら OpenCV 、 `EXLA.Backend` なら XLA を使った行列演算を実行しています

## ローカル

実行環境は以下の通りです

- MacBook Pro 13 inch, 2019
  - macOS Ventura 13.4.1
  - CPU 2.4 GHz クアッドコアIntel Core i5
    （物理的には 4 コア、 Hyperthreading による擬似 8 コア）
  - メモリ 16 GB
- Elixir 1.15.2
- Erlang 26.0.2
- Livebook 0.10.0

Elixir と Erlang は asdf でインストールし、 Livebook は GitHub からタグ指定でクローンしてきたコードをローカルビルドしています

実行結果は以下のようになりました

| バックエンド |  IPS    |
|:---------|--------:|
| binary   |      79 |
| evision  |   2,580 |
| exla     |   8,260 |
| torchx   |   5,810 |

## コンテナ

コンテナには Rancher Desktop を使います

また、イメージは以下のリポジトリーのものを使いました

https://github.com/RyoWakabayashi/elixir-learning

- Rancher Desktop 1.9.1
  - CPU割当て 6
  - メモリ割当て 10 GB
- Debian 11
- Elixir 1.15.2
- Erlang 26.0.2
- Livebook 0.10.0

実行結果は以下の通りです

| バックエンド |  IPS   |
|:---------|--------:|
| binary   |      41 |
| evision  |     392 |
| exla     |     771 |
| torchx   |     862 |

ローカルと比べて明らかに遅くなりましたね

## 比較

ローカルとコンテナの比較表は以下のようになります

| バックエンド | ローカル　IPS | コンテナ IPS | ローカル / コンテナ |
|:---------|-----------:|----------:|---------------:|
| binary 　 |         79 |        41 |           1.93 |
| evision 　|      2,580 |       392 |           6.58 |
| exla    　|      8,260 |       771 |          10.71 |
| torchx  　|      5,810 |       862 |           6.74 |

BinaryBackend 、つまり単純な足し算のループでも 2 倍近い差がありました

EXLA に至っては 10 倍も差があります

## まとめ

使用目的に応じて環境を使い分けましょう

- コンテナ
  - 環境構築を試行錯誤したい
  - 速度は気にしない

- ローカル
  - 環境構築はすでに確立している
  - 速度が問題になる
PF作成：５日目

昨日の疑問点をまとめて質問したおかげで新たな発見があったのとやり直しが発生してしまった。

## 進捗
- 御朱印を投稿するときに神社、仏閣が存在しなかった場合ユーザーに投稿してもらって承認制にしようと思っていたが、それだとだいぶ難しそうなので承認制は無くした。その代わり定期的に見回りをして編集、削除をするような仕組みに変更した。
- devise関連の仕組みを完成させた。
- 画面遷移図の修正


## 学んだこと
- not nullをつけない場合、FKは使用不可。なので代わりにバリデーションなどでデータの信頼性を高めるやり方をするといいらしい。だけどそれは後からできることなので、すぐにやる必要はない。
- カラムに年月日を入れたい場合dateを使用する。<br>(参照：https://qiita.com/jackie0922youhei/items/472ae8a35455475b3de8)
- 日付の入力フォームを使用したい場合はfrom_withを使用すると簡単にカレンダー管理ができるらしい。（ちなみにカレンダー管理をするメリットは簡単に日付を入力できるから。ただし、古い記憶に遡る場合面倒なのでプルダウンのやり方がおすすめ。おすすめできないのは手入力）<br>(参照:https://qiita.com/___fff_/items/ad5ce5d2a0090d8c6b6c）
- ワイヤーフレームや画面遷移図を書くと部分テンプレートを使用できそうな部分が見えてくる。


## 明日の予定
明日からはいよいよ本格的にアプリケーション実装に入る。最初に簡単にTopページを作成してから管理者側が神社仏閣を投稿できる仕組みを作り終えるところまでいきたい。明日も１３：００から質問できるのでやれるところはどんどんやっていこうと思うが、出かける用事もあるので効率よくやっていこう。
macでFinder上では隠しフォルダになってるのに、lsでファイルを見ると隠しフォルダとはなっていない場合

ある日、macのデスクトップのファイルにアクセスしようとしたら全部ファイルが消えていて焦った。幸い、"command+shift+."で隠しフォルダを表示させてみると全部ファイルは見つかったので助かった。
但し、
```
ls　
```
でファイルを見てみると、全て表示されており、
```
ls -a　#隠しフォルダも表示する。macでは隠しフォルダは.から始まる名前になっている
```
でなくても表示された。


このままでも問題ないと言えば問題ないが、見栄えが悪いので戻すやり方についてメモっておく。



```
chflags nohidden 'file path '　　　　　　　　　#fileの可視化
```

これをすれば治った。但し、隠しておきたいファイルがある場合は以下のコマンドで戻せば良い
```
chflags hidden 'file path'       #fileの非可視化
```


追記：
ただのバグだったようです、、、別の日に開いたら治ってました。
せんせー、マイクログリッドってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/7f59d21b-0564-377b-a326-47169950dc66.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/319ddbbb-e9dd-5833-688d-5808a705af9b.png)

せんせー、マイクログリッドってなに？

# マイクログリッドとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/754ad1db-cf66-be94-8f33-137d3e28f1cc.png)

マイクログリッドというのは、小さな町や村などで自分たちだけの電気を作る特別な方法です。

大きな町では、大きな電気工場からたくさんの家に電気が行くようになっているんです。
でも、小さな町や遠く離れたところでは、大きな工場から電気をもらうのが難しいこともあります。

そこで、マイクログリッドを使うと、その町や村だけで自分たちの電気を作ることができるんです。
太陽の光や風などの自然の力を使って、ちょうどいい量の電気を作ることができます。

君がお家でお料理をするとき、必要なものを全部自分で用意することを想像してみてください。
自分で材料を用意して、自分で料理するんだ。そうすると、自分にちょうどいい料理ができますよね。

マイクログリッドも同じで、自分たちにちょうどいい電気を自分たちで作ることができるんです。
これはとてもスマートで、地球にやさしい方法なんです。

# まとめ

マイクログリッドというのは、小さな町や村などで自分たちだけの電気を作る特別な方法
Line Works Api 2.0を使ってGoogleスプレッドシートでGasでBot通知

```javascript
function sendLine(text, channelId) {
  
  //LINE WORKS APIのリクエストURLを定義 (下の XXX… を Bot ID に、YYY… をトークルームのチャンネルID に変更する)
  const url = `https://www.worksapis.com/v1.0/bots/id/channels/${channelId}/messages`
  
  //LINE WORKSへ接続するための基本設定 (下の XXX… をそれぞれの値に変更する)
  const config = {
    SCOPE: 'bot,bot.read',
    CLIENT_ID: '',
    CLIENT_SECRET: '',
    SERVICE_ACCOUNT: '',
    PRIVATE_KEY: ''
  }


  //LINE WORKS API の Access Token を取得する
  const accessToken = getAccessToken(config).access_token;

        //LINE WORKS へ Post するデータを作成する
        const options = {
          method: 'post',
          headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json'
          },
          payload: JSON.stringify({
            'content': {
            'type': 'text',
            'text': text
            }
          })
        }
      
        // LINE WORKS へ Post する
        const response = UrlFetchApp.fetch(url, options);
}

//LINE WORKS API から Access Token を取得する関数
function getAccessToken(config) {
  const time = Date.now();
  const header = Utilities.base64Encode(JSON.stringify({ 'alg': 'RS256', 'typ': 'JWT' }));
  const claimSet = Utilities.base64Encode(JSON.stringify({
    'iss': config.CLIENT_ID,
    'sub': config.SERVICE_ACCOUNT,
    'iat': Math.floor(time / 1000),
    'exp': Math.floor(time / 1000 + 3600)
  }));
  const signature = Utilities.base64Encode(Utilities.computeRsaSha256Signature(`${header}.${claimSet}`, config.PRIVATE_KEY));
  const jwt = `${header}.${claimSet}.${signature}`;

  const endpoint = 'https://auth.worksmobile.com/oauth2/v2.0/token';
  const options = {
    method: 'post',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    payload: {
      'assertion': jwt,
      'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
      'client_id': config.CLIENT_ID,
      'client_secret': config.CLIENT_SECRET,
      'scope': config.SCOPE
    }
  }
  return JSON.parse(UrlFetchApp.fetch(endpoint, options));
}


```
Streamlitで画面を録画する


[Streamlitのドキュメント](https://docs.streamlit.io/library/advanced-features/app-menu)に記載されているのですが、Streamlitのハンバーガーメニューから簡単に画面を録画することができます。  

https://docs.streamlit.io/library/advanced-features/app-menu

## 使い方

右上のハンバーガーメニューから「Record a screencast」を選択。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/92d8c81b-9a31-a95b-b62e-b2513030fb2f.png)

表示されるダイアログで「Start recording!」をクリック。  
「Also record audio」チェックボックスを入れれば一緒に音声も録音できるそうです。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/f07be3e7-b729-121b-950b-7edb6dd2dbf7.png)

アプリにコンテンツの読み取りを許可すると録画してくれるので、「共有する情報を選択」で録画する対象を選択しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/759048e2-c24f-80bb-8574-4371902c0af8.png)

3カウント後に録画が開始されます！  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/63422226-799a-c625-a6a2-f866f03b457e.png)

録画の終了はESCキー。  
ハンバーガーメニューから「Stop recording」を選択してもいいようです。  

録画を終了するとプレビューと保存のダイアログが表示されます。  
「Save video to disk」をクリックすればWebM形式で動画がダウンロードできます！  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/4cce7152-6d00-e590-33ff-4822897d01b0.png)


## 注意事項

ブラウザのバージョンや設定によっては自分自身を録画することができないようです。  
そういうときはアプリを二重起動するしかないかも。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/7469de3d-0d17-6895-4649-b126eb16030b.png)

こんな感じで左のアプリで右のアプリを録画することができます。
Aiven・アイデアの発表 - 製品開発の方向性を決めるチャンス

<font color="Grey">*[Announcing Aiven Ideas - your chance to shape the direction of our product development](https://aiven.io/blog/announcing-aiven-ideas)の翻訳です。*</font>

2023年8月2日

# 製品開発の方向性を決めるチャンスです。

Aivenでは、製品ロードマップを公開することで、オープン性をさらに強化しています。今すぐご登録の上、開発へのフィードバックや新しいアイデアをお寄せください。

信頼関係の最前線は透明性です。Aivenをご利用いただいているお客様の多くが、当社の将来の製品計画を可視化したい、またアイデアや意見を提供することでAivenの製品チームとより密接に協力したいと望んでいることを耳にしました。このような背景から、この度、製品ロードマップを公開する[Aiven Ideas](https://ideas.aiven.io/)を立ち上げる運びとなりました。


![image](https://cdn.sanity.io/images/sczeoy4w/production/a7af92161144f4cf98fbe33bc917bec611e50d1b-1223x1209.png?q=80&fit=min&auto=format&dpr=1.5)


Aiven Ideasでは、Aivenの製品開発の方向性に影響を与えることができます。製品チームとの交流、既存機能へのフィードバック、新機能のアイデア投稿、他の人のアイデアへの投票ができるフォーラムです。アイデアのステータスが変更されると通知を受け取ることができるので、新機能への進化を確認することができます。私たちのチームは、あなたのアイデアやフィードバックを注視し、より詳細な情報が必要な場合は、あなたに連絡することがあります。


例えば、Aiven for Apache Flink®でカスタムコードを実行したい場合、[このアイデア](https://ideas.aiven.io/forums/951277-event-streaming/suggestions/46266534-allow-inspected-custom-code-jars-in-apache-flink)に移動して投票し、ユースケースに関する情報をコメントで提供し、この機能があなたにとっていかに重要かを述べてください。


![image](https://cdn.sanity.io/images/sczeoy4w/production/16d5763cdca5b6e4da6ebfb474d287e75195a0c6-1410x812.png?q=80&fit=min&auto=format&dpr=1.5)


私たちの製品チームはあなたの意見を聞きたいと思っています。今すぐ[Aiven Ideas](https://ideas.aiven.io/)に登録して、フィードバックや新しいアイデアをお寄せください。皆様からのご意見をお待ちしております！



[Aiven Ideas](https://ideas.aiven.io/)は、Aivenの信頼できるオープンソースデータプラットフォームを改善するためのアイデアを共有するためのものです。製品チームの近況については、要約 [ブログ記事](https://aiven.io/blog/what's-new-at-aiven-q22023) をご覧いただくか、最近の発表の [ウェビナー](https://aiven.io/webinar/whats-new-with-aiven-q2q3-2023) にご参加ください。当社がサービスとして提供するオープンソース技術に関する一般的な議論やアドバイスについては、[Aivenコミュニティフォーラム](https://aiven.io/community/forum/)をご利用ください。弊社製品で問題が発生し、バグを報告したい場合は、[Aiven Console](https://console.aiven.io/)で直接サポートチケットを提出してください。
せんせー、バーチャルパワープラントってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/7f59d21b-0564-377b-a326-47169950dc66.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/319ddbbb-e9dd-5833-688d-5808a705af9b.png)

せんせー、バーチャルパワープラントってなに？

# バーチャルパワープラントとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/754ad1db-cf66-be94-8f33-137d3e28f1cc.png)

バーチャルパワープラントというのは、電気を作る工場をたくさんつなげて、
ひとつの大きな工場のようにする考え方です。

君がお友達と一緒に手をつないで、大きな輪を作ること、想像してみてください。
一人で遊ぶのも楽しいけど、みんなで手をつないで遊ぶと、もっと楽しいし、もっと大きなことができますよね。

バーチャルパワープラントも、それと同じようなことをします。
たくさんの小さな電気を作る工場が、手をつないで協力することで、ひとつの大きな工場のように働きます。

それぞれの工場は太陽の光や風など、自然の力で電気を作ることがあるから、とても環境に優しいんです。
そして、これらの小さな工場が一緒になって、大きな力になることで、
たくさんの人々に必要な電気を提供することができるんです

だから、バーチャルパワープラントは、みんなで力を合わせて、地球にやさしい電気を作る特別な方法なんです。

# まとめ

バーチャルパワープラントというのは、電気を作る工場をたくさんつなげて、
ひとつの大きな工場のようにする考え方
【初心者のためのGitコマンド集】


Gitはバージョン管理システムであり、ソフトウェア開発において非常に重要なツールです。
以下は初心者向けの基本的なGitコマンド集です。

# コマンド

### 1. リポジトリの初期化
   ```bash
   git init
   ```

### 2. ステージング（変更をインデックスに追加）
   ```bash
   git add <ファイル名>      # 特定のファイルをステージング
   git add .                 # 全ての変更をステージング
   ```

### 3. コミット（変更をリポジトリに保存）
   ```bash
   git commit -m "コミットメッセージ"
   ```

### 4. プッシュ（ローカルリポジトリの変更をリモートリポジトリに反映）
   ```bash
   git push <リモート名> <ブランチ名>
   ```

### 5. 新しいブランチの作成と切り替え
   ```bash
   git checkout -b <新しいブランチ名>
   ```

### 6. リモートブランチの移動
   ```bash
   git checkout <リモートブランチ名>
   ```

### 7. リモートリポジトリのクローン
   ```bash
   git clone <リモートリポジトリURL>
   ```

### 8. リモートリポジトリから最新の情報を取得（フェッチ）
   ```bash
   git fetch
   ```

### 9. 一時的な変更を保存（スタッシュ）
   ```bash
   git stash            # 現在の変更を一時的に退避
   git stash pop        # スタッシュから変更を復元
   ```

# 【便利なGitテクニック】

### 1. 履歴を見る
   ```bash
   git log             # コミット履歴を表示
   git log --oneline   # 一行でコミット履歴を表示
   ```

### 2. ブランチを比較する
   ```bash
   git diff <ブランチ名1>..<ブランチ名2>   # 2つのブランチの差分を表示
   ```

### 3. 変更を元に戻す
   ```bash
   git reset HEAD <ファイル名>  # ステージングを取り消し
   git checkout -- <ファイル名> # ファイルの変更を取り消し
   ```

### 4. プルリクエスト（Pull Request）の作成
   GitHubなどのプラットフォームでは、コ

ード変更を他の人に取り込んでもらうためのプルリクエスト機能があります。

### 5. ブランチの削除
   ```bash
   git branch -d <ブランチ名>    # ローカルブランチの削除
   git push <リモート名> --delete <ブランチ名>   # リモートブランチの削除
   ```

### 6. コミット履歴の修正
   ```bash
   git commit --amend       # 直前のコミットを修正
   git rebase -i HEAD~n     # 直近のnコミットを対話的に修正
   ```

### 7. リベース（履歴の整理）
   ```bash
   git rebase <ベースブランチ>   # カレントブランチをベースブランチの先に移動
   ```

### 8. コンフリクトの解消
   コンフリクトが発生した場合は、手動でコンフリクトを解消し、再度ステージングしてコミットする必要があります。

### 9. リモートリポジトリの情報を表示
   ```bash
   git remote -v   # リモートリポジトリのURLを表示
   git remote show <リモート名>   # 特定のリモートリポジトリの詳細情報を表示
   ```

### 10. マージ
```bash
    git merge <ブランチ名>    # 指定したブランチを現在のブランチにマージ
```

### 11. リモートの最新情報を取得してマージ（プル）
```bash
    git pull <リモート名> <ブランチ名>
```

### 12. インタラクティブなスタッシュ
```bash
    git stash save "一時退避メッセージ"    # スタッシュにメッセージを付けて保存
    git stash list                        # スタッシュのリストを表示
    git stash apply <スタッシュID>        # 特定のスタッシュを適用
```

### 13. 空のプッシュ（進捗トラッキング）

進捗をリモートリポジトリに反映するため、空のコミットを作成してプッシュします。

```bash
    git commit --allow-empty -m "進捗トラッキングのための空コミット"
    git push <リモート名> <ブランチ名>
```




これにより、進捗をリモートリポジトリに反映させるための空のコミットを作成し、プッシュすることができます。この空のプッシュを活用することで、プロジェクトの進捗を透明化し、チーム内での協力を円滑に行うことができます。
【SwiftUI】iOS16から使えるfontWidthってなに？

# はじめに
`fontWeight`は結構使いますが、`fontWidth`は全然使いません。
使わないのでどんな機能なのかわからなかったのでちょびっと調べてみました。

https://developer.apple.com/documentation/swiftui/view/fontwidth(_:)

# 実装
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(spacing: 10) {
            Text("fontWidth")
                .fontWidth(.compressed)
            
            Text("fontWidth")
                .fontWidth(.condensed)
            
            Text("fontWidth")
                .fontWidth(.expanded)
            
            Text("fontWidth")
                .fontWidth(.standard)
        }
    }
}
```

# こうなる
![Simulator Screenshot - iPhone 14 Pro - 2023-08-05 at 21.56.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/c40051b4-8db1-ac84-fc1d-9bf67c4d1f5c.png)

# 全角だとどうなるか
変わらない
![simulator_screenshot_55A0C334-B158-44DA-88BA-9B2ADE2EE2AD.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/872db9ed-4ccd-7e45-22b0-708cbafb3b01.png)

# おわり
全角だと変わらないのには注意が必要そうですね
Rails7のActiveStorageでファイルのURL（key）を変更する方法

[株式会社TECH LUCK](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)という会社で代表兼エンジニアをしている齊藤です。

DXプロジェクト、開発プロジェクト、Rails開発などでお困りごとがありましたら[弊社HP](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)からご相談をいただけますと幸いです。
以下のような問題に対応することが可能です。
- プロジェクトでRailsエンジニアが足りなくて困っている
- Railsのバージョンアップをしたいがノウハウ・リソースが足りなくて困っている
- オフショア開発をしているが、要件の齟齬やコード品質が悪いので改善したい

また、Railsエンジニアも募集しておりますので、興味がありましたら[弊社HP](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)からご連絡いただけますと幸いです。

# 前提

ActiveStorage経由でアップロードしたファイルを表示する際に、そのファイルのURLはランダムに生成されます。
そのURLを変更したい時があり、その方法がなかなか見つからなかったのでメモとして残しておきます。

2種類のやり方が見つかったので、状況に応じて使い分けていただくといいかと思います。

開発環境は以下の通りです。
Ruby:v3.2.0
Ruby on Rails:v7.0.5

# ActiveStorageを利用する各モデルでメソッドを定義する方法

```ruby:app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  primary_abstract_class

  # すべてのモデルに継承される。
  # create_blobメソッドを利用するモデルの中でオーバーライドをしないとエラーになる。
  def attachable_storage_path
    raise NotImplementedError
  end

  # すべてのモデルに継承される。
  # ActiveStorageを利用するモデルの中で、create_blobメソッドを利用してアタッチする。
  def create_blob(attachable)
    return if attachable.nil?

    ActiveStorage::Blob.new.tap do |blob|
      blob.filename = attachable.original_filename
      blob.key = attachable_storage_path
      blob.upload(attachable)
      blob.save!
    end
  end
end
```

```ruby:app/models/application_record.rb
class Content < ApplicationRecord
  has_one_attached :image

  # ActiveStorageのkeyを変更する際には、このメソッドを利用する。
  def image_attach(attachable)
    return false unless self.persisted?
    image.attach(create_blob(attachable))
  end

  # ApplicationRecordにあるメソッドをオーバーライド。
  def attachable_storage_path
    "<key生成の処理>" #ここにkeyの生成を指定する。他のActiveStorageのレコードのkeyと被らないように生成しないとエラーになる。
  end
end

```



# Railsアプリケーション生成時に変更する方法
ActiveStorageでは、アップロードしたファイルのURLは`active_storage_blobs`の`key`という項目で管理しています。

ActiveStorageの中身のソースコードを見ていくと、`key`の生成のソースコードは以下のようになっていました。

ActiveStorageのGitHubの[ソースコード](https://github.com/rails/rails/blob/27b12e9249572d267e9ebf9f64b5bb2c21070f0d/activestorage/app/models/active_storage/blob.rb#L169-L172)

上記を抜粋したものは以下のようになっています。

```ruby:rails/activestorage/app/models/active_storage
class ActiveStorage::Blob < ActiveStorage::Record
  # ...省略...

  def key
    # We can't wait until the record is first saved to have a key for it
    self[:key] ||= self.class.generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH)
  end

  # ...省略...
end
```

　
上記のように作成されている`key`の生成をオーバーライドして、こちら側で利用したい`key`の形で生成することができます。
今回はファイル名にしたかったので、以下のようにしました。

```ruby:config/application.rb
module App
  class Application < Rails::Application
    
    # 以下を追加
    Rails.application.config.to_prepare do
      class ActiveStorage::Blob
        def key
          self[:key] ||= "<key生成の処理>" #ここにkeyの生成を指定する。他のActiveStorageのレコードのkeyと被らないように生成しないとエラーになる。
        end
      end
    end
  end
end
```

以上です。
コンテナで起動したDrupalのバックアップを試してみて

 Docker Hubの使い方を　(https://hub.docker.com/_/drupal/) 見てバックアップもしなくちゃなと思って Backup and restoreのモジュールを入れたのだが以下のようなメッセージが
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/28dcb59a-3067-9780-9522-2309f8cb228a.png)

以下のやり方でバックアップを作成しました。（DrupalのコンテナにPhpの拡張を入れるんでもよかったのかもですが）なお、今回はRancher desktopを使ってやってみてます。
-Drupalのバックアップ
　docker commitでコンテナをイメージで保存
-Mysqlのバックアップ
　Mysql dumpでデータベースのダンプを作成

では早速以下のようにやってみました。
-Drupalの起動
こちらのページを参考に以下のコマンドで
https://hub.docker.com/_/drupal/

```Drupalのデプロイ
docker network create --subnet 172.21.0.0/16 --attachable some-network
docker run -d --name some-mysql --network some-network -e MYSQL_DATABASE=drupal -e MYSQL_USER=user -e MYSQL_PASSWORD=password -e MYSQL_ROOT_PASSWORD=password mysql
docker run --name some-drupal --net some-network -p 8080:80 -d drupal
```
これでDrupal が立ち上がりセットアップが始まります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/d2c3893c-65d9-751e-5f81-d033d58183fd.png)

上記の環境変数で設定したDB設定をもとにDrupalサイトの設定を進めます。設定が終わると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/35d9adc1-104c-0799-b981-4971310d117e.png)
Drupalの画面になります。

とりあえず適当に基本ページでコンテンツを作ってみます。
メニューにリンクもつけてページも/aboutとしてfrontページに設定します。こちらがfrontページ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/51df934b-ec52-d4b1-ddf3-f48c83777561.png)

-バックアップの作成
　まずはDrupalのバックアップを
コマンドラインでまずはコンテナの動作を止めます。
```Drupalの停止
 docker stop some-drupal
```
続いてコンテナのイメージを作成します。ついでにイメージをファイルで保存
```イメージ作成
 docker commit some-drupal some-drupal:v1
 docker export some-drupal > some-drupal.tar
```
（確認はpodman imagesで、ファイルに出力は思った以上に時間がかかりました、感覚ですが10分以上）
次にmysqlのバックアップ。mysqlのコンテナに入って
```
 docker exec -it some-mysql bash
```
Mysqlのダンプをとります。
```
 mysqldump -uroot -p'password' drupal > mysqldump-v1
```
コンテナから抜けてダンプをPCに保存します。
```
docker cp some-mysql:/mysqldump-v1 .
```
（確認はlsコマンドで）

次にレストアをしてみます。
一度現状のコンテナを削除してみます。
```
docker stop some-mysql
docker rm some-drupal some-mysql
```
まずはmysqlとDrupal（先ほど保存したイメージから）起動します。
```Drupalのデプロイ
docker run -d --name some-mysql --network some-network -e MYSQL_DATABASE=drupal -e MYSQL_USER=user -e MYSQL_PASSWORD=password -e MYSQL_ROOT_PASSWORD=password mysql
docker run --name some-drupal --net some-network -p 8080:80 -d some-drupal:v1
```
mysqlのデータを戻します。
```
docker cp mysqldump-v1 some-mysql:/
docker exec -it some-mysql bash
```
コンテナにはいってダンプデータを戻します。
```
mysql -u root -p 'password' drupal < mysqldump-v1
exit
```
execでコンテナからから抜けてブラウザでサイトをみるともとに戻ってますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/7b7cb86e-95c9-2ce6-761a-30c59c4bd412.png)
CakePHP4のページネーションで「Argument #1 ($format) must be of type string, array given, called in」

## エラー内容
Cakeのページネーションで件数を表示しようとしたらエラーで動かない！
エラーメッセージには以下が表示されていました。
~~~
Cake\View\Helper\PaginatorHelper::counter(): Argument #1 ($format) must be of type string, array given, called in 
~~~

must be of type string, array given, called in 
引数の型が違う？でもドキュメント通りのはず。

## CakePHPのドキュメント

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592669/46086659-bdfe-73aa-658d-20b095ce87a5.png)
https://book.cakephp.org/4/ja/views/helpers/paginator.html

## 解決

~~~
<div class="list_num"><?php echo $this->Paginator->counter(['format' => "<span>{{count}}</span>件"]) ?></div>
~~~

を以下に書き換えて解決しました。
~~~
<div class="list_num"><?php echo $this->Paginator->counter("<span>{{count}}</span>件"); ?></div>
~~~

ドキュメントでは配列で渡してるのに、Stringで渡さないといけないのなぁぜなぁぜ？


## 仕様が変わってる。
/vendor/cakephp/cakephp/src/View/HElper/PaginatorHelper.php
のcounterが微妙に変わってました。
多分「counter('range')」とかで簡単に数字だけを呼び出せるようにって変更だとは思いますが、3からの移植を考えるとそのままでもよかったような気もします。optionが第二引数として残ってるのは移植用かな？。ページ関連とその他のオプションを明確に分けるのももしかしたらあるかもしれません。

CakePHP4
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592669/34158366-023b-0fa6-d542-3f5078ed80b2.png)


CakePHP3
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592669/0a2e1972-88bb-d276-9176-cdd915bab21a.png)
TypeScript jestで単体テストを書く

### はじめに
最近、TypeScriptに入門しました。
jestについて個人的な備忘録として記事を執筆しました。

### この記事でまとめたこと
TypeScriptでjestを使ったテストの実行方法
jestの各種設定

### jestとは？
javascriptのテストを実施するためのフレームワーク。
この記事ではTypescriptのjestの記事となっていますが、ReactやVueのテストなどもjestで行えます。

### jestの設定方法

#### 1.node.jsのインストール
まずはNode.jsのインストールを行う
https://nodejs.org/ja
上がnode.jsの公式サイト。
こちらからダウンロードを行う。

#### 2.PJの新規作成

Node.jsをインストールした後は
指定のフォルダで
```
npm init
```
プロジェクトの新規作成

```
npm install typescript
```
TypeScriptをインストール
※npm install時に -g オプションを付けると、グローバルでインストールされる。
ただ、各PJでバージョンを分けたい場合は-gオプションを付けずにインストールを行う。


#### 3.jest関係のパッケージのインストール
```
npm install jest

npm install ts-jest

npm install @types/jest

```
ts-jestを入れることでTypeScriptを一々、コンパイルせずにテストが行えるようになる。
@types/jestはテストコードの型チェックを行いたい場合に必要になるのでインストール。

#### 4.typescriptでテスト時の設定ファイル作成
```
npx ts-jest config:init
```
上のコマンドを実行すると、jest.config.jsが生成される。
この設定ファイルを以下に変更。
```jest.config.js
module.exports = {
  preset: 'ts-jest',
  testEnviroment: 'node'
}
```
TypeScriptのコードをテストしたい場合はpresetの値をts-jestにする必要がある

また、テストから除外したい場合は
```jest.config.js
testPathIgnorePatterns: ["指定したディレクトリ"]
```
デフォルトではnode_modulesフォルダが除外されている。

https://jestjs.io/ja/docs/configuration#testpathignorepatterns-arraystring

#### 5.テストの実行

test.tsがファイル名に含まれているものがテストコードのファイルになる。
例として挙げるなら、sample.test.tsのような感じ。
テスト対象となるソースコードはexportし、テストコードのファイルでimportする必要がある。

```package.json
"scripts": {
  "test": "jest"
}
```
package.jsonに上の記述を追加すると
npm run testでjestの実行が行えるようになる


#### 6.mockの設定

jest.fnで関数をmock化できる
```sample.test.ts
(global as any).fetch = jest.fn(() =>
  Promise.resolve({
    'json' () => Promise.resolve({"hoge": "hogehoge"})
  })
);
```
これはfetchをmock化した例。

https://jestjs.io/ja/docs/mock-functions#%E3%83%A2%E3%83%83%E3%82%AF%E9%96%A2%E6%95%B0%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B
詳しくは公式ドキュメントを参照。


#### 7.DOMのテスト
```
npm install jest-environment-jsdom
```
外部のHTMLファイルを読み込みたい場合はNode.jsのfsモジュールをrequireする。

```jest.config.js
module.exports = {
  preset: 'ts-jest',
  testEnviroment: 'jsdom'
}
```


#### 8.coverageを出力するためのパッケージのインストール

カバレッジを出力する場合は
テスト実行時に --coverageオプションを付けるだけ
```
jest --coverage
```


### 参考にさせていただいた記事

https://jestjs.io/ja/docs/getting-started
https://typescriptbook.jp/tutorials/jest