OmniAICreator/Qiita-1.07M huggingface dataset:
All-in-One WP Migrationでインポートするときの最大アップロードファイルサイズをロリポップであげる方法

久々にやろうとしたら忘れてて無駄に時間くったので今度こそメモ✍️

# ① php.iniの設定を変更

:::note info
この設定が「 On 」の場合 .htaccess の設定内容が優先されます
:::

ロリポップ管理画面→「サーバーの管理・設定」→「PHP設定」より
「<INS>php_value, php_flagを利用可能にする</INS>」を「 On 」に。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2824889/165a9a06-02ea-4b2c-0eb2-5b86a126c67f.png">

# ② .htaccessに追記

:::note warn
初期設定だと最大アップロードファイルサイズ「8M」だった
::: 

ロリポップFTPの「.htaccess」に下記を追記
```
php_value upload_max_filesize 128M
php_value post_max_size 128M
php_value memory_limit 256M
php_value max_execution_time 300
php_value max_input_time 300
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2824889/6526d7be-73a2-4631-a1cd-8951f51ff397.png">

# ③ 8MB → 128MBにあっぷ成功！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2824889/eb82c4e9-375c-2926-e14d-65d396d65efc.png">

# 🗒 参考記事
右往左往して最終的に下記記事を参考にしました。
ありがとうございました 🙇‍♀️

https://xn--t8j4aa4n0j5byg4ih4e4eb.net/others/all-in-one-wp-migration-max-filesize/

# 🗒 追記
2023年2月現在、ロリポップではPHPのバージョンが下記4つから選べるようになっています。
- 7.4 （CGI版）
- 8.0 （CGI版）
- 8.1 （CGI版）
- 8.1 （モジュール版）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2824889/555e9ea1-2435-e9e6-f6b8-b80596288b19.png">

:::note alert
「PHP設定」ページ上部には下記のような注意書きがごにょごにょ書かれております。
:::

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2824889/8ac97eb7-6c78-49dc-1120-5b7365c7bb79.png">

### 文字起こし版（抜粋）
> PHPバージョンの変更によりサイト表示やプログラム利用に影響が出る可能性があります。
> **下記注意事項を必ずご確認の上**、PHPバージョンの変更を行ってください。

- LiteSpeed版、モジュール版のPHPではphp.iniの設定変更はできません。
- LiteSpeedを使用するプランでは、wwwなしドメインのPHPバージョンと同じものがwwwサブドメインにも適用されます。
- 現在PHP7.1以下のPHPバージョンをご利用の場合、バージョンを変更すると、元のバージョンへ戻すことはできません。
- 古いバージョンのPHPは提供を終了することがございますので、最新バージョンのご利用を推奨しています。

### ... LiteSpeed版、モジュール版のPHPではphp.iniの設定変更ができない:sob:

ロリポップのPHPの仕様は以下の表の通りです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2824889/8e47a2f5-cd5f-53eb-e825-eb9dfb29fa9e.png">

モジュール版の管理画面はこんな感じで、php.iniの設定変更ができない...
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2824889/f3e8bcf7-70f5-c824-1b6b-489b826c8bc9.png">

当方は「ライトプラン」を契約しており、仕方ないので今回は一瞬だけいちかばちか「CGI版」に戻して作業しました。が、今後プランを変更したり、いずれCGI版が終了したらこの方法使えなくなるかもといった懸念があります。。。

もっと良い解決法をご存知の方いましたら教えてください:thinking:
wslでledger その7

# 概要
wsl(wsl2じゃない)でledgerやってみた。
練習問題、やってみた。

# 練習問題
農業の勘定科目を設定せよ。

# 農業の勘定科目

Income:売上高
Income:作業受託料
Income:家事消費仕向高
Income:期首農産物棚卸高
Income:期末農産物棚卸高
Income:営業外収益
Income:生産調整助成金等
Income:受取共済金
Income:固定資産処分益
Income:貸倒引当金戻入
Income:雑収入

Expenses:生産原価
Expenses:期首仕掛品棚卸高
Expenses:種苗費
Expenses:肥料費
Expenses:農薬費
Expenses:燃料費
Expenses:水道光熱費
Expenses:諸材料費
Expenses:小農具費
Expenses:修繕費
Expenses:賃借料
Expenses:支払地代
Expenses:作業委託料
Expenses:作業用衣料費
Expenses:土地改良水利費
Expenses:減価償却費
Expenses:専従者給与
Expenses:雇用労賃
Expenses:期末材料棚卸高
Expenses:期末仕掛品棚卸高
Expenses:雑費
Expenses:貸倒償却
Expenses:販売・一般管理費
Expenses:研修・交際費
Expenses:一般管理費
Expenses:租税公課
Expenses:保険・共済掛金
Expenses:営業外費用
Expenses:固定資産処分損
Expenses:雑損失

Assets:現金
Assets:預金
Assets:売掛金
Assets:未収金
Assets:貸倒引当金
Assets:前渡金
Assets:立替金
Assets:立毛作物
Assets:生産物
Assets:肥料
Assets:農薬
Assets:諸材料
Assets:燃料
Assets:建物施設
Assets:機械器具
Assets:外部出資金


Liabilities:買掛金
Liabilities:短期借入金
Liabilities:未払金
Liabilities:預り金
Liabilities:固定負債
Liabilities:農林漁業金融公庫資金
Liabilities:改良資金
Liabilities:その他長期借入金

Equity:資本金






以上。
②ストロングパラメーターについて

本日はストロングパラメーターについて投稿します。

○ストロングパラメーターとは
---

Ruby on rilsのアプリケーションにおいて不正なデータを取得しないように指定する
アプリ内の警備員みたいなもの。（例えが間違っていたらすいません。。）:sweat_smile:

ストロングパラメーターを使う為には２つのメソッドを使用します。


①require（リクワイア）メソッド
---

送信されたパラメーターの情報を持つparamsが使用出来るメソッドの事。
パラメーターからどの情報を取得するか選択する事が出来る。
使い方
`````
paras.require（:モデル名）
`````


さらに指定したパラーメーターをより限定した時に使うのがpermitメソッドです。



②parmitメソッド
---

requieメソッドと同じでparamsが使用出来るメソッド。
取得したいキーを指定出来て、その中の値のセットのみ取得出来る。
使い方
`````
params.require（:モデル名）.parmit（キー名）
`````

まだ僕自身ざっくりな理解ですが日々アウトプットをしながら学んでいきます。
ありがとうございました！！
if文を使わずにFizzBuzzしてみた

次のお二人の記事
- [剰余演算子を使わずにFizzBuzzを解く](https://qiita.com/nkfrom_asu/items/783c6be996abe6cc2a67)
- [Python: 剰余演算子を使わないでFizzBuzzしてみた](https://qiita.com/ttatsf/items/2c500ff077118ff8698b)

を読んで、`if`文を使わずに`FizzBuzz`を解こうとして、剰余演算子`%`も使わずに、次のようなコードを書いたことを思い出しました。

```python
def fizzbuzz(n):
    def set_fizzbuzz(d, s):
        for i in range(0, n, d):
            fb[i] = s

    n += 1
    fb = [i for i in range(n)]
    set_fizzbuzz(3, "Fizz")
    set_fizzbuzz(5, "Buzz")
    set_fizzbuzz(15, "FizzBuzz")
    return fb[1:]


print(*fizzbuzz(100), sep="\n")

```

　今、計算量なんか気にせずに`if`を使わないことだけを考えて書くのが“マイブーム”になっているんです。

# 追記(2023/7/7)
その後、こんなのもできました。
```python
for i in range(100):
    print("Fizz"*(i%3==2) + "Buzz"*(i%5==4) or i+1)
```
REST API の Azure RBAC を Azure CLI で試してみた

Azure サブスクリプションのアクセス制御 (IAM) でユーザーやサービスプリンシパルにロールを割り当てます。これをアプリから実行する必要がありそうなので、事前検証として REST API の Azure RBAC を Azure CLI で試してみました。

## セキュリティ管理者ロールをユーザーに割り当てる

```bash:bash
SubscriptionId=$(az account show \
  --query id \
  --output tsv)

echo $SubscriptionId

RoleId=$(az rest \
  --method get \
  --url https://management.azure.com/subscriptions/$SubscriptionId/providers/Microsoft.Authorization/roleDefinitions?api-version=2022-04-01 \
  --query "value[?properties.roleName=='Security Admin'].id" \
  --output tsv)

echo $RoleId

MyUpn=$(az account show \
  --query user.name \
  --output tsv)

echo $MyUpn

MyId=$(az ad user show \
  --id $MyUpn \
  --query id \
  --output tsv)

echo $MyId

az rest \
  --method put \
  --url https://management.azure.com/subscriptions/$SubscriptionId/providers/Microsoft.Authorization/roleAssignments/$(uuidgen)?api-version=2022-04-01 \
  --body '{
    "properties": {
      "roleDefinitionId": "'$RoleId'",
      "principalId": "'$MyId'",
      "principalType": "User"
    }
  }'
```

## 閲覧者ロールをサービスプリンシパルに割り当てる

```bash:bash
ReaderRoleId=$(az rest \
  --method get \
  --url https://management.azure.com/subscriptions/$SubscriptionId/providers/Microsoft.Authorization/roleDefinitions?api-version=2022-04-01 \
  --query "value[?properties.roleName=='Reader'].id" \
  --output tsv)

echo $ReaderRoleId

ServicePrincipalId=$(az ad sp list \
  --display-name sampleapp \
  --query [].id \
  --output tsv)

echo $ServicePrincipalId

az rest \
  --method put \
  --url https://management.azure.com/subscriptions/$SubscriptionId/providers/Microsoft.Authorization/roleAssignments/$(uuidgen)?api-version=2022-04-01 \
  --body '{
    "properties": {
      "roleDefinitionId": "'$ReaderRoleId'",
      "principalId": "'$ServicePrincipalId'",
      "principalType": "ServicePrincipal"
    }
  }'
```

## 参考

https://learn.microsoft.com/en-us/azure/role-based-access-control/role-assignments-rest
還暦爺がAtCoderにPascalで挑戦②　DP１問解きました。

おさらい
---------------------------
先輩Coderの方の記事を見るとやはり過去問を順次解いていくのが王道の様です。
しかしながらじっくり勉強するのが子供の頃から苦手な私、
なかなかモチベーションが湧きません。
ということでコンテストで取り組んだけど解けなかった問題を時間をかけて
おさらいすることにしました。
コンテスト中はそれなりに真面目に考えているので初見の問題よりは
頭に残っている分考えやすい様に思います。
ちゃんと理解しないで形だけ覚えても応用が利かないので腑に落ちるまで
考えてみます。
今回は

https://atcoder.jp/contests/abc286/tasks/abc286_d

に取り組んでみました。コンテスト中は全ケースの組み合わせじゃTLE確実だし
と悩んだ結果脱落。
解説を見るとこの問題はDP（動的計画法）で解けるとのこと。
DPとはなんじゃらほいとググっていくつかの記事を見てみました。
分かった様な分からないような…
最小範囲のケースを解決してそれを足場にどんどん範囲を拡げていく感じ？

この問題の場合はまず１種類の硬貨で払える金額のブーリアン配列を作っていって
その配列の結果に次の種類の硬貨で払える金額を加えていく感じです。
最終的に dp[n][x] の値がtrueになっていれば払えることになります。

```Pascal
var n,x,i,j,v,k : integer;
    a,b : array of integer;
    dp : array[0..50,0..10000] of boolean;

begin
  read(n,x);
  setlength(a,n+1);  // 1オリジンで使うため+1しておく
  setlength(b,n+1);  // a[0],b[0]は使わない
  for i := 0 to 50 do
    for j := 0 to 10000 do
      dp[i][j] := false;
  dp[0][0] := true;
  for i := 1 to n do
    read(a[i],b[i]);
// 硬貨の種類分繰り返し
  for i := 1 to n do
  begin
    // 硬貨の枚数分繰り返し
    for j := 0 to b[i] do
    begin
      v := a[i]*j;  // その枚数での金額
      dp[i][v] := true; 
      // １つ前の結果に足していく
      for k := 0 to x-v do
        if dp[i-1][k] then 
          dp[i][k+v] := true;
    end;
  end;
  // 最終結果判定
  if dp[n][x] then
    writeln('Yes')
  else
    writeln('No');
 
end.
```

無事ACとなりました。
次回同類の問題が出た時にうまく応用できるかは自信ないけど。
とりあえずは めでたしめでたし。
コードレビュー時に使ったことがあるドキュメント集


個人的に忘れるのでストックする目的ですが色々参考になると思うので、記事化します。

※適宜更新
※2022年10月〜2022年12月にかけてPR（MR）をReviewするときに使用したもの（または指摘を受けて参照したもの）

随時加筆修正はするつもり。


https://qiita.com/shoheiyokoyama/items/d752834a6a2e208b90ca

https://qiita.com/rkonno/items/1b30daf83854fecbb814

https://www.techscore.com/tech/DesignPattern/Facade#:~:text=Facade%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%AF%E3%80%81%E6%97%A2%E5%AD%98%E3%81%AE,%E3%81%AE%E6%AD%A3%E9%9D%A2%E3%80%8D%E3%81%A8%E3%81%84%E3%81%86%E6%84%8F%E5%91%B3%E3%81%A7%E3%81%99%E3%80%82

https://debimate.jp/2021/01/07/%E3%80%90%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%80%91%E5%85%A823%E7%A8%AE%E9%A1%9E%E3%81%AEgof%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC/

https://qiita.com/genzouw/items/35022fa96c120e67c637#flgkbn%E3%81%AA%E3%81%A9%E3%81%AE%E7%95%A5%E5%90%8D%E3%81%AF%E5%88%A9%E7%94%A8%E3%81%97%E3%81%AA%E3%81%84

http://java6.blog117.fc2.com/blog-entry-39.html

https://qiita.com/flyaway/items/90c931b21dc5dc310d9e

https://qiita.com/RyoheiHashimoto/items/38ec132bd2852238295e

https://qiita.com/AKB428/items/20e81ccc8d9998b5535d

https://qiita.com/Takmiy/items/a0f65c58b407dbc0ca99

https://qiita.com/takahirocook/items/470b2858de1a4f99b334

https://qiita.com/chimayu/items/58e3481305e91d188be3

https://qiita.com/kazTera/items/ab5dd9fb5b2579b25c4d

https://qiita.com/soepy/items/0c65f5a9b2ca586832a6

https://www.itsenka.com/contents/development/uml/class.html

https://zenn.dev/ctrlkeykoyubi/articles/try-with-resources-with-preparedstatement

https://confrage.jp/java%E3%81%AEtry-with-resources%E6%96%87/

https://qiita.com/tadashiro_ninomiya/items/19c774898c68add6185e
RaspiのSoftether VPN Server のアップデート記録

Softether VPN Serverはこれまで新規インストールやリセットしかしたことがなく、
アップデートしたことはなかったので挑戦。

基本的にはこのサイトに従う。

https://rin-ka.net/softether-vpn-update/

# 環境
* RaspberryPi 3B+
    * Softether VPN Server
* Windows 11 (RaspiにSSH接続する)

# バージョン確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125845/c96ed3ab-d6e3-f619-d320-5cbbaccef654.png)

# Softehterのダウンロード
Windows上で公式サイト
https://www.softether-download.com/en.aspx?product=softether
から以下の設定でダウンロードする。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125845/d8836001-f9f8-0de5-7089-9f9fd0022145.png)

# RaspiでSoftetherのバックアップ
Server状態の確認と停止

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125845/def8a685-daba-8848-cddd-b8ab8c415831.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125845/7472bd19-a490-8d93-6e04-f494b7e9d5e8.png)

/usr/local/vpnserver を名称変更
バックアップする時は名称を戻すだけでよいらしい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125845/dd864244-0ac8-30c0-a3c4-89c487364e0e.png)

# Raspiに新バージョンをインストール
scpでRaspiに.tar.gzファイルをコピー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125845/e81fc2fa-d065-7d5e-980c-d8f41cdfc87b.png)

.tar.gzファイルをコンパイル用に適当に用意した場所(softehter_for_compie)に移動したあと、解凍
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125845/e76602b6-31b3-7ece-542a-c553976155bc.png)

参考サイトでは「使用許諾の許可が聞かれなかった」と書いてあり、自分も聞かれませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125845/931ca5ac-81c8-b1a6-0696-54d84e746343.png)

/usr/local に出来上がったvpnserverディレクトリを移動させ、パーミッションを付与。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125845/6e34c79b-429d-c8e5-4192-05ca99be06d9.png)

バックアップフォルダから vpn_server.config を新フォルダにコピーし、サービスを起動。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125845/7b2990b4-ee9b-c680-4dab-c4c1446c7ef3.png)

無事更新されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125845/178931a4-33ce-5852-3b37-9bf15ffa9809.png)
AWS SAMのLambdaでS3へのPut権限をつける

AWS SAMでLambdaの構築が便利になったものの、`Hello World Example`で作成されるテンプレにはS3の権限がついていません。

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html

なので、S3にオブジェクトを読み書きさせたいときには、下のように`template.yaml`を編集して権限をつける必要があります。

```diff_yaml
Globals:
  Function:
    Timeout: 3
    MemorySize: 1000

+Parameters:
+  S3BucketName:
+    Type: String
+    Default: "アクセスしたいバケット名"

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      PackageType: Image
      Architectures:
        - x86_64
+      Policies:
+        - S3WritePolicy:
+            BucketName: !Ref S3BucketName
    Metadata:
      Dockerfile: Dockerfile
      DockerContext: ./hello_world
      DockerTag: python3.9-v1

```

あとはLambdaからboto3などでよしなにしましょう。

なお、今回は`S3WritePolicy`でしたが、もちろん他のポリシーも付けられます。

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-policy-templates.html
【備忘録】ロリポップでSSL化したあと「.htaccess」に追記することメモ

リダイレクトでURLをまとめるメモです✍️
- https://【ドメイン】
- http://【ドメイン】
- https://www.【ドメイン】
- http://www.【ドメイン】

```apache:.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
```
↓ これに
```apache:.htaccess
# www無しのURLに統一
RewriteCond %{HTTP_HOST} ^www\.hogemoge\.com
RewriteRule ^(.*) http://【ドメイン】/$1 [R=301,L]
# httpをhttpsに統一
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
```
↓ これを追記して
```apache:.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# www無しのURLに統一
RewriteCond %{HTTP_HOST} ^www\.hogemoge\.com
RewriteRule ^(.*) http://【ドメイン】/$1 [R=301,L]
# httpをhttpsに統一
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</IfModule>
```
こうなって完成！
# リダイレクトチェックツール

https://abashi.net/redirect-checker

https://ohotuku.jp/redirect_checker/
Ubuntu: apt update を行った時の警告を消す

sudo apt update を行った時の警告を消す方法です。
次のページを参考にしました。
[Fixing "Key is stored in legacy trusted.gpg keyring" Issue in Ubuntu](https://itsfoss.com/key-is-stored-in-legacy-trusted-gpg/)
Ubuntu 22.10 で確認しました。

## 警告のメッセージ

```text
$ sudo apt update
（省略）
W: http://jp.archive.ubuntu.com/ubuntu/dists/kinetic/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
W: http://security.ubuntu.com/ubuntu/dists/kinetic-security/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
W: http://jp.archive.ubuntu.com/ubuntu/dists/kinetic-updates/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
W: http://jp.archive.ubuntu.com/ubuntu/dists/kinetic-backports/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
```

キーをリスト

```text
$ sudo apt-key list
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
/etc/apt/trusted.gpg
--------------------
pub   rsa4096 2018-09-17 [SC]
      F6EC B376 2474 EDA9 D21B  7022 8719 20D1 991B C93C
uid           [ unknown] Ubuntu Archive Automatic Signing Key (2018) <ftpmaster@ubuntu.com>
```

>F6EC B376 2474 EDA9 D21B  7022 8719 20D1 991B C93C
>の最後の8桁をインポートに使います。
>991BC93C

キーのインポート

```text
sudo apt-key export 991BC93C | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/feb11.gpg
```

sudo apt update で警告が出ないことを確認
テストについて

## テストの目的
#### なぜテストを行うのか
・プログラムの正しい動作を確認するため。
・作成したプログラムの正しくない動作を発見するため。

## テストのやり方
### テストケースの設計
・プログラムが正しく動くか検証するための、前提条件・データ・操作・結果を抽出する。

#### ホワイトボックステスト
・モジュールの内部構造に着目するテスト。仕様を知らないとできないテスト。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/cd6dddd2-05b0-1c53-cb5a-9f24942d1182.png)

#### ブラックボックステスト
・モジュールの内部構造を見ないテスト。仕様を知らなくてもできるテスト。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/b9ca75b1-372b-475b-1356-29ee21d541c3.png)

## ユニットテスト(単体テスト)
・モジュール単位で行うテスト。設計書をもとにして、テストコード、ドライバ、スタブを作成する。
・個々の機能ユニット(関数)に対するテストで、最も粒度が細かい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/74363cfd-edf0-f810-9e3f-1dcc2b8fe4a2.png)


#### ユニットテストのメリット
・開発の早期にバグを発見でき、修正コストが下げることができる
・開発者がコードの内容を理解するのを助け、迅速に後の変更や拡張開発に役に立つ
・テストの実行速度が速い
などが挙げられます。

## ソフトウェア結合テスト
・作成したユニットを結合して行うテスト。
　→結合したユニットによる、インターフェースのエラー、結合したことで発生したエラーを検出する
### テスト技法
テスト技法については、主に4つあります。
・トップダウン
・ボトムアップ
・ビックバン
・サンドイッチ
今回は、よく使用される「トップダウン」と「ボトムアップ」について簡単に説明します。
○トップダウン
上位のモジュールから順にテストする技法。システムの全体像が見えやすいことがメリットとして挙げられます。
○ボトムアップ
下位のモジュールから順にテストする技法。テスト条件が見えやすいことがメリットです。

## バグ管理について
テストで大切になるバグ管理についてです。
バグ管理ではこちらの図を使用することが多いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/b152d97f-592c-73e5-7556-b4b291f1047f.png)
この図は、テスト項目の消化とともに、起こったバグの数を表にしたものです。
上の図が理想的な図の形で、テストをして発生したバグを回収していく中で、少しずつバグの回数が減っていき、システムの品質が高まっていくことが見て取れます。

以下の図のように、変曲線がオレンジのような形になるとダメな形です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/4da21b87-65e2-45dd-35f0-76927a6cfdaf.png)

## テストの自動化
自動化のメリットは以下の通りです。
・テスト工数の削減
・ヒューマンエラーの排除
が挙げられます。

## デバック手法
バグの回収の際に行う、良いアプローチとダメなアプローチは以下の通りです。

### 悪いアプローチ
・すぐにソースファイルを開く
・「原因ジャンプ」をしてしまう。
・やみくもにソースコードファイルを修正する。⇦これが特にダメ！

### 良いアプローチ
・問題の明確化
・仮説を立てる
・仮説に基づいて検証を行う。

## まとめ
テストには様々な方法がありますが、経験を積んで、システムの品質を上げられるようなテストをしていきたいなと思います。
【Railsアプリケーション】Heroku、AWS S3、Active Storageの設定

# はじめに

Railsなどを中心に勉強中のエンジニア初心者が他の記事を参考にしたり、実際に実装してみたりして、アウトプットの一環としてまとめたものです。
間違っていることもあると思われるので、その際は指摘いただけると幸いです。

# Heroku上でアプリケーションを稼働させる

Railsアプリケーションでアップロードした画像がAWS S3に保存されるように設定し、そのアプリケーションをHeroku上で本番稼働させる想定で記載する。

`Active Storage`の実行環境、AWSのアカウント情報、およびS3のバケット作成などは済んでいる前提で記載する。

# `storage.yml`の編集

設定ファイルにAWSのアカウント情報および、S3のバケット情報を記載する。

### ※AWSのアカウント情報やS3のバケット情報などについては、セキュリティ的な観点から環境変数に持たせて読み込むようにする。

### `config/storage.yml`

```yaml
# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
amazon:
  service: S3
  access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
  secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
  region: <%= ENV['AWS_REGION'] %>
  bucket: <%= ENV['AWS_S3_BUCKET'] %>
```

# Herokuへ環境変数を設定

アプリケーションを稼働させるHeroku環境へ環境変数を登録して、デプロイすればOK！

> Herokuへのデプロイ方法は別記事参照（https://qiita.com/sekkey_777/items/edc879476c101343c813）
> 

```bash
# access_key_id および secret_access_key の登録
$ heroku config:set AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=yyy

# region および bucket の登録
$ heroku config:set AWS_REGION=aaa AWS_S3_BUCKET=bbb
```

# 参考

https://railsguides.jp/active_storage_overview.html
ジェネレータの設定

# ジェネレータ設定について

> ソースコードの雛形を生成するジェネレータという機能があります。

> 自動的にコントローラやビューファイルを生成してくれるのですが、自動的に生成しない様に設定を行います。

``` config/application.rb
module TaskApp
  class Application < Rails::Application

    config.load_defaults 6.0

    config.generators do |g|
      g.skip_routes true        #routes.rbの変更されず
      g.helper false            #ヘルパーファイルの生成せず
      g.assets false            #css,JavaScriptファイル生成せず
      g.test_framework :rspec   #testファイル生成せず
      g.controller_specs false  #specs_controller生成せず
      g.view_specs false        #specs_view生成せず
    end
  end
end
```
Android Studioを複数起動した際に「Timeout waiting to lock journal cache」というエラーが出た時に…

# Timeout waiting to lock journal cache :joy:
セキュリティソフト（ESETなど）を入れている場合に、Gradle周りでビルドが終わらないなどの不都合が発生することがあります。

特に、Android Studioを複数起動した際に、下記のような「**Timeout waiting to lock journal cache**」というエラーが出てしまうのは開発効率的な意味でとても面倒な問題です。

```terminal
Gradle could not start your build.
> Cannot create service of type BuildSessionActionExecutor using method LauncherServices$ToolingBuildSessionScopeServices.createActionExecutor() as there is a problem with parameter #21 of type FileSystemWatchingInformation.
   > Cannot create service of type BuildLifecycleAwareVirtualFileSystem using method VirtualFileSystemServices$GradleUserHomeServices.createVirtualFileSystem() as there is a problem with parameter #7 of type GlobalCacheLocations.
      > Cannot create service of type GlobalCacheLocations using method GradleUserHomeScopeServices.createGlobalCacheLocations() as there is a problem with parameter #1 of type List<GlobalCache>.
         > Could not create service of type FileAccessTimeJournal using GradleUserHomeScopeServices.createFileAccessTimeJournal().
            > Timeout waiting to lock journal cache (/Users/xxxxx/.gradle/caches/journal-1). It is currently in use by another Gradle instance.
              Owner PID: 51888
              Our PID: 52417
              Owner Operation:
              Our operation:
              Lock file: /Users/xxxxx/.gradle/caches/journal-1/journal-1.lock
```

エラーの対応としては、プロセスをkillすることで一旦解消できはしますが、毎回行うのは少々面倒です。

```bash
$ kill -9 51888
```

# Gradle user home を設定する:bulb:
 **Gradle user home** がデフォルトだと `/Users/xxxxx/.gradle` として設定されているので、これを別に設定すれば回避できるようです。

デフォルト（ `/Users/xxxxx/.gradle` ）| 別指定（ `/Users/xxxxx/.gradle2`）
-----------|------------
![スクリーンショット_2023-02-11_午前5_36_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/9666d082-00d1-4bf3-051d-8d211783a40e.png)| ![スクリーンショット_2023-02-11_午前5_43_52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/87332f60-77a4-3035-9133-5f4ae53af267.png)

>Override the default location where Gradle stores downloaded files, e.g. to tune anti-virus software on Windows

と記載がありますが、Macでも言えそうですね。

## デメリット :slight_frown:
一応これで問題なく動いているようですが、**デメリット**としては
- Gradleのキャッシュなどがないため初回ビルドに時間がかかる
- 容量を食う

があげられるかなと思います。


# 関連リンク
https://github.com/gradle/gradle/issues/8750
Rails apiモードでプレーンな文字列を返す方法

Rails apiモードで、jsonではなく文字列（string）を返却したい時の方法について記載する。

あまり使わない方法だと思うが、
先日token(string)のみを返すエンドポイントを作成する必要があり、
方法がわからず困ったのでメモ的に残す。

# 返したい値
今回やりたいイメージ。returnを使うわけではないがイメージとしてわかりやすいので。
```ruby:string（ただの文字列）
return token
```

通常だとこういう形式になる。
```ruby:json（普通はこの形式で値を返す）
return { "token" : "token" }
```

# 方法
renderメソッドで `render plain: "文字列"` とする
```ruby:controller.rb
render plain:  'This is the string'
```

別の書き方として、`render :json => "文字列"` としてもいい。
（plainの方が文字列を返すことが伝わりやすいのでplainを使うことをオススメする。）
```ruby:controller.rb
render :json => 'This is the string'
```
Laravel サブドメインルーティング(Subdomain Route)が効かない

# 前提

Laravel 9.x
Laravel Sail
Laravel Jetstream設定済み

# やりたいこと

[Laravelのサブドメインルーティング](https://readouble.com/laravel/9.x/ja/routing.html?header=%25E3%2582%25B5%25E3%2583%2596%25E3%2583%2589%25E3%2583%25A1%25E3%2582%25A4%25E3%2583%25B3%25E3%2583%25AB%25E3%2583%25BC%25E3%2583%2586%25E3%2582%25A3%25E3%2583%25B3%25E3%2582%25B0)が効かない。

admin.example.comに管理者用、example.comで通常用。それぞれでJetstreamを利用したい。


```php:web.php
# 一番上に記載
Route::domain('admin.example.com')->group(function () {
    Route::get('/login', function () {
        dd('admin login page');
    });
});

```
このとき`admin.example.com/login`にアクセスしたときに、jetstreamのloginページが表示されてしまう。

# 原因

Readoubleにある通り、サブドメインなしのドメインルートを登録する前にサブドメインルートを登録しておく必要があるのですが、Jetstream(というかFortify)内のrouteでやっているため

> Note: ルーティングがサブドメインルートに到達できるようにするには、サブドメインなしのドメインルートを登録する前にサブドメインルートを登録しておく必要があります。これにより、サブドメインなしのドメインルートが同じURIパスを持つサブドメインルートを上書きするのを防げます。

# 直し方

それぞれルーティング無効化して、自身でインポートする



```bash
# fortifyのroute
# vendor/laravel/fortify/routes/routes.phpからコピーする
cp ./vendor/laravel/fortify/routes/routes.php ./routes/fortify.php
```


```php:FortifyServiceProvider.php

    public function register(): void
    {
        Fortify::ignoreRoutes(); # 追加
    }

```


```bash
# jetstreamのroute
php artisan vendor:publish --tag=jetstream-routes
```

```php:JetstreamServiceProvider.php

    public function register(): void
    {
        Jetstream::ignoreRoutes(); # 追加
    }

```


既存のrouteにインポート

```web.php
<?php

Route::domain('admin.example.com')->group(function () {
    Route::get('/login', function () {
        dd('admin login page');
    });
});

# ~ 省略 ~

require __DIR__.'/fortify.php';
require __DIR__.'/jetstream.php';

```

これでサブドメインが機能するようになりました。
【ServiceNow】通知(Notification)における「イベント作成者に送信(Send to event creator)」の仕様について

イベント発火をトリガーにしたメール通知を実装するとき、「受信者(Who will receive)」タブで宛先を設定するかと思います。

このとき、「ユーザー(Users)」「グループ(Groups)」など静的に宛先を設定したり、「フィールド内のユーザーまたはグループ(Users/Groups in fileds)」で可変となる宛先を設定できますが、最初からチェックが入っている「イベント作成者に送信(Send to event creator)」を目にして、

**「おっ、これがTrueならとりあえずイベント作成者には通知が飛ぶんだな」**

と、思っていました。


#### ↑これ勘違いでした。

これにチェックが入っているだけでは通知が飛びません。

先に結論を書きます。

:::note warn

いずれかの受信者フィールドにイベント作成者が設定されていなければ、「イベント作成者に送信(Send to event creator)」をチェックしていても通知されません。
:::

## 検証

#### ①「グループ(Groups)」宛にメール通知してみる

グループ「TestUserGroup」を作成。メンバーは以下。
・user1 test (test.user1@example.com)
・user2 test (test.user2@example.com)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251204/0e21f759-d316-1852-2395-0bcae1b3d536.png)

通知の宛先グループに設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251204/6a0c4fed-836c-4572-5cf0-ade78d100f00.png)

イベントを発火してみる。
・イベント名は「u_20230210_testtable.eventfire」
・イベント作成者は「test.user1」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251204/d20be408-c270-a526-45f6-f88cc02d3b6b.png)

メール送信箱に入った。
・宛先はグループのメンバー2名で正しい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251204/501dc5a7-4b4a-8c60-f336-361eba2a77bb.png)

#### ①「イベント作成者に送信(Send to event creator)」のチェックを外してメール通知してみる

チェックを外した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251204/5069e191-3526-93be-6437-6cef74bdd4f1.png)

イベント発火も確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251204/865561b2-ec83-390b-1795-cf61c5ae1241.png)

チェックを外したことで、イベント作成者(test.user1)が除外されて、
test.user2だけになったことを確認できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251204/bb0c571a-041c-f0d3-01b3-aa69b6c99d4f.png)

#### ③「イベント作成者に送信(Send to event creator)」のチェックだけでメール通知してみる

グループを外して、チェックをつけた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251204/a6845352-055d-02cf-0896-3205d136d4b1.png)

イベント発火も確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251204/b5ccadc9-c150-e061-e0da-5e3338a2e4d6.png)

イベント作成者(test.user1)に通知されると思いきや、メールは作成されない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251204/7e0a4002-3a68-399a-efc1-1558dcdb8e2c.png)

## まとめ

検証結果は以下となりました。
|宛先にイベント作成者を含むか|「イベント作成者に送信」|イベント作成者に実際に送信されるか|
|:-:|:-:|:-:|
|含む|True|される|
|含む|False|されない|
|含まない|True|されない|

以上

## 参考

https://docs.servicenow.com/ja-JP/bundle/tokyo-servicenow-platform/page/administer/notification/task/t_CreateANotification.html
MediaPad T2 Pro 10.0 へLineage OS 18.1を導入する

SIMフリーで4Gに対応しており、10インチというなかなかの大画面液晶を搭載した型落ちタブレット**MediaPad T2 Pro 10.0**。
Androidバージョン6.0の公式ROMが中々使いづらく、省電力を意識し過ぎたためかクロック数を本来利用できる値の1/4に強制的に固定しているため、常にもっさりとした動作になる。
しっかりと中華タブレットでありがちな**使えないことはないけどイライラする**の要素を含んでいるのだ。
# 10インチ版の既出記事がない
7インチ版へLinege OSを導入する記事はいくつか存在するものの、なぜか10インチ版への導入解説を行っているサイトを見つけることはできなかった。英語版ではいくつかあったが、日本語版はおそらく存在しない。
色々試行錯誤した結果、Linege OS 18.1 (Android 11)を導入することができた。流石にOSが新しいだけあって使いやすい。バージョンの低さが理由でアプリが利用できない問題に遭遇することもなくなった。
# 準備するもの
- BootloaderをUnlock済みのMediaPad T2 Pro 10.0
- [platform-tools](https://developer.android.com/studio/releases/platform-tools?hl=ja)
    - adb
    - fastboot
- [lineage-18.1-UNOFFICIAL-federer.zip](https://drive.google.com/file/d/1DgCa0PQgApb-hZB3YS0t37_HTAoeFEGL/view?usp=share_link)
- [TWRP-3.3.0-0-federer.img](https://drive.google.com/file/d/1BAYA1dHk4vMlivgtrIBGP1Bkk52uReGX/view?usp=sharing)
- [Open GAPPS](https://opengapps.org/)
    - Platform: ARM64
    - Android: 11.0
    - Variant: micro以下
- 32GBくらいのmicroSDカード
# 導入手順
#### microSDへromとgappsを配置
ルートディレクトリに`lineage-18.1-UNOFFICIAL-federer.zip`、`open_gapps_***.zip`を配置します。
　
#### fastbootからTWRPをブートさせる
タブレット本体の**電源ボタン**+**音量下ボタン**を長押ししてfastbootモードへしておく。

TWRPの.imgファイルを配置したディレクトリよりコマンドプロンプトを開き、下記コマンドを実行。
`fastboot boot TWRP-3.3.0-0-federer.img`


※ここで `fastboot flash recovery TWRP-3.3.0-0-federer.img` を実行してフラッシュを行うと、次回以降はfastbootコマンドを利用せず本体のみでTWRPを起動できるようになるのですが、なんとなく嫌だったのでリカバリーの上書きは行いませんでした。
　
#### TWRPでBackup & Wipeを行う
バックアップなんてしたことなかったんですが、念のため一応しておいた方がいいかもしれません。
`Backup`より
- `Boot`
- `Data`
- `System`

を選択し、`Select Storage`よりバックアップ先を`Micro SD card`に指定。`Swipe to Backup`をスワイプしてバックアップを開始する。
バックアップが完了したら、`Wipe`より`Advanced Wipe`から、
- `Dalvik / ART Cache`
- `cache`
- `Data`
- `System`
を選択し、`Swipe to Wipe`をスワイプ。完了したら今度は`Swipe to Factory Reset`を実行。
　
#### romとGAPPSのインストール
`Install`より`Select Storage`→`Micro SD card`を選択。
はじめに`lineage-18.1-UNOFFICIAL-federer.zip`を選択して`Add more Zips`より`open_gapps_***.zip`も追加。
`Swipe to confirm Flash`をスワイプしてインストール開始。

おなじみのlineageロゴが表示されれば、あとは待つだけです。

# トラブルシューティング
#### fastbootモードへ入れない
micro SDカードディレクトリに`dload`フォルダがあるとHuaweiのRecoveryが必ず起動します。
dloadディレクトリを削除してください
CSS 基本Part1

### CSSの色付け方法

- HTMLファイル　index.html
```css
<h1>Hello World</h1>

<p>プログラミングの世界へようこそ</p>
```

- CSSファイル　stylesheet.css

```css
h1 {
 color:#ff0000;
  }

p {
  color:#0000ff;
   }
```
h1 が赤色。
pが青色で表示される
Python: 剰余演算子を使わないで無限のジェネレータでFizzBuzzしてみた

[剰余演算子を使わずにFizzBuzzを解く](https://qiita.com/nkfrom_asu/items/783c6be996abe6cc2a67)  の題名を見て「そうだよな剰余演算子って別になくてもできるよな」って妙に納得してしまったので、自分だったらどうやるかな?と思って考えてみました。

「3の倍数かどうか」 と考えれば剰余演算子の出番ですが、「みっつめごとに"Fizz"になる」と考えれば別のやりかたがありそうです。


```py:
def print_fizzbuzz(n):
    for _, fizzbuzz in zip(range(0, n)
                           , fizzbuzz_gen()
                           ):
        print(fizzbuzz)
        
def fizzbuzz_gen():
    for fizz, buzz in zip(mod_gen(3, "Fizz")
                          , mod_gen(5, "Buzz")
                          ):
        yield (
            fizz if type(buzz) == int else
            buzz if type(fizz) == int else
            fizz + buzz
            )
        
def mod_gen(m, name):
    n = 1
    while True :
        for i in range(n, n+m-1):
            yield i 
        yield name
        n = n + m
        
print_fizzbuzz(100)
```
無限にFizzするジェネレータと無限にBuzzするジェネレータを組み合わせて無限にFizzBuzzするジェネレータを作り、それの最初から n 個を出力しています。

みっつめごとに"Fizz"って叫ぶ芸人と五つ目ごとに"Buzz"って叫ぶ芸人がコンビを組んでFizzBuzz芸をする、ってコンセプトです。
[個人開発]職務経歴書エディターを作りました

## 2023/03/07 追記
ブラウザに保存する機能を追加しました。
今まで、会員登録せずに入力→会員登録とすると入力データが消えてしまっていたのですが、それを解消する機能となります。

----

この度、職務経歴書をWEB上で作成するツールとして、resumeeというWEBアプリを作成しました。
サービスの紹介とやったことなどの振り返りを書いておこうかと思います。

## サービスについて

以下がサービスURLです。

https://www.resumee.site/

サービスの特徴としては、以下の3つになります。

1. マークダウンを使ってブラウザ上で記述ができる
2. 作った職務経歴書はファイルとしてダウンロードできる
3. 会員登録をすれば、職務経歴書を共有するための共有リンクを作成することができる

### 背景

転職をするかもとぼんやりと考えて、色々な企業の採用ページを見ていたのですが、その時2つ気づいたことがありました。

1. 企業の応募フォームから応募する場合、自分で職務経歴書を準備しなければならない
2. 転職時には、自身で作成したアプリの提出を求められることが多い

これに気づいたときに、「あ、てことは職務経歴書をいい感じに作れるWEBサービスを作ったら一石二鳥なのでは？」とひらめき、このようなサービスを作ろうと思い立ったのでした。
ただいきなり作ったわけではなく、簡単に競合調査のようなものもしてみたのですが、自分の観測範囲ではWEBサービスで職務経歴書作成に特化した良さげなものはあまりないように思えました。
というよりも、結構皆さんエクセルで作っているようで、これは作ったら使ってもらえるかも、と思い作ることにしました。

### かんたんな使い方

以下のURLから職務経歴書を作成することができます。

https://www.resumee.site/edit

使い方といってもあまり説明することはなく、各項目を自由に埋めていただくだけです。
項目の順番はドラッグ・アンド・ドロップで入れ替え可能で、項目自体の追加・削除もページ下部にあるメニューから行うことができます。
また、項目には表を用いることができます。表の行と列の増減ももちろん可能です。

ログインしていれば「保存する」ボタンから保存することができ、その横のメニューからファイルとしてダウンロードすることもできます。
ファイルダウンロードはログインしていなくても可能です。

すべて書き終わったら保存メニューから公開の操作を行い、アカウントのアイコンから共有リンクを作成し、URLを共有することで他の誰かと職務経歴書を共有することができます。

### サービスの売り
自分が思うこのサービスの売りは以下です。

- マークダウンで書けるので、エンジニアが親しみやすい
- 直感的な操作で職務経歴書作成ができる
- 共有リンクを使えば、いちいちファイルをダウンロードしてメールで送るなどということはしなくて良い（企業が許してくれるならの話ですが）

### 想定利用者
おそらくこういう人に刺さるサービスなのではないかとおもっています。

- エクセルで職務経歴書を作るのはちょっと嫌だなーと思っている
- 一方で、ポートフォリオを自分で作ったり、もしくはGithubやNotionを使って１から作るのもちょっとやりすぎだと感じている
- ある程度のフォーマットが固まっていて、その中では自由がきくようになっていてほしい
- そんなツールがあったらいいなと思っている

これは、自分自身が考えていたことでもあります。
よく個人開発では自分だけでも使いたいと思えるものを作れ、みたいなことが言われていますが、まさに自分がほしいものを作った感じですね。

## 使用した技術

言語: Typescript
フレームワーク: Next.js
UIフレームワーク: Chakra UI
ORM: Prisma
DB: Planet Scale
ホスティング: Vercel
ドメイン: CloudFlare

ドメインとこのサービス用に作ったGoogleWorkspace以外は、全て無料で済むような構成にしました。
VercelもPlanet Scaleも無料って本当にすごいですね。

## 開発期間

最初のコミットが2022/10/14だったので、およそ4ヶ月でした。
主に夜、眠る前にやってました。

## 苦労したポイントなど

マークダウン→PDF出力が一番たいへんでした。諦めようかとも思いました。
結構この部分はごりごりに実装しているために、一部マークダウンの装飾がPDFで反映されなくなってしまいました。
が、本当に一部なのでFAQにも書いたし大丈夫かな、、、と自分を納得させています。

途中何もしない期間があったりしましたが、意外とモチベは下がりませんでした。
自分がほしくて必要としているものだと、ちゃんと続けられるものだなと思います。


## 今後について

今後は運用となるので、できる限り快適に使えるようメンテしていきたいなと思っています。
SNSのようなサービスとは違い、利用人数が少なくとも成立するサービスなので、ほそぼそとでも続けていけたらなと思っています。

機能追加の予定などは特になく、今の機能で結構事足りているのではないかと感じています。
もしこういう機能がほしい、というのがあったら、コメントに書いたりしていただければ対応するかもです。

また、このサービスは今の所完全無料で広告なども入れていません。
大体無料で済むような構成を取っているので、有料化することはないかなあと思っています。
もしこういう風にマネタイズしたらどうかな、というのがあれば、これもコメントに書いていただけたらありがたいです。

こっそり目論んでいるのは、単品で使えるサービスなので、転職サービス系の1つの機能としてどこかの企業に買ってもらえたら一番ハッピーかもな、と思ったりしています。

---

色々書きましたが、もし転職で職務経歴書が必要になった、という方がいたら、試しに使ってみてください！
そしてフィードバックをもらえたら嬉しいです！
MUI TextField type='number'のスクロールイベントを止める


# 概要
`<TextField type='number' />`を使っているとスクロールに従って数値が上下します。
このスクロールで勝手に値が増減しても困るので、止める方法を残します。

# 解決策
スクロールで増減するイベントはフォーカスなので、フォーカスで止めます。
```tsx
import { BaseSyntheticEvent } from 'react'
import { TextField } from '@mui/material'

<TextField type='number' onFocus={(e: BaseSyntheticEvent) => e.target.blur()} />
```

`blur`イベントは、フォーカスが外れる時に起きるイベントで、フォーカス時に生じる
動作をフォーカスが外れた状態にすることで打ち消しています。

詳しくは以下の記事が参考になります。

https://developer.mozilla.org/ja/docs/Web/API/Element/blur_event
老技術者がWindows11でubuntuを使う（Windows11+WSL2+ubuntu）

 ## はじめに
老技術者は名前の通り還暦を過ぎた技術者である．ブロックチェーンの会社やAIの会社からお仕事をいただいてナウい技術を切り売りしている．開発案件は基本的にMacで良いのであるが，最近はナウい技術を教えてくれという需要が高まっている．すると教える相手がWindowsの人だったりするので，そんなものすぐに叩き売れとも言えず，仕方なく老技術者も話を合わせるためにWindowsマシンを買うことにする．とはいえ買うからには最新OSのやつを買わないと気が済まず買っちゃったのだよ，酔った勢いで．Windows11だよ．
```
プロセッサ	12th Gen Intel(R) Core(TM) i7-12700   2.10 GHz
実装 RAM	32.0 GB (31.7 GB 使用可能)

エディション	Windows 11 Pro
バージョン	22H2
インストール日	‎2023/‎01/‎15
OS ビルド	22621.1194
エクスペリエンス	Windows Feature Experience Pack 1000.22638.1000.0
```

Powershellを見たらターミナルなんてモードがあるので，普通にCurl使えるのだろうなとMac用にこしらえた虎の巻を使って仕事がらみのとあるサービスのAPIを叩いてみたらダメじゃん．なんで？と詮索する時間も惜しいのでubuntuを入れることにした．

## 1. ターミナル（管理者）を起動
スタートボタンを右クリックし「ターミナル（管理者）」をクリック．ダイアログが出るのでOK．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/873c23af-5899-d008-2422-bb5f54c5c1cb.png)

「ターミナル」？！とひるむが大丈夫PowerShellである．

![2023-02-10_20h06_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/32322b14-d4d3-f19d-f6a1-770f8dabd2c8.png)

そこに

```
wsl --list --online
```
と打ってリターン．そうすると，もうUbuntuだのDebianだのが入っている．ものによっては複数のディストリビューションが挙がっている．
そもそも，Windows Subsystem for Linuxの有効化はWindows10のどこかのバージョンから不要になっている．

![2023-02-10_20h15_58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/6ebe8d98-c4bf-3a6e-eaee-8beb241922e3.png)

そこでせっかくなので

```
wsl --install -d ディストリビューション名
```
と指定してみよう．
せっかくなのでUbuntu 20.04 LTSを選ぼう．最新のを選ばないのは君子危うきに云々．
ここで注意．
```
wsl --install -d Ubuntu 20.04 LTS
```
ではダメです！
```
wsl --install -d Ubuntu-20.04
```
と打ち込むと，Ubuntu 20.04 LTSが立ち上がってきます．

![2023-02-11_00h41_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/051bd3b2-780b-2966-a747-693e1fda2f10.png)

## 2. wsl --installでハマる
上記でうまくUbuntu 20.04 LTSが立ち上がった方は
次の<b>3. ubuntuを使えるようにする</b>に進んでよし．
しかし老技術者の場合はそうはいかなかった．
立ち上がったubuntuがすぐクラッシュする．
press any key
と出るので押してみるとubuntuが消えてしまうのだ．

そこで，いろいろ調べた挙句，
``
wsl --update
``
とやると，
![2023-02-11_00h50_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/ea857229-fb40-756c-bc4c-7a17a7c93660.png)

「インストールされました」と表示され，自動的にubuntuが立ち上がってくる．
一件落着．

## 3. ubuntuを使えるようにする
立ち上がってきたubuntuをまずは使える状態にする．

usernameには絶対に大文字を使わないように気を付けて記入．New passwordとRetype new passwordに忘れないパスワードを入れて，

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/327ca8c4-9bf8-2491-f6ce-1772b57d34bc.png)

エンターを押すと，優しいメッセージが現れる．

![2023-02-11_01h01_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/476ceee2-20f3-6cd2-d869-3eb9969f4bf8.png)

```
cat /etc/lsb-release
```
と打ってこんなのが返ってくればOK．

![2023-02-11_01h07_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/bc1b5b02-3757-5849-7819-a6d95f028236.png)

さて，このububtuで何をしようか．
ImportError: /lib64/libstdc++.so.6: cannot allocate memory in static TLS block　対策メモ

### こんなエラーが出た場合

```
Traceback (most recent call last):
  File "/usr/local/lib64/python3.8/site-packages/MySQLdb/__init__.py", line 18, in <module>
    from . import _mysql
ImportError: /lib64/libstdc++.so.6: cannot allocate memory in static TLS block

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "xxxx.py", line 15, in <module>
    import MySQLdb
  File "/usr/local/lib64/python3.8/site-packages/MySQLdb/__init__.py", line 24, in <module>
    version_info, _mysql.version_info, _mysql.__file__
NameError: name '_mysql' is not defined

```

### 対応の１つ

/etc/profile に記述

```
export LD_PRELOAD=/lib64/libstdc++.so.6
```
AzureのWeb Appsで作成するときにアクセス許可で手間取ったしょうもない話


# はじめに
初めてAzureでWebアプリを作ろうと息巻いてWeb Appsから作成しようとした矢先、
こんなエラーが出てしまいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413535/1a01f0c6-76fa-66f3-5489-2b96292098c4.png)

これどうすればいいの？という問題に初心者ながら対応したのをまとめます。

# 原因
そもそも作成時の設定がミスしていました。
Webアプリの作成で「公開」の項目が「コード」になっていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413535/75f2fba7-f41d-b126-91e3-6b386d8881c8.png)

正しいのは「静的」ですね。
そもそも「公開」で選択されるのは以下の時が良かったみたいです。

| 公開 | |
|-|-|
| コード | すでにGitHub Actionsで作成されたアプリをデプロイしたいとき |
| Docker | すでにコンテナで作成されたアプリでデプロイしたいとき|
| 静的| 静的なWebアプリを作成したいとき |

何も考えずにやって余計な時間を食ってしまいました。

# 解決法
一度作成したApp Serviceを削除し、公開を「静的」で作成しなおしたらできました。

# 最後に
初心者らしいミスでした。
これからAzureやるぞ！というエンジニアの方はお互い気を付けてましょう
【JavaScript】コロンのないオブジェクト！？

## 前書き
Udemyを受講している時、JavaScriptのコードでコロンのないオブジェクトを見かけました。
波括弧で囲われているのにも関わらず、波括弧の中で宣言済みの変数(定数)を配列のようにカンマで羅列させていました。
混乱しましたが、結果自分で解決できました。くっそ簡単な理論でした。
## コロンのないオブジェクトの正体とはいったい！？
このコロンのないオブジェクトを考えていると、あることを閃きました。
**波括弧の中の変数(定数)は「変数名:変数の値」を表しているんじゃね？**
居ても立ってもいられず書いてみました
```JavaScript:test.js
const hoge = "hogeだよ";
const fuga = "fugaだよ";
const piyo = "piyoだよ";

const testDict = {
    hoge,
    fuga, 
    piyo
}

console.log(testDict);
// =>{ hoge: 'hogeだよ', fuga: 'fugaだよ', piyo: 'piyoだよ' }
```

## 正解でした
一件落着！！！
なんか、Swiperもっさりしてるな

# 主旨
Reactのスイープ処理ライブラリ、Swiperを使用してみたけど、意外ともっさりしてた。
pure jsでスイープ処理を実現するサイトを参考にして、スイープ処理を自作した話。

# Swiper
[こちら](https://swiperjs.com/demos)。
Reactでスイープ処理を実現しようとすると、一番の候補となる。

## なんか、思ってたよりももっさりしてるな
実現したい要件としては、ネイティブアプリのTrelloのリスト切り替え時くらいのレスポンス。
だけど、スマホでSwiperのdemo操作をして、もっさりすることが判明。また、実際にアプリに組み込んでみても、案の定、もっさり動作することが判明。
普通にストレスフル。

## pure js ならばどうか
[参考サイト](https://dianxnao.com/javascript%E3%81%A7%E3%82%B9%E3%83%AF%E3%82%A4%E3%83%97%E5%87%A6%E7%90%86%E3%82%92%E3%81%99%E3%82%8B/)
[デモサイト(スマホのみ反応)](https://dianxnao.com/js/swipe_counter/index.html)
めっちゃいい。私の望むレスポンスに近い。しかもどれくらい動かした時にスイープしたと判断する閾値も変えられる。

## React上で実装できるか？
タッチイベントをReactでどう実現するかを調べた。ググればいっぱい出てきた。
[参考サイト](https://felixgerschau.com/react-typescript-ontouchstart-event-type/)


# 実装
カスタムフックとして切り出した。
```react
import { TouchEvent, useState } from "react"

export const useSwipe = () => {
    const dist = 80;

    const [startX, setStartX] = useState(0);
    const [moveX, setMoveX] = useState(0);
    const [currentIndex, setCurrentIndex] = useState(0);

    const touchStartHandler = (e: TouchEvent<HTMLDivElement>) => {
        setStartX(e.touches[0].pageX);
    }

    const touchMoveHandler = (e: TouchEvent<HTMLDivElement>) => {
        setMoveX(e.changedTouches[0].pageX);
    }

    return {
        currentIndex, startX, moveX, dist,
        touchStartHandler, touchMoveHandler, setCurrentIndex,
    }
}
```

呼び出し側
```react
export const MyComponent: FC = () => {
    const { currentIndex, startX, moveX, dist,
        touchStartHandler, touchMoveHandler, setCurrentIndex } = useSwipe();

    return(
        <>
            <div 
               onTouchStart={touchStartHandler}
               onTouchMove={touchMoveHandler}
               onTouchEnd={() => {
                            if (startX > moveX && startX > moveX + dist) {
                                // 右へスイープした場合の処理
                            }
                            else if (startX < moveX && startX + dist < moveX) {
                                // 左へスイープした場合の処理
                            }
                        }}
                >
            </div>
        </>
)};
```
スイープ完了時の処理も、コンポーネントのstateに依存しなければ、フック側に記述可能

# 実演
スイープ処理を行いたいアプリで、動作確認した。
![movie.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532785/b1f3fffa-c46a-2c7f-7380-c39741f749e0.gif)
いいじゃん。ノーストレスフル。

# 結果
Swiperよりも、最小限で、高レスポンスなスイープ処理を実現できた。
pure jsの処理をReact上に実装する手法も学べた。
vitest, jestでnew Dateを固定する

# vitest, jestでnew Dateを固定する

## なんでこの記事を書くのか？

よく忘れるので、書き方を記載しておく

## vitest

[vi.useFakeTimers()](https://vitest.dev/guide/mocking.html#dates)を利用し、[vi.setSystemTime()](https://vitest.dev/guide/mocking.html#dates)でdateを固定する。

```sample.spect.ts
beforeEach(() => {
  vi.useFakeTimers()
})

afterEach(() => {
  vi.useRealTimers()
})

it("", () => {
  const date = new Date(2000, 1, 1)
  vi.setSystemTime(date)
　　expect(date.toLocaleDateString()).toBe("2/1/2000")
})
```

## jest

[jest.useFakeTimer()](https://jestjs.io/docs/timer-mocks#run-all-timers)を利用して、日時を固定する

```sample.spec.ts
beforeEach(() => {
  jest.useFakeTimers().setSystemTime(new Date('2000-01-01'));
})

afterEach(() => {
  jest.useRealTimers();
});

it("", () => {
  const date = new Date(2000, 1, 1)
  expect(date.toLocaleDateString()).toBe("2/1/2000")
})
```

忘れないようにしたい。(きっとまたググる)
【システム運用】顧客から特別対応を求められた時の対応方針

### 初めに

この記事は法人向けのSaas運用を想定して書いています。
オーダーメイドのシステムやtoC向けのアプリケーションは考慮していません。
ご了承ください。

### この記事の目的

顧客から特別対応を求められた時の対応方についてノウハウを整理することで、システム運用におけるトラブルを回避すること。また、これにより顧客に高品質なサービスを提供すること。

### 特別対応とは

ここでは「不特定多数の顧客に提供しているサービスにおいて、特定の顧客に対して基本機能・オプションに含まれないサービスを提供すること」と定義します。

具体的には顧客が誤って削除したデータをバックアップファイルから復元する、特定のノードのみリリース日時を変更する等が挙げられます。

### 基本方針

原則として特別対応はお断りするのが良いです。
理由として以下のことがあります。

- 想定していないオペレーションにより予期しないトラブルが起こる可能性がある。
  - データを復元する際に誤って関係のないデータを切り戻してしまう、デプロイ手順を書き換えて不具合が発生するなどのトラブルがよく起こります。
- CSチームとの調整や事前検証等に時間がとられて本来やるべき業務に取り組むことができない。
  - 新機能開発・問い合わせ対応等にかけられる稼働が減り、総合的なサービスとしての品質が低下します。
- 特別対応の前例を作るとそれ以降も他の顧客(あるいは、特別対応の前例を知った営業)から同様の対応を求められる。
  - 一度前例を作ると断ることが難しくなります。


ただし、注意点として単に「特別対応はやりません」と無下に断ると角が立ちます。
CSチームや営業チームとの関係が悪化して今後の業務に悪影響が出ることは避けたいです。

上記のような理由をきっちりと説明すれば大抵は大きな問題なく断ることができるでしょう。

この時、「開発が大変なのでやりたくない」だけではなく **「お客様に不利益が及ぶ危険があるのでやらない方が良い」** という方向で説明できれば納得いただける可能性が上がります。


例： 「事前に十分検証の上対応しますが予期せずデータが更新・削除される可能性があります。この場合、復旧に0.5人日程度かかりその間はシステムをご利用いただけません。」


### どうしても対応を求められた場合

やりたくない理由やリスクを説明しても対応を求められることはままあります。
この時本番作業前にがやるべきことは以下の3点です。

1. 上位者に報告して承認を得る
1. 関係各所と調整して合意形成する
1. 事前に検証する

#### 1. 上位者に報告して承認を得る

特別対応のようにリスクのある作業を実施する時は必ず上位者に報告して承認を得ます。
その目的は 大きく2つあります。

1つは報告によって責任を上位者に委譲することです。事前に報告すれば仮に問題が発生した場合でも何とかしてもらえる可能性が上がります。逆に報告せずに事を進めて問題が発生した場合かなり怒られます。

2つ目の目的は対応方針をレビューしてもらい、問題点やリスクを解消することです。
そのためには単に「特別対応することになりました。どうすればよいですか？」と報告するのではなく、「特別対応します。 私はこのような方針で作業を進めようと考えています」とある程度たたき台を作っておくと良いでしょう。


報告する範囲は顧客影響の大きさによって変わります。DBのレコードを1つ更新する程度であればチームリーダーに報告すれば十分だと思います。リリース時期を変更する・システム要件を超えた利用を許可するといった内容であればPdMや管理職にも報告すべきでしょう。

また、必ずチャットやメモ書き程度でも良いので報告と承認の証跡を残します。

#### 2. 関係各所と調整して合意形成する

開発チーム内で承認が下りたら次は関係各所と調整します。この作業は平のメンバーがやるよりもある程度肩書のあるメンバー(PdMやチームリーダー)がやる方がスムーズに進むことが多いです。 可能であれば報告の時点で依頼しておくのが良いでしょう。

ここでいう関係各所としては開発・顧客との窓口になる部署(主に営業やCS)・本番作業を担当する部署(開発部内の運用エンジニアやインフラチームのメンバー)を想定しています。

どの部署からもある程度上位者に参加してもらう必要があります。

ここでは対応方針と対応完了までの納期を調整します。 営業やCSからはなるべく早くしてほしいと言われることが多いですが、適当に理由をつけて断る方が無難です。

ここでも合意形成に至るまでの証跡を文面で残します。

#### 3. 事前に検証する

対応方針が決まったら検証を実施します。
検証の目的は2つあります。

1つは当然作業内容に問題がないかを事前に確認することです。2つ目は問題が発生した際に原因がどこにあったのかを検証するための証拠を残すことです。(万一障害報告書の提出にまで発展した場合にも材料にすることができます。)

検証にあたってはなるべく本番と近い状態を再現します。(データ量・アクセス状況・MWのバージョン等)
本番に近い環境を急ごしらえするのは大変なので、普段から本番相当の環境を最低1つ用意しておくのが良い運用と言えそうです。

また、ここでも証跡を残します。ターミナルのログを使うのが手っ取り早いです。


### 本番作業

祈ります。

### 全体を通して

説明・報告・記録によって責任を回避することがシステム運用の肝と言えるかもしれません。
Anacondaの仮想環境でpip installできないときのプロキシ設定（社用PC）

## はじめに
社用PC（Windows）にインストールしたAnacondaで仮想環境を構築し、その中で`pip install pycaret`しても以下のエラーでインストールできなかったので、その解決方法のメモ。

```bash
>pip install pycaret
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1131)'))': /simple/pycaret/
WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1131)'))': /simple/pycaret/
WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1131)'))': /simple/pycaret/
WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1131)'))': /simple/pycaret/
WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1131)'))': /simple/pycaret/
Could not fetch URL https://pypi.org/simple/pycaret/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='pypi.org', port=443): Max retries exceeded with url: /simple/pycaret/ (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1131)'))) - skipping
ERROR: Could not find a version that satisfies the requirement pycaret (from versions: none)
ERROR: No matching distribution found for pycaret
```

## 試したこと
以下の方法を実施してみたのですが、なかなかエラー解消されませんでした。同じような方は今回の方法で解決できるかもしれません。

### pipインストール時の接続先を信頼済に設定
参考：https://qiita.com/kekosh/items/e96e822bf9cb6ca1aff8

うまくいかず。

### Anacondaにプロキシ設定
参考：https://qiita.com/teruroom/items/7d8c26dc07ddeae90be8

逆にこの方法でcondaコマンドでエラーが出るようになってしまいました。（なぜ）

### pipコマンドでプロキシ指定
参考：https://qiita.com/masahiro-t/items/ca7a52cb9037bba9443d#pip%E3%81%AE%E3%83%97%E3%83%AD%E3%82%AD%E3%82%B7%E5%AF%BE%E5%BF%9C

pipコマンドでプロキシ指定したらインストールが進み始めたので、うまくいったと思ったのですが、途中で再度冒頭のようなエラーが出て止まってしまいました。

おそらくですが、インストールする過程で別途pipコマンドが使われていて、そのプロキシが指定されていないことが原因かもしれません。


## 解決方法

pipのProxy設定を設定ファイル（pip.ini）で実施してコマンドを打ったらうまくいきました！
参考：[Python3][Windows]pip の proxy 指定 を設定ファイルで行う（https://www.curict.com/item/46/4657c26.html）

ファイルパス：`C:\ProgramData\pip\pip.ini`

```ini:pip.ini
[global]
proxy = [プロキシアドレス]:[ポート番号]
```

上記のパスはグローバルにpipの設定をする場合らしいので、ユーザーローカルで実施する際には別の方法が必要になるかもしれません。

## さいごに
あれやこれやと方法を試してやっと解決するまでに一日費やしてしまいました。。（せっかくの金曜日が笑）
私と同じように困っている方の助けになれば嬉しいです。
【Linux】grepコマンドで先読みや後読みを使う方法

## 方法

grepコマンドで先読みや後読みを使用するには次のようにコマンドを実行します。

```terminal
grep -P 'foo(?!bar)'
```

## 先読み後読みについて

https://www.javadrive.jp/regex-basic/writing/index2.html
APGWのアドレスプール（＝バックエンドプール）の接続切り離し

# はじめに
メモ残しとく

# コマンド（アドレスプールにVMのIPを削除する）

```
# Set variables for the resource group and application gateway names
$resource_group_name="pro-nabehiro-001"
$app_gateway_name="nbfr151x"
$backend_pool_name = "appGatewayBackendPool"

# show address pool ip addresses from the application gateway
az network application-gateway address-pool list --resource-group $resource_group_name --gateway-name $app_gateway_name


# Detach the backend pool from the application gateway
az network application-gateway address-pool delete --resource-group $resource_group_name --gateway-name $app_gateway_name -name $backend_pool_name --remove backendAddresses

# show address pool ip addresses from the application gateway
az network application-gateway address-pool list --resource-group $resource_group_name --gateway-name $app_gateway_name
```


# コマンド（アドレスプールにVMのIPを接続する）

```
# Set variables for the resource group and application gateway names
$resource_group_name="pro-nabehiro-001"
$app_gateway_name="nbfr151x"
$backend_pool_name = "appGatewayBackendPool"
$vm_ips = @("10.0.0.4", "10.0.0.5", "10.0.0.6")

# show address pool ip addresses from the application gateway
az network application-gateway address-pool list --resource-group $resource_group_name --gateway-name $app_gateway_name

# atach the backend pool from the application gateway
az network application-gateway address-pool update --resource-group $resource_group_name --gateway-name $app_gateway_name --name $backend_pool_name --server $vm_ips

# show address pool ip addresses from the application gateway
az network application-gateway address-pool list --resource-group $resource_group_name --gateway-name $app_gateway_name
```