OmniAICreator/Qiita-1.07M huggingface dataset:
【AWS】EC2にEFSのマウントが上手くいかないときに確認する事

# 概要
Session ManagerでEC2インスタンスへ接続して、共有ストレージサービスのEFSをマウントしようとしたところ上手くマウントできず暫く沼にはまったので、戒めとして記録に残します。

# EFSとは
EFS(Amazon Elastic File System)は、AWSが提供するファイルストレージサービスです。
ファイルストレージサービスだとDropboxが有名です。
EBSと異なって、複数のEC2インスタンスに一つのEFSをマウントすることが可能です。
![WS000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638561/ad7ec624-7b0e-710e-9f4e-d441c44fb82f.jpeg)
EFSのリソースを作成すると、fsから始まるファイルシステムIDが自動採番されるので、
そのIDはマウントする際に使用します。

# EFSのマウント手順

```
1. session Managerにログインする
2. df -h コマンドでEFSがマウントされていない事を確認する
3. cat /etc/fstab コマンドでfstabファイル内を確認する
4. vi /etc/fstab コマンドでfstabファイル内に下表の必要な情報を追記して保存する
5. cat /etc/fstab コマンドでfstabファイル内を確認する
6. mount -a コマンドでEFSのマウントを実施する
7. df -h コマンドでEFSがマウントできたかを確認する
```

# fstabファイルに記載する内容
| デバイスファイル名 | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>マウントポイント | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>ファイルシステムの種類 | マウントオプション | dump対象 | &nbsp;fsck順序 |
| :---: | :---: | :---:| --- | :--:| :---:|
| fs-×××××××××××××××××.efs.ap-northeast-1.amazonaws.com:/ | /work | nfs4 |nfsvers=4.1,rsize=1048576,<br>wsize=1048576,hard,timeo=600,<br>retrans=2,noresvport,_netdev| 0 | 0 |

<br>例としてworkディレクトリにEFSをマウントする想定で、マウントオプション内の値については
**[NFS の推奨されるマウントオプション](https://docs.aws.amazon.com/ja_jp/efs/latest/ug/mounting-fs-nfs-mount-settings.html)** を参照ください。

上記1～7のコマンドを入力し、fstabファイルを編集すればEFSのマウントは成功するはずです。
それでマウントできない場合、以下の理由が想定されます。

# マウント失敗の原因

```
1. fstabファイルに記載したデバイスファイル名の記載が誤っている
2. セキュリティグループの設定が不足している
3. 異なる環境のEFSリソース情報をfstabに記載していたりする
```


上記1のデバイスファイル名の記載が誤っているについては私が失敗した事例です。
![WS000001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638561/37f247ef-fe35-8d4f-0bda-0dd052d1c0b5.jpeg)
EFSのリソース上のDNS名はコピペが出来てほぼデバイスファイル名そのままです。
しかし、DNS名にはデバイスファイル名の末尾に記載するべき **:/** がありません。
EFSマウントが成功する場合と失敗する場合が発生し、**:/** の記載漏れに気付けなかった私は暫く沼にはまりました。

**mount.nfs4: remote share not in 'host:dir' format** と文言が出力され、
**リモート共有がhost:irではありません**と怒られましたが、そんな設定をしてなかったのですが、
実際は **:/** のただの記載漏れでした。

上記2のセキュリティグループについては設定の不足が原因で**Connection timed out**が発生することがあります。事例が分かりやすかったので **[[小ネタ][EFS]マウント時にConnection timed outが出て少しハマる](https://dev.classmethod.jp/articles/20181209-efs/#toc-2)** を参照ください。

上記3については複数のAWS環境を行き来する場合に起こりえます。実際に使用するのは本番環境のEFSリソースなのに、検証環境のEFSリソースを設定していたなんていう場合にも**Connection timed out**が発生します。

一文字の記載漏れでも上手く動いてくれなくて、延々と時間を溶かすことが起こりえます。
成功した場合と失敗した場合の比較をするために **[WinMerge](https://winmerge.org/?lang=ja)** で比較すれば良かったかもと頭をよぎりました。

# 補足
fstabファイルの編集はvimで編集しています。
vimも使わないとすぐにコマンドを忘れるので、
よくお世話になるQiita記事のリンクを貼っておきます。※自分用でもあります。
**[よく使う Vim のコマンドまとめ](https://qiita.com/hide/items/5bfe5b322872c61a6896)**
Rustのserdeを使ってJsonの新規作成・読み込みをする

# serde exampleを作ろう(1)

Rust言語のserdeは便利なライブラリで必須といっても過言ではないライブラリですが、ネットで使い方を調べるとやりたい事が載ってないことが多いので用例集を書いておこうと思った次第です。
自分の備忘録としても使っていきます。

## jsonファイルを新規作成・書き込み
必要なライブラリは以下のようになっています。
注意点はfeatures=["derive"]の記述がないと動かないことです。

```toml
[package]
name = "serde_json_example"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1.0.163", features = ["derive"] }
serde_json = "1.0.96"

```

## ソースコード
```rust
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::prelude::*;

#[derive(Serialize, Deserialize)]
struct Person {
    name: String,
    age: u32,
}

fn create_json_file() {
    // 構造体のデータを作成
    let person = Person {
        name: "Alice".to_string(),
        age: 25,
    };

    // 構造体をJSON文字列にシリアライズ
    let serialized = serde_json::to_string(&person).unwrap();

    // JSON文字列をファイルに書き込む
    let mut file = File::create("person.json").unwrap();
    file.write_all(serialized.as_bytes()).unwrap();
}

fn read_json_file() {
    // JSONファイルを読み込む
    let mut file = File::open("person.json").unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();

    // JSON文字列をデシリアライズして構造体に変換
    let deserialized: Person = serde_json::from_str(&contents).unwrap();

    // デシリアライズされたデータを表示
    println!("Name: {}", deserialized.name);
    println!("Age: {}", deserialized.age);
}

fn main() {
    create_json_file();
    read_json_file();
}

```

以上となります。
※このコードはChatGPTより生成したコードから私の方で明らかな間違いを修正したものとなります。
緯度経度から地図タイル座標への変換

# 初めに
[地図タイルダウンロードツール](https://qiita.com/notmushroom/items/2e7cb89ad623ca6edf9f)作成にあたり、緯度経度をタイル座標に変換する必要があり、計算式等を調べたが理解できる解説がなかったので、自分で式を作りました。もっと簡易な方法があるかもしれません

本解説では、緯度経度を一度ＸＹ座標へ変換していますがこれは個人的に理解しやすかったからです

# 変換方法
ざっくりと次の手順で計算している。
1. 北緯約８５度をＹ座標０としたときの南緯約８５度のＹ座標を算出する
1. 西経１８０度をＸ座標０としたときの東経１８０度のＸ座標を算出する
1. ズームレベル「Ｚ」におけるＸＹ座標それぞれのタイルの最大数を算出する
1. １、２をそれぞれ３で割り、タイル１枚あたりの間隔を算出する
1. 変換したい座標のうち緯度のＹ座標を算出する
1. 変換したい座標のうち経度のＸ座標を算出する
1. ５、６をそれぞれ４で割る
1. ７の小数点以下を切り捨てた値がタイルのＸ（経度）Ｙ（緯度）座標となる

## 各手順を説明する前に
**地図タイル**とは主にＷｅｂメルカトルで用いられる地図を表すためのパーツのようなもの
詳しい説明は[国土地理院](https://maps.gsi.go.jp/development/siyou.html)を参照


#### 前提
・ 測地系は<b>ＷＧＳ８４</b>
　 赤道半径(m)：<font color=red>$a = 6,378,137$</font>
・ <b>地球は真球</b>として扱う
・ 今回は<b>緯度35.685227、経度139.753347(皇居)</b>のタイル座標を求めてみる。
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394814/c6fdd478-e3f2-069f-7e72-709de819152d.png)



## 手順１、２：ＸＹ座標の最大値を算出
#### 緯度南端
$S = -85.05112877980659$
#### Ｙ座標南端
$Ys = a * Atanh(Sin(S * π / 180))$
$Ys = -20,037,508.34278924$

赤道を基準とした値から北緯約８５度を基準とした値に変換する
$Ys=40,075,016.68557848$
***
#### 経度東端
$E = 180$
#### Ｘ座標東端
$Xe = a * E * π / 180$
$Xe = 20,037,508.34278924$

本初子午線を基準とした値から西経180度を基準とした値に変換する
$Xe=40,075,016.68557848$


## 手順３：タイル最大数
タイルはズームレベルが１つ上がる毎に２倍されていく
従ってズームレベルｎにおけるＸＹ座標それぞれのタイル最大数は<b>$2^n$</b>

## 手順４：タイル間隔
ズームレベルｎにおけるタイル間隔は以下の通り
$40,075,016.68557848/2^n$

## 手順５、６：ＸＹ座標の算出
手順１、２の最大値を求める緯度経度を今回タイル座標を求める緯度経度へ置き換える

#### 求める緯度のＹ座標
$N = 35.685227$
$Yn = a * Atanh(Sin(N * π / 180))$
$Yn = 4,257,395.08697871$

赤道を基準とした値から北緯約８５度を基準とした値に変換する
$Yn=20,037,508.34278924 - 4,257,395.08697871$
$Yn=$<font color=blue>$15,780,113.25581053$</font>

#### 求める経度のＸ座標
$W = 139.753347$
$Xw = a * W * π / 180$
$Xw = 15,557,271.42469566$

本初子午線を基準とした値から西経180度を基準とした値に変換する
$Xw=20,037,508.34278924 + 15,557,271.42469566$
$Xw=$<font color=blue>$35,594,779.7674849$</font>

## 手順７、８
手順５、６の値を手順４の値で割って、小数点以下を切り捨てた値がタイル座標となる
<b>緯度35.685227、経度139.753347(皇居)のズームレベル14</b>のタイル座標は次のとおり

ズームレベル：$n = 14$
タイル１枚の間隔：$40,075,016.68557848/2^n=2,445.98490512$
Ｙ座標：<font color=blue>$15,780,113.25581053$</font>
Ｘ座標：<font color=blue>$35,594,779.7674849$</font>
#### タイル座標Ｙ
$15,780,113.25581053 / 2,445.98490512 = 6,451.43525733$
小数点以下を切り捨てて<font color="red">$6,451$</font>
#### タイル座標Ｘ
$35,594,779.7674849 / 2,445.98490512 = 14,552.33010350$
小数点以下を切り捨てて<font color="red">$14,552$</font>

## 最後に
タイル座標は次の式で求められる。

赤道半径：$a=6,378,137$
ズームレベル：$n$
緯度：$Lat$
経度：$Lon$
Ｙ座標の最大値：$Ys=40,075,016.68557848$
Ｙ座標の中央値：$Yq=20,037,508.34278924$
Ｘ座標の最大値：$Xe=40,075,016.68557848$
Ｘ座標の中央値：$Xq=20,037,508.34278924$

$タイル座標Ｙ=(Yq - a * Atanh(Sin(Lat * π / 180)))/(Ys / 2^n)$
$タイル座標Ｘ=(Xq + a * Lon * π / 180)/(Xe / 2^n)$
電動機試験(moter test) 　制御(16)

モータトルク総合試験機
https://www.sugawara-labs.co.jp/motor/torque/モータトルク総合試験機

モータの基本特性試験（中型・大型）
https://www.onosokki.co.jp/HP-WK/products/keisoku/test_system/motor_basictest.htm

モータ特性自動検査システム
https://www.nskw.co.jp/automotive/solution/automobile/hev/motor.html

モータ試験装置
~~http://www.kdwan.co.jp/solution/s_test_motor01.html~~
https://www.ipros.jp/product/detail/2000704919

モータ負荷試験装置／耐久試験装置
https://tk-techno.co.jp/motor/

電気サーボモータ式振動試験機
http://www.kokusaikk.co.jp/product/tester/vibration/about-esm.html

誘導~~モータ試験
~~https://www.toyo.co.jp/mecha/solution/detail/id=8070~~
https://www.toyo.co.jp/mecha/contents/detail/magtrol.html

モータ~~の試験成績書（テストレポート）の記載事項、活用について~~
https://cyclo.shi.co.jp/product/select-capacity/gear-motor.html?selection=capacity

~~モータ制御あれこれ~~
~~https://www.atengineer.com/pr/technoalive/company~~

 ＜この記事は書きかけです。順次追記します。＞

# 参考資料
power energy research 
https://qiita.com/kaizen_nagoya/items/001dcea35c73a907a9cd

Motor Bench and Hardware In the Loop Simulator
https://qiita.com/kaizen_nagoya/items/3b5cf163663ad1d3b83e

電動機故障診断(ACサーボモータを中心に)
https://qiita.com/kaizen_nagoya/items/756d19527d5f862e8085

プログラマが電動機(electric motor)制御する際に陥る穴
https://qiita.com/kaizen_nagoya/items/1f26d75bb1a8fb0f9e1b


物理記事　上位100
https://qiita.com/kaizen_nagoya/items/66e90fe31fbe3facc6ff

数学関連記事１００
https://qiita.com/kaizen_nagoya/items/d8dadb49a6397e854c6d

言語・文学記事　１００
https://qiita.com/kaizen_nagoya/items/42d58d5ef7fb53c407d6

医工連携関連記事一覧
https://qiita.com/kaizen_nagoya/items/6ab51c12ba51bc260a82

通信記事１００
https://qiita.com/kaizen_nagoya/items/1d67de5e1cd207b05ef7

自動車　記事　１００
https://qiita.com/kaizen_nagoya/items/f7f0b9ab36569ad409c5

なみのりがうまくなるのか波作る電動機(motor)作るの上手くなるのか 携帯電話計画者日記(8)
https://qiita.com/kaizen_nagoya/items/789e92b9eb3e15108e08

モータ試験
https://researchmap.jp/blogs/blog_entries/view/78451/96afad149ac78cf5d4a29d9892ad0789

プログラマが知っていると良い「公序良俗」
https://qiita.com/kaizen_nagoya/items/9fe7c0dfac2fbd77a945

一覧の一覧( The directory of directories of mine.) Qiita(100)
https://qiita.com/kaizen_nagoya/items/7eb0e006543886138f39

小川清最終講義、小川清最終講義（再）計画, Ethernet(100) 英語(100) 安全(100)
https://qiita.com/kaizen_nagoya/items/e2df642e3951e35e6a53

＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞
This article is an individual impression based on the individual's experience. It has nothing to do with the organization or business to which I currently belong.
# 文書履歴(document history)
ver. 0.01初稿　　20230527
### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
####  Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.
Azure BackupでVM単体のバックアップを取得する

### Azure Backupを設定

Azure Portalの対象VMの管理画面からBackupを選択し、バックアップを有効化することができます。
![backup1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3322105/1cafef8b-3269-8c39-7507-db11cc13c3d1.png)

|入力値|概要| 
|:-:|:-:|
|リカバリーサービスコンテナ|バックアップコピーの配置場所|
|コンテナ名|既存のものがある場合は選択する|
|ポリシータイプ|規定または拡張のポリシーを選択するとバックアップポリシーに反映される。拡張だと1日に複数回バックアップを構成でき、[トラステッド起動のVM](https://learn.microsoft.com/ja-jp/azure/virtual-machines/trusted-launch)に対応する|
|バックアップポリシー|規定、または拡張、新規作成から選択できる|

完了すると以下のようにバックアップの取得状態を確認できます。初回バックアップはすぐに開始することもスケジュールを待つこともできます。
![backup2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3322105/48158a6c-815b-b455-259b-a5b89dbfa1a9.png)

バックアップセンターを使用して1つのウィンドウで全体のジョブやバックアップインベントリを監視することも可能です。
![backup3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3322105/4e1e26df-44dd-5af8-117e-5560d745ae1b.png)

### リストア

リストアオプションは現時点で5つ用意されています。
- 新しいVMを作成する
- ディスクを復元する
- 既存のものを置き換える
- ペアリージョンに復元する
- 別のサブスクリプションで復元する（プレビュー）
- 別のゾーンで復元する

バックアップセンターからリストアを開始できます。
![backup4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3322105/0b251e1c-ac22-cd93-5793-fd249a61612c.png)

### ディスクスナップショットとの違い

スナップショットはディスク単位なのに対し、Azure Backupは仮想マシン単位で取得することができます。
Azure Backupはポリシーに沿って定期的にバックアップを取得、管理し、バックアップセンターで監視できるため管理が楽です。また転送中、保存データともに保護されるためランサムウェア対策にも活用できます（ランサムウェア対策についてはディスクスナップショットでも可能です）。
対してディスクスナップショットはマネージドディスクを作成してから復元するため、VMを複製したいときにも重宝するというのが私の理解です。

※5/27追記
また整合性の観点でもディスクスナップショットとAzure Backupでは違いがあり、Azure Backupではアプリケーション整合性に対応していますが（Windowsの場合VSS対応が必要）、ディスクスナップショットの場合はクラッシュ整合性になります。整合性の観点では以下の記事が詳しくまとめられています。

@aktsmm さんコメントありがとうございました。[Azure VM Backupにおける整合性について](https://jpabrs-scem.github.io/blog/AzureVMBackup/Consistencies/)の記事を参考にさせていただきました。

### 参考
- [バックアップ センターを使用してバックアップとディザスター リカバリーを監視および操作する](https://learn.microsoft.com/ja-jp/azure/backup/backup-center-monitor-operate#resource-centric-views)
- [VM の設定から Azure VM をバックアップする](https://learn.microsoft.com/ja-jp/azure/backup/backup-azure-vms-first-look-arm)
RubyでAtCoder ABC254(A, B, C)を解いてみた

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC254のA, B, Cを解きました。備忘録として解き方をまとめていきたいと思います。

# A - Last Two Digits
https://atcoder.jp/contests/abc254/tasks/abc254_a
```ruby:a-254.rb
puts gets.chomp[1..]
```

# B - Practical Computing
https://atcoder.jp/contests/abc254/tasks/abc254_b
```ruby:b-254.rb
n = gets.to_i
array = []
for i in 0..n - 1
  answer = []
  for j in 0..i
    if j == 0 || j == i
      answer << 1
    else
      answer << array[i - 1][j - 1] + array[i - 1][j]
    end
  end
  array << answer
  puts answer.join(" ")
end
```
他の方の提出結果を参考にした別解になります。

combinationメソッドを使うことでもっと簡素に書くことができます。
```ruby:別解
n = gets.to_i

n.times do |i|
  puts (0..i).map{ |j| [*1..i].combination(j).size }.join(" ")
end
```
## 解説
問題文にある通りにコーディングすることで実装することができます。

# C - K Swap
https://atcoder.jp/contests/abc254/tasks/abc254_c
```ruby:c-254.rb
n, k = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)
b = Array.new(k) { [] }

a.each_with_index do |number, index|
  b[index % k] << number
end

b.each do |array|
  array.sort!
end

array_after_sort = []
n.times do |i|
  array_after_sort << b[i % k].shift
end
puts array_after_sort == a.sort ? "Yes" : "No"
```
## 解説
（公式解説を参考にしました）

最初にK飛びごとの要素を取得することで、バブルソートできる形にし、それぞれ配列bに格納します。このとき、bに含まれる各配列は必ず昇順にすることができます。最後に、bの要素をもとの順番に戻したものが、aをソートしたものと一致しているかどうかを判定することにより実装することができます。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166
Retrofit / OkHttp APIコール時にヘッダ、パラメータ追加

## Retrofit2 / OkHttp3 でAPI通信機能作成時にヘッダやパラメータを追加する場合のメモ

よくあるこんなの

```kotlin
fun builderHttpClient(): OkHttpClient =
    OkHttpClient.Builder().apply {
        when (BuildConfig.BUILD_TYPE) {
            "debug", "staging" -> {
                val logging = HttpLoggingInterceptor()
                logging.level = HttpLoggingInterceptor.Level.BODY
                addInterceptor(logging)
            }
            else -> {
                // nop
            }
        }

        addInterceptor(createInterceptor())
        authenticator(認証用Authenticator())
        connectTimeout(Environment.TIME_INTERVAL, TimeUnit.SECONDS)
        readTimeout(Environment.TIME_INTERVAL, TimeUnit.SECONDS)
    }.build()
```
createInterceptor()　の部分で追加

```kotlin
private fun createInterceptor(): Interceptor {
    return object : Interceptor {
        override fun intercept(chain: Interceptor.Chain): Response {
            // パラメータ追加
            val url: HttpUrl = chain.request().url.newBuilder()
                    .addQueryParameter(PARAMETER_NAME, PARAMETER_VALUE).build()

            // 認証トークン、OS Version などをヘッダに追加
            val request = chain.request().newBuilder()
                .header("Authorization", AuthorizeDataStore().accessToken ?: "")
                .header(
                    "x-app-version",
                    "${BuildConfig.VERSION_MAJOR}.${BuildConfig.VERSION_MINOR}.${BuildConfig.VERSION_PATCH}"
                )
                .header("x-os", "android")
                .header("x-os-version", Build.VERSION.RELEASE)
                .url(url)
                .build()
            return chain.proceed(request)
        }
    }
}

```

認証やトラッキングなどのパラメータ、ヘッダ追加を共通化
PHPの設定変更について: .htaccess vs php.ini

# PHP実行モードによる設定値の変更方法の違い

PHPを実行する方法はいくつかあり、それぞれによって設定値を変更するための方法が異なります。この記事では、それぞれの方法とその違いについて説明します。

## はじめに

PHPの設定値を変更するために`.htaccess`ファイルを使用しようとしたところ、500エラーが発生しました。原因を調査したところ、PHPの実行モードが関係していることが分かりました。具体的には、`.htaccess`ファイルを利用して設定値を変更できるかどうかは、PHPがどのように実行されているかによります。この記事では、それぞれの実行モードとその違いについて説明します。

## PHPの設定ファイルについて

PHPの動作に関する設定は、主に`php.ini`ファイルと`.htaccess`ファイルで行います。`php.ini`はWebサーバー全体の設定を管理する一方、`.htaccess`は個々のディレクトリに対する設定を管理します。つまり、`php.ini`はサーバー管理者が、`.htaccess`はアプリケーション開発者がそれぞれ管理することが一般的です。

以下に、`post_max_size`設定を変更する場合の例を示します。`php.ini`で変更する場合、以下のように記述します。

```ini
post_max_size = 40M
```

.htaccessで変更する場合、以下のように記述します。
```htaccess
php_value post_max_size 40M
```

しかし、この設定変更が反映されるか否かは、PHPがどの実行モードで動作しているかによります。Apacheモジュール（mod_php）としてPHPを実行している場合、.htaccessファイルでPHPの設定値を変更することが可能です。一方、FastCGIやPHP-FPMといった実行モードでは、.htaccessファイルでPHPの設定を変更することはできません。つまり、PHPがFastCGIモードで動作している状況で、.htaccessファイルでpost_max_sizeを変更しようとした場合、その設定は反映されないということです。

この事実を踏まえて、PHPの実行モードによる設定方法の違いを以下に記載します。


## PHPの実行モードと設定変更の影響

PHPを実行する方法は主に3つあります。

1. **Apacheモジュール（mod_php）**
2. **CGI（Common Gateway Interface）**
3. **FastCGI**

これらの実行モードによって、PHPの設定値をどのように変更するかが異なります。

### Apacheモジュール（mod_php）

ApacheモジュールとしてPHPを実行する場合、PHPはApacheサーバーの一部として動作します。そのため、`.htaccess`ファイルを利用して設定値を変更することが可能です。しかし、全ての設定値が`.htaccess`から変更可能なわけではなく、設定可能な値は`php.ini`ファイルの設定によります。

### CGI

CGIとしてPHPを実行する場合、`.htaccess`ファイルでの設定変更は利用できません。代わりに、`php.ini`ファイルや、PHPスクリプト内部で`ini_set()`関数を使用することで設定値を変更することが可能です。

### FastCGI

FastCGIとしてPHPを実行する場合、`.htaccess`ファイルでの設定変更は一部の値に対してのみ可能です。具体的には、`php_flag`や`php_value`ディレクティブを使用することができます。しかし、その他の設定値については`php.ini`ファイルや`ini_set()`関数を使用する必要があります。

## 近年の主流：FastCGI

近年では、PHPを実行する方法としてFastCGIやPHP-FPM（FastCGI Process Manager）が多くの環境で主流となっています。主な理由は以下のとおりです：

- **パフォーマンスと効率:** FastCGIはプロセスをプールし、それらを再利用することができます。これにより、新しいプロセスを作成するためのオーバーヘッドが削減され、パフォーマンスが向上します。
- **セキュリティ:** FastCGIを使用すると、PHPプロセスをウェブサーバー（Apacheなど）から分離できます。これにより、PHPスクリプトの問題がウェブサーバー全体に影響を及ぼすリスクが低減されます。
- **柔軟性:** FastCGIは、様々なウェブサーバー（Apache、Nginx、IISなど）で使用することができます。これにより、ウェブサーバーの選択肢が広がります。

一方、Apacheモジュール（mod_php）もPHPを実行する方法として存在します。この方法は設定が比較的簡単で、Apacheの.htaccessファイルからPHP設定を変更できるなどの利点があります。しかし、これらの利点は、パフォーマンスやセキュリティの問題に比べて、一部の状況や用途に限定されることが多いです。

つまり、FastCGIはパフォーマンス、セキュリティ、柔軟性の観点から主流となりつつあります。特に大規模なウェブアプリケーションや高負荷の状況では、FastCGIの利点が活かされます。

## まとめ

以上のように、PHPの実行モードによって設定値を変更する方法が異なります。

## 参考記事

1. [PHP-FPM 環境で .htaccess に php_value を使用したら 500 Internal Server Error](https://crieit.net/posts/php-fpm-php-value-error-20211124)
2. [PHP.iniに設定する設定をhttpd.confや.htaccessに対して行うメリット](http://algorhythnn.jp/blg/2013/10/23/merit-php_value-on-apache/)
3. [LinuxとApacheの.htaccessファイル](https://blog.apar.jp/linux/8208/)
4. [MovableType ドキュメンテーション - Apache + FastCGI で Movable Type を動かす](https://www.movabletype.jp/documentation/mt6/reference/apache-fastcgi.html)
5. [CentOS8 + Apache + PHP の基本的な環境を整える](https://laboradian.com/centos8-apache-php/)
6. [PHPの処理速度を上げるための設定とは？PHP-FPMとmod_phpの違いを解説](https://maasaablog.com/development/backend/php/1295/)
【2023年05月版】Ubuntu22.04 上での DRBD によるストレージレプリケーション 動作確認編

# はじめに

- [【2023年05月版】Ubuntu22.04 上での DRBD によるストレージレプリケーション 構築編](https://qiita.com/nouernet/items/52eb00f766fae0f579ca) の続きです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143127/e2708e2c-99b9-7e8f-5d62-e976cabbe37c.png)

# 前提条件

- 2台の ubuntu 22.04
- Primary を node1、Secndary を node2 とする
- Primary/Secondary 共に /dev/sda をシステム、/dev/sdb をストレージレプリケーションとして利用
- node1 の IPアドレスは 192.168.100.101 とする
- node2 の IPアドレスは 192.168.100.102 とする
- マウント先は /export とする
- すでに、/dev/drbd0 として構築済み

# node1 を　Primary に決定

- node1 で

```terminal
$ sudo drbdadm primary r0
$ sudo drbdadm status r0
$ sudo mount /dev/drbd0 /export
```

# node1 を Primary -> Secondary 、　node2 を Secondary -> Primary

- node1 で

```terminal
$ sudo umount /export
$ sudo drbdadm secondary r0
$ sudo drbdadm status r0
```

- node2 で

```terminal
$ sudo drbdadm primary r0
$ sudo drbdadm status r0
$ sudo mount /dev/drbd0 /export
```

# フォーマットしてみる

- node1 が primary、node2 が secondary
- 元のファイルシステムは xfs、変更先のファイルシステムは ext4
- node1 で

```terminal
$ sudo touch /export/aaa
$ ls /export
aaa
$ df -T
Filesystem                        Type  1K-blocks    Used Available Use% Mounted on
/dev/drbd0                        xfs    20960604  179192  20781412   1% /export
$ sudo umount /export
$ sudo mkfs.ext4 /dev/drbd0
mke2fs 1.46.5 (30-Dec-2021)
/dev/drbd0 contains a xfs file system
Proceed anyway? (y,N) y
Creating filesystem with 5242711 4k blocks and 1310720 inodes
Filesystem UUID: 09cefcc7-a853-49c2-ba03-e405fea00769
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
	4096000

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done   

$ sudo mount /dev/drbd0 /export
$ df -T
Filesystem                        Type  1K-blocks    Used Available Use% Mounted on
/dev/drbd0                        ext4   20465580      24  19400632   1% /export
$ ls /export
lost+found
$ sudo touch /export/aaa
$ time sudo dd if=/dev/random of=/export/abcd bs=100M count=20
20+0 records in
20+0 records out
2097152000 bytes (2.1 GB, 2.0 GiB) copied, 10.678 s, 196 MB/s

real	0m10.688s
user	0m0.002s
sys	0m0.004s
$ md5sum /export/abcd
c5deb3807e7b3859afd2bb43558ec5f3  /export/abcd
$ ls /export
aaa  abcd  lost+found
$ sudo umount /export
$ sudo drbdadm secondary r0
```

- node2 で

```terminal
$ sudo drbdadm primary r0
$ sudo mount /dev/drbd0 /export
$ ls /export
aaa  abcd  lost+found
$ md5sum /export/abcd
c5deb3807e7b3859afd2bb43558ec5f3  /export/abcd
```

# さいごに

- かんたんでしたね

# 参考
[Ubuntu 22.04 man page drbdadm](https://manpages.ubuntu.com/manpages/jammy/ja/man8/drbdadm.8.html)
[Ubuntu 22.04 man page drbd](https://manpages.ubuntu.com/manpages/jammy/ja/man8/drbd.8.html)

[DRBD9 ユーザーズガイド](https://linbit.com/drbd-user-guide/drbd-guide-9_0-ja/)
[LINSTOR ユーザーズガイド](https://linbit.com/drbd-user-guide/linstor-guide-1_0-ja/)
循環参照が起きてはいけない理由

### 循環参照とは
循環参照（またはretain cycle）は、二つ以上のオブジェクトが互いに強い参照を持ち、それらがメモリから解放されることがない状態を指します。

### これが問題となる主な理由は以下の通り

- **メモリリーク**
循環参照が発生すると、参照されているオブジェクトはメモリから解放されません。この結果、使用されなくなったオブジェクトがメモリを占有し続け、メモリリークが発生します。これが長期間続くと、アプリケーションのパフォーマンスが低下し、最終的にはアプリケーションがクラッシュする可能性があります。

- **不必要なオブジェクトの保持**
循環参照が発生すると、不必要なオブジェクトがメモリ内に残り続けます。この結果、それらのオブジェクトの状態が更新され続ける可能性があります。これは予期しない挙動を引き起こす可能性があります。

- **データの整合性**
循環参照が発生した場合、オブジェクトのライフサイクルが適切に管理されない可能性があります。オブジェクトがメモリから解放されるタイミングが明確でないと、データの整合性を保つことが難しくなります。

### まとめ

これらの理由から、Swiftでは通常、強い参照の代わりに弱い参照や非所有参照（unowned reference）を使用して循環参照を避けます。
わざわざ市販ツールを利用して工数管理をする意味を考える


![people-690810_640.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3458152/b595baf9-2830-71e3-e477-8536810b0495.jpeg)

## 工数管理ツールを使う意味

工数管理ツールは、プロジェクト管理において不可欠なツールの一つです。工数管理ツールを使用することで、プロジェクトの進行状況を正確に把握することができ、従業員のスケジュールやタスクの割り当てを管理することができます。以下に、工数管理ツールを使用するメリットを詳しく説明します。

## 管理の容易性

工数管理ツールを使用することで、従業員の作業時間を簡単に追跡することができます。従業員がどのプロジェクトに時間を使っているか、どのタスクが最も時間を要しているかをすばやく確認することができます。これにより、プロジェクトの進行状況を把握し、従業員のスケジュールやタスクの割り当てを管理することができます。また、従業員がどのプロジェクトに時間を使っているかを把握することで、プロジェクトの優先度を正確に把握することができます。

## フィードバックの改善

工数管理ツールは、従業員が作業に費やした時間を正確に記録することを可能にします。これにより、プロジェクトの見積もりをより正確に行い、将来のプロジェクトの計画を改善することができます。また、従業員は自分がどのような作業に時間を費やしているかを把握することができ、自分自身の仕事スタイルを改善することができます。さらに、従業員が実際に費やした時間を正確に把握することで、プロジェクトの問題点を特定することができ、改善策を提案することができます。

## 課題の追跡

工数管理ツールは、プロジェクトの課題を簡単に追跡することができます。従業員がどのタスクに時間を費やしているかをすばやく確認することができ、課題を特定し、解決策を提供することができます。これにより、プロジェクトの品質を向上させることができます。また、課題の解決にかかる時間を正確に把握することができるため、将来のプロジェクトの計画を立てる際に役立ちます。

## プロジェクトの進行状況の可視化

工数管理ツールは、プロジェクトの進行状況を簡単に可視化することができます。従業員がどのタスクに時間を費やしているかをすばやく確認することができ、プロジェクトの進行状況を把握することができます。これにより、プロジェクトのスケジュールを管理し、問題が発生した場合には早期に対処することができます。また、プロジェクトの進行状況を可視化することで、チーム全体がプロジェクトの進捗状況を共有することができます。

## 経費の削減

工数管理ツールを使用することで、プロジェクトのコストを削減することができます。従業員の作業時間を正確に追跡することで、プロジェクトの見積もりをより正確に行うことができます。また、プロジェクトの進行状況を把握することで、プロジェクトのスケジュールを管理し、余分な時間を費やすことを防ぐことができます。さらに、工数管理ツールを使用することで、従業員が無駄な時間を費やすことを防ぎ、プロジェクトのコストを削減することができます。

## まとめ

工数管理ツールを使用することで、プロジェクト管理が容易になります。従業員の作業時間を正確に追跡することで、プロジェクトの見積もりが正確になり、プロジェクトの進行状況を可視化することができます。また、従業員がどのプロジェクトに時間を使っているかを把握することで、プロジェクトの優先度を正確に把握することができます。以上の理由から、工数管理ツールは、組織にとって非常に有用であると言えます。
Javaを使うためにJDKをインストールしたい

<h1>JDKとは</h1>

JDK（Java Development Kit）は、Javaで開発を行うために使用されるソフトウェアパッケージです。JDKには、Javaプログラムのコンパイル、デバッグ、実行などを行うためのツールやライブラリが含まれています。

## 目的
Javaで開発をするためには、JDKが必要不可欠なので、今回はMacでJDKをダウンロード、インストールすることが目的になります

## JDKが未インストールか確認する

次のコマンドはJavaコンパイラのバージョンを確認するコマンドです
```
$ javac -version
```
### JDKにはjavaコンパイラが付属されている

JDKがインストールされているかどうかを確認するコマンドは見つかりませんでしたが、JDKをインストールするとjavaコンパイラが使用可能になっているため、javaコンパイラのバージョンが確認できない場合はJDKがインストールされていないと同義になります

## JDKのダウンロード

https://www.oracle.com/jp/java/technologies/downloads/

![スクリーンショット 2023-05-27 10.52.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/06a3a319-52b4-de16-18a3-c06da644468e.png)


リンク先からJDKのダウンロードが可能です
今回、最新バージョンがJDK20だったので20をインストールします

JDKのダウンロードファイルはPCのOSやスペックによってリンク先が変わります

### ARM64とかx64とか何を選べばいいのか

ARM64版とx64版が存在しますのでPCのアーキテクチャを次のコマンドで調べることでどのリンク先を選択すれば良いかがわかります
```
uname -m
```

著者の実行結果では`x86_64`だったので`x86_64アーキテクチャを持つMac`ということがわかりました。そうなるとこの場合Intelのx86アーキテクチャの64ビット版が最適解になります。理由としてはx86_64アーキテクチャは一般的にx64とも呼ばれていますので、x64を選びました

`Compressed Archive`と`DMG Installer`ですが、あくまでどのような形式でファイルをダウンロードするかを示しているだけなので、結果的にはどちらもJDKパッケージが入っているのでどちらを選択しても問題ありません。

違いとしては`Compressed Archive`はファイルが圧縮された状態なので、ダウンロード後は解凍してからJDKファイルをダブルクリックしてインストールを実行するという手間があること、`DMG Installer`はMacでしか開けないファイルをダウンロードすることを意味しており、お使いのOSがMacならばダウンロードしたファイルをダブルクリックしてすぐにJDKのインストールを始めることができます。

つまりはARM64か、X64なのか、ここだけ注意すればどちらの手段でインストールしても問題なさそうです。

## JDKインストール

![スクリーンショット 2023-05-27 11.19.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/627c7b48-a530-8a05-fe87-83e1f175b37b.png)

![スクリーンショット 2023-05-27 11.21.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/5b9eee33-c873-2a53-d59f-a0c354ceb46b.png)


ダウンロードしたファイルを開くとJDKのインストールが始まります。特に選択することもなく"続ける"ボタンを押すだけなので簡単でした

### ARM64とかx64とかどれを選べばいいのか

もう一度JDKがインストールされているかJavaコンパイラのインストール具合で確認します

```
$ javac -version

javac 20.0.1
```

javacのバージョンが確認できたのでどうやらJDKのインストールは正常に実施できたようです

## JDKの環境変数を設定する

JDKをインストールしましたが、MacやWindows等でJDKを使えるようにするためにはOSに対してJDKがインストールされている場所を伝える必要があります。

環境変数を設定することで、システム（あなたのコンピュータ）に対してJDKの存在とパスを知らせることができ、これによりシステムはJDKのインストール場所を特定し、JDKに含まれるコマンドやライブラリにアクセスすることができるようになります。

### Macで環境変数を設定する場合
・ターミナルで次のコマンドを実行します

```bash
$ nano ~/.bash_profile

```

・テキストエディタに以下の行を追加します
（JDKのバージョンに応じてパスを適切に修正する必要があります）
```java
テキストに追加する内容
export JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk-<version>.jdk/Contents/Home"
export PATH="$JAVA_HOME/bin:$PATH"

```

・テキストエディタで Control + O を押した後、エンターキーで保存し、Control + X を押してテキストエディタを終了します。
・ターミナルで以下のコマンドを実行し、変更を反映させます

```bash
$ source ~/.bash_profile

```

### JDKのパッケージパスを調べる

Macの場合、JDKのデフォルトのインストール先は次でした

`/Library/Java/JavaVirtualMachines/`

![スクリーンショット 2023-05-27 14.28.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/fe6f1cc1-9b1e-8027-1e59-a29fa339c530.png)

よって環境変数に記述するパスは次のようになりました
```
/Library/Java/JavaVirtualMachines/jdk-20.jdk/Contents/Home
```

## 動作確認

javaとjavaコンパイラをもう一度確認します。
結果、正常に表示できたのでJDKのインストールは完了になります

```
$ java -version

$ javac -version
```
もしも、別のバージョンに切り替えた場合など、バージョンが更新されない場合は、一度ターミナル（コマンドプロンプト）を終了し、再度開き直してから実行してください
2019年くらいの 「Windowsプログラムでディレクトリ丸ごと削除」 3/4

シリーズもの一覧

1/4 https://qiita.com/macchan/items/30d81c4cb66a52fe4b0b
2/4 https://qiita.com/macchan/items/282db3e735ed0ad4bed8
3/4 https://qiita.com/macchan/items/19a06f30e8f3c553d4cb
4/4 https://qiita.com/macchan/items/9853a6d7b4e01ad4dc8d


SHFileOperationA, SHFileOperationW を見ると

> This function has been replaced in Windows Vista by IFileOperation.

と書いてあります。訳すと「Windows Vista で IFileOperation に置き換えられた」で、つまり SHFileOperation は「いつ使えなくなるかわからない」ということになります。
　Windows Vistaは(Wikipediaで調べました)2006年ですからもうかれこれ20年前になります。
　筆者の環境はVisualStudio 2019で、SHFileOperation はまだ使えていますが、モノは試しに書いてみましょう。

IFileOperation インターフェースのプログラムサンプルは以下にあります。

https://learn.microsoft.com/ja-jp/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifileoperation-copyitem?redirectedfrom=MSDN

かなり長くなりました。\<atlcomcli.h\> を includeすると スマートポインタ CComptr が使えて少しはマシになりますが、それでも「たかがディレクトリを削除するのにCOMインターフェースを使うのか」というのが素直な感想です。あ、これも読み取り専用属性を無視して削除します。いやはや。

```C++:main.cpp

#include    <iostream>

#include    <windows.h>
#include    <shobjidl_core.h>

#include    <locale>

int main()
{
    setlocale(LC_ALL, "Japanese");

    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    IShellItem* psiTarget = NULL;

    if(FAILED(hr)) {
        std::cout << "COM初期化失敗" << std::endl;
        return -1;
    }

    // インターフェース インスタンス生成
    IFileOperation* pFileOp;
    hr = CoCreateInstance(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pFileOp));
    if (FAILED(hr)) {
        std::cout << "IFileOperation インターフェース失敗" << std::endl;
        goto End01;
    }

    hr = pFileOp->SetOperationFlags(FOF_NO_UI);
    if (FAILED(hr))
    {
        std::cout << "SetOperationFlags 失敗" << std::endl;
        goto End01;
    }

    hr = SHCreateItemFromParsingName(L"D:\\Work\\Dir", NULL, IID_PPV_ARGS(&psiTarget));
    if (FAILED(hr))
    {
        std::cout << "SHCreateItemFromParsingName 失敗" << std::endl;
        goto End02;
    }

    // 準備(宣言)
    hr = pFileOp->DeleteItem(psiTarget, NULL);
    if (FAILED(hr))
    {
        std::cout << "DeleteItem 失敗" << std::endl;
        goto End03;
    }
    // 削除実行
    hr = pFileOp->PerformOperations();
    if (FAILED(hr))
    {
        std::cout << "PerformOperations 失敗" << std::endl;
        goto End03;
    }

    std::cout << "Delete 成功" << std::endl;

End03:
    if (psiTarget) {
        psiTarget->Release();
        psiTarget = NULL;
    }

End02:
    if (pFileOp) {
        pFileOp->Release();
        pFileOp = NULL;
    }

End01:
    // COMの後始末
    CoUninitialize();

    return 0;
}


```
WiMAXルーターを他社SIMで使えるようにする方法

SIMフリーのWiMAXルーターを他社SIMで使用する場合APN設定が必要です

Galaxy 5G Mobile Wi-FiをRakuten UN-LIMIT VIIのSIMで使用する場合の例

ルーター側に楽天のAPN設定を追加する
ホーム→通信設定→APN→追加

以下の設定を入力
名前：rakuten
アクセスポイント名：rakuten.jp
ユーザー名：ブランクでOK
パスワード：ブランクでOK
認証：Auto
PDN：デフォルト値
以上

参考情報
https://network.mobile.rakuten.co.jp/faq/detail/00001495/
https://mobilewifi-real.com/rakuten-mobile/
https://mobilewifi-real.com/galaxy-scr01/
2019年くらいの 「Windowsプログラムでディレクトリ丸ごと削除」 2/4

シリーズもの一覧

1/4 https://qiita.com/macchan/items/30d81c4cb66a52fe4b0b
2/4 https://qiita.com/macchan/items/282db3e735ed0ad4bed8
3/4 https://qiita.com/macchan/items/19a06f30e8f3c553d4cb
4/4 https://qiita.com/macchan/items/9853a6d7b4e01ad4dc8d

　DemoveDirectory を調べていくと、以下のような記載を見つけました。

> ディレクトリ内のファイルを再帰的に削除するには、 SHFileOperation 関数を使用します。

https://learn.microsoft.com/ja-jp/windows/win32/api/fileapi/nf-fileapi-removedirectorya
https://learn.microsoft.com/ja-jp/windows/win32/api/fileapi/nf-fileapi-removedirectoryw

はい。書きました。面倒になっています。
「読み取り専用」属性のファイルもディレクトリも消える凶悪さです。

```C++:main.cpp
#include	<iostream>
#include	<Windows.h>

int main()
{
	SHFILEOPSTRUCT	op;
	op.hwnd = NULL;
	op.wFunc = FO_DELETE;
	op.pFrom = L"D:\\Work\\Dir";
	op.pTo = NULL;
	op.fFlags = FOF_NO_UI;
	// op.fAnyOperationsAborted このメンバは出力に使用される
	op.hNameMappings = NULL;
	op.lpszProgressTitle = NULL;

	int nResult = SHFileOperation(&op);
	std::cout << nResult << std::endl;

	return 0;
}

```
AtCoder水色になった話

AtCoder Beginner Contest (ABC 302)で水色になりました！

他の人の「AtCoder  ◯色記事」を読むと他の人の考えが知れて面白いなと思ってたので、水色になるまでに大事だなと思ってたことを書いていこうと思います。

![スクリーンショット 2023-05-22 11.25.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600812/b4cd0f87-339f-60d6-4938-f74a80dfc4c5.png)

![スクリーンショット 2023-05-22 11.38.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600812/90252ab3-241c-54cc-2102-0c17226abf59.png)
![スクリーンショット 2023-05-22 11.37.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600812/65dbea86-4f8b-a376-c0a4-f151800252ee.png)

そもそもAtCoderって？という方はこちら↓ 適当なコンテストの問題を見てみるとどんなものか分かるかと思います。
https://atcoder.jp

水色ってどれくらいなのって方はこちら↓
https://chokudai.hatenablog.com/entry/2019/02/11/155904


# 始めたきっかけ
始めたきっかけは大学の授業(情報系)で紹介されて、水色くらいまではやっておくとエンジニアとかやるならいいよということだったので、そんなもんかと思い始めました。

言語はC++を使っていて、競プロを始めるにあたって授業の参考書として買ってあった本(「問題解決力を鍛える！アルゴリズムとデータ構造」)がC++で書かれていたというだけの理由ですが今としてはいい選択だったなと思ってます。

# やったこと(教材等)
大体時系列順に書きます。

APG4b: https://atcoder.jp/contests/APG4b
AtCoderの中にあるC++の入門用教材。C++で競プロを始めるなら当然おすすめだしそうでなくてもC++の初学にとてもいいと思う。ちょっと書き方が堅いところもある気がするが手元の環境がなくても無料で気軽に始められるのでとてもいい。

AtCoder Beginners Selection: https://atcoder.jp/contests/abs
始めたばかりの人におすすめの8問。下の記事にわかり易い解説がある。
https://qiita.com/drken/items/fd4e5e3630d0f5859067

大槻兼資 . 問題解決力を鍛える！アルゴリズムとデータ構造 . 講談社 , 2020.
通称けんちょん本。詳しくていいのだが初学者がやるには難しいと思う。基本的なアルゴリズムの部分だけやったが演習問題が難しすぎて全然できなかった。

ーーーー緑色~ーーーー
精選100: https://qiita.com/e869120/items/eb50fdaece12be418faa
この100問を各単元についてネットで調べて勉強して解いていった。とても教育的な問題が揃っているがすごく難しい問題もちょくちょくあるので2時間くらいまたは数日置いて考えても分からないなら解説見て学んだほうがいいと思う。

米田 優峻 . 競技プログラミングの鉄則 ~アルゴリズム力と思考力を高める77の技術~ . マイナビ出版,2022
通称鉄則本。カラーでわかりやすく網羅性も高くいい。買った時点で7割方本の中の知識はあったがそれでもかなり勉強になり力がついた気がする。著者は精選100の制作者でもある。


# レートを上げるために
レートを上げるためにやってよかったこととか考えてたことを書きます。

## コミュニティに参加する
コミュニティに参加するとモチベの維持ができたり新しい知識が知れたりします。私自身、大学の競プロサークルに参加したことでC++の知らなかった知識を教えてもらったり、ICPCに参加したお陰でモチベが保てたりしました。
 他にもAtCoderProblemsのVirtualContest(通称 バチャ)とかもコミュニティと言えるかわかりませんが他の人がやってるのを感じながらできるので刺激になって結構いいです。

## 1色上の問題を逃げずに解く
私は緑になってから長らくDifficultiy(diff)が水色相当の問題を避けていたのですが、後から見るとこれはだいぶ成長の妨げになってたなと思ってます。避けていた理由としてはできない問題が多く、その解説を見てしまうことに抵抗があったからでした。しかし、ある程度覚えゲー要素の多い競プロにおいて解説をなかなか見ないというのはABCの範囲ではあんまり良くないのかなと最近は思ってます。
競プロフレンズさん(@kyopro_friends)もよくマシュマロの回答でABCは解説ACして先に進んだほうがいいよと言ってます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">サーバル「ABCの範囲なら早めに解説を見てもいいし、質より量でいいと思うよ。私たちが書いた記事も参考にしてね」<a href="https://t.co/fqROHRSE31">https://t.co/fqROHRSE31</a></p>&mdash; 競技プログラミングをするフレンズ (@kyopro_friends) <a href="https://twitter.com/kyopro_friends/status/1638477835697553408?ref_src=twsrc%5Etfw">March 22, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

分からなかったら解説を見ると言っても、最近自分がやってるやり方としては解説をちらっとだけ見るというのがあります。やり方としては、解説をざっと見て方針だけ理解して実装してみるというものです。感覚的にはABCの後Twitterで◯問題はBFSで~とか方針を他の人が言ってるのをヒントに解くのと近いかなと思ってます。このやり方のいい点は方針だけ知って自分で考えて実装することで実装力がつくことや方針に対しても吟味＆理解が進むという点です。自力で解ききるほどではないですが、方針を知ってから解けても結構うれしいのでやったことない方はぜひやってみてください。



# おわりに
読んでいただきありがとうございます。競プロを初めて１年ちょっとが経ち、始めた当初は水色になったら辞めようと思ってたのですが、今が一番やる気があるので青色目指して頑張ろうと思います。
JAVA_HOME should point to a JDK not a JREエラーが出る

# はじめに

普段はIntellijのJava環境を利用していますが、ターミナルからテストを実行することがあり、そこで遭遇したエラーが特殊だったのでまとめます

# 問題

mavenコマンドを実行したところ以下のエラーが発生しました

```
watanabejin@watanabejin:~/workspace/test$ mvn -version
The JAVA_HOME environment variable is not defined correctly
This environment variable is needed to run this program
NB: JAVA_HOME should point to a JDK not a JRE

```

JAVA_HOMEの環境変数が設定されていないようなので確認してみました

```
echo $JAVA_HOME
/home/watanabejin/.asdf/shims/java
```

環境変数には設定がされていそうでした (asdfが勝手にやってくれてるっぽい)

# 解決方法

asdfが設定したJAVA_HOMEの場所がおかしかったのが問題でした

本来は以下のパスになるので、そこを設定することで治りました

```
watanabejin@watanabejin:~/workspace/test$ export JAVA_HOME=/home/watanabejin/.asdf/installs/java/corretto-19.0.2.7.1
```

`/home/watanabejin/.asdf/installs/java`以降にあるバージョンを設定するはずなのが変な場所が設定されていました

# おわりに

あまりネットで調べても見ないつまづきかただったので簡単にまとめました
お名前.comにRoute53のNSレコードを登録してみました

# はじめに
実務の勉強用に検証用のドメインが必要になり、初めてお名前.comでドメインを購入しました。
本記事はお名前.comでドメイン購入して、Route53のNSレコードをお名前.comに登録したため記事にしました。

以下の記事を参考にしました。
https://tech-broccoli.life/articles/engineer/setting-onamae-domain-for-route53

# 手順
### お名前.comにログインする
### Topを選択してドメイン名のネームサーバー「その他」をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/214de0d2-5a67-2373-cef7-3f0c5e769c62.png)



### ネームサーバーを設定する

Route53のホストゾーンのNSレコードをコピーする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/6a1cb8f2-4766-ab8b-0b6a-a277f4945663.png)

NSレコードは4つです。
ns-*******.co.uk.
ns-847.*********.net.
ns-1040.*********.org.
ns-199.*********.com.

赤枠のネームサーバー情報にてRoute53のNSレコードを張り付けて、対象ドメインにチェックを入れて「確認画面に進む」をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/8fc4aced-ed34-7837-9bf0-967bae987cc4.png)


以下のメッセージが出ます。
**ネームサーバーの後ろの「.」を削除しました。
Route53からコピーする際は末尾に「.」が付いているため注意**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/8b0a43a3-9f79-006d-76f0-6bafadfc1354.png)


「設定する」ボタンを押下して登録完了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/4a5dea53-7c8e-be04-9f41-dff5dd5fe6f3.png)


ドメインを選択してネームサーバー情報がRoute53のNSレコード情報になったことを確認しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/742f29c6-bf29-6d71-6e6c-d0e05411d8e6.png)
[入門] Flask + Bootstrapで爆速でweb装飾する

## ディレクトリ構造
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738475/9e66e37f-290e-7999-91ac-a1c8c977eaef.png)

## 事前準備

### CSSとJSをダウンロード
下記から、CSSとJSをダウンロードする

https://github.com/twbs/bootstrap/releases/download/v5.0.2/bootstrap-5.0.2-dist.zip

### staticの作成
ダウンロードしてきたCSSとJSを上記のディレクトリ構造の様に、static配下に配置する。

### head.html
staticに紐づけるために、以下のタグをhead.htmlのheadタグに入れる。

```
<link rel="stylesheet" href="static/css/bootstrap.css">
  <script type="text/javascript" src="static/js/bootstrap.bundle.min.js"></script>
```

## 実際に装飾していこう
### bootstrapのwebページへ

https://bootswatch.com/quartz/


### 背景の配置
欲しいテーマのサイトで開発者モードを開き、ページ全体が選択される場所を探す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738475/57764cf9-4441-35f1-8576-bef85d7eac31.png)

スタイルタブの所を見る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738475/233c21ec-6aea-c1f3-b58a-7deaa3851efd.png)

head.htmlの<body>タグに以下を挿入
```
body {
    background-image: linear-gradient(90deg, #33b7e2, #5e62b0, #dc307c);
}
```



### 欲しい装飾の選択・コピー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738475/8af4a7d7-26f9-4b13-e9ac-93dc77558867.png)


### head.htmlのbodyに上記のコードを挿入
```
<body>

#### ここにいれる

</body>
```


### webページへアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738475/7950cf9b-7aef-ab79-1de8-07fecef9e9ed.png)

おおおお！ヘッダーが出来てます

## themaが正しく反映されない場合
### HeaderからCSSをダウンロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738475/7688fe0b-f07b-3589-9fbe-23acb8bb170a.png)

### ダウンロードした物をstatic配下に配置
```
cd static
wget https://bootswatch.com/5/quartz/bootstrap.min.css
wget https://bootswatch.com/5/quartz/bootstrap.css
```


##### 参考サイト
https://getbootstrap.jp/docs/5.0/getting-started/introduction/
Nextjsでフルスタックアプリ開発！Docker環境編

# 目標と前提環境

## 今回の目標

`create-next-app`を行うためのDocker環境を用意

create-next-appに関しては以下を参考に。

https://nextjs.org/docs/getting-started/installation

## 前提環境

PC : mac

利用ライブラリー
1. docker
2. docker-compose

# 始めましょう。


## 前提環境のチェック

まずは次のコマンドが動作するか確認しましょう。

```
docker -v

Docker version 20.10.13, build a2233s222
```

```
docker-compose -v

docker-compose version 1.29.2, build 5bec333111
```

エラーが出る場合はdockerとdocker-composerをインストールしましょう。

dockerのインストール

https://docs.docker.com/desktop/install/mac-install/

docker-composeのインストール

https://docs.docker.jp/v1.12/compose/install.html

## 環境構築

では、docker環境を構築します。

### セットアップ内容

- Nodejs v16.x

### ディレクトリ構成

```
.
├── README.md
├── app
├── docker
│   └── Dockerfile
└── docker-compose.yml
```
`app`ディレクトリは今後nextjsのコードが入って来ます。作成しておいてください。
まずは、上の構成の通りファイルを配置しましょう。

Dockerfile
```
FROM node:16-alpine
LABEL app="nextjs-fullstack-app-qiita"
WORKDIR /app
COPY . .
EXPOSE 3000
```

`LABEL app="nextjs-fullstack-app-qiita"`の部分はお好きな名前をどうぞ。

docker-compose.yml
```
version: "3.8"
services:
  frontend:
    build: ./docker
    volumes:
      - ./app:/app
    working_dir: /app
    ports:
      - 3000:3000
    tty: true
    stdin_open: true
    environment:
      - CHOKIDAR_USEPOLLING=true
```

### Dockerコンテナ立ち上げ

次のコマンドでdockerコンテナを作成します。

```
docker-compose up -d
```

コンテナの中に入ってNodejsがセットアップされているか確認しましょう。
`sh`の部分はあなたの環境にあったコマンドを渡しましょう。`docker-compose exec frontend bash`になることが多いでしょうか。

```
docker-compose exec frontend sh
node -v
v16.20.0
```

`v16.20.0`と表示されればおkです。

以上になります。
Laravel artisan コマンド

# artisanコマンド
artisanコマンドは意外と毎回ググったりしてるのでまとめました。
このコマンドも追加してほしい！！ってのがあったり、ご指摘があればコメントしてください。

## make
```php
// コントローラー
php artisan make:controller SampleController
php artisan make:controller SampleController --invokable  //single actionコントローラー
php artisan make:controller SampleController --resource   //resourceコントローラー

// モデル
php artisan make:model Sample
php artisan make:model Sample --factory    //factoryファイルも生成される
php artisan make:model Sample --migration  //migrationファイルも生成される
php artisan make:model Sample --policy     //policyファイルも生成される
php artisan make:model Sample --seed       //seederファイルも生成される
php artisan make:model Sample --resource   //resourceコントローラーも生成される
php artisan make:model Sample --all        //上記ファイルに加えFormRequestファイルも生成される

// マイグレーション
php artisan make:migration create_sample_table

// フォームリクエスト
php artisan make:request SampleRequest

// 独自ルール
php artisan make:rule SampleRule

// シーダー
php artisan make:seeder SampleSeeder

// テスト
php artisan make:test SampleTest         // Feature配下に生成される
php artisan make:test SampleTest --unit  // Unit配下に生成される

// リソース
php artisan make:resource SampleResource

// メール
php artisan make:mail SampleMail

// ミドルウェア
php artisan make:middleware SampleMiddleware

// コマンド
php artisan make:command SampleCommand

// ポリシー
php artisan make:policy SamplePolicy

// ファクトリー
php artisan make:factory SampleFactory

// ジョブ
php artisan make:job SampleJob
```

## その他のコマンド
```php
// APP_KEYの生成
php artisan key:generate

// シンボリックリンク
php artisan storage:link

// tinker起動
php artisan tinker

// マイグレーション実行
php artisan migrate
php artisan migrate:rollback  // 最後のmigrationをロールバック
php artisan migrate:reset     // 全てのmigrationをロールバック
php artisan migrate:refresh   // 全てのmigrationをロールバック後migrationを実行
php artisan migrate:fresh     // 全てのテーブルを削除後migrationを実行
php artisan migrate:fresh --seed     // 全てのテーブルを削除後migrationを実行し、Seeder実行

// シーダー実行
php artisan db:seed
php artisan db:seed --class SampleSeeder  // 特定のSeederを指定して実行

// キューの実行
artisan queue:work
artisan queue:work --queue=queueName  // 名前付きqueueを実行

// スケジュールをローカルで実行
php artisan schedule:work

// テストの実行
php artisan test                             // 全てのテスト実行
php artisan test tests/Unit/SampleTest.php   // ファイルを指定して実行

// ファイルの自動読み込み
composer dump-autoload  // artisanじゃないけど

// 最適化（ファイルのリネームをしたり手動でControllerなどを作成した際）
php artisan optimize

// キャッシュクリア
php artisan cache:clear
php artisan config:clear
php artisan config:cache
php artisan route:clear
php artisan view:clear

// vender publish
php artisan vendor:publish --tag=laravel-errors      // エラー用のblade生成(404など)
php artisan vendor:publish --tag=laravel-pagination  // ページネーションデザインのblade生成
php artisan vendor:publish --tag=laravel-mail        // メールテンプレートのblade生成
php artisan vendor:publish --tag=sanctum-migrations  // sanctum用のmigration生成

// stabファイル生成
php artisan stub:publish

// langディレクトリ作成
php artisan lang:publish

// ルート確認
php artisan route:list


```

https://artisan.page/
エラー日記(name error編)

name error発生

![スクリーンショット 2023-05-26 14.20.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3354671/07408149-b418-c98a-8506-607e2226365e.png)


controllers/post_controllers

```ruby
class PostsController < ApplicationController
  def index
    posts = Post.all
  end

  def new
    @post = Post.new                                         #controllerでデータを作りviewからブラウザ表示
  end 

  def create
    Post.create(post.params)
    redirect_to new_post_path                                 #newメソッド
  end
  
private                                                       #予期せぬところからblog_paramsを呼び出せないようにするため

  def post.params
    params.require(:post).permit(:content)                    #送られてきたデータをパラメーターで取得
  end
end
```

def post.paramsじゃくて、post_params？

直したら、

![スクリーンショット 2023-05-26 14.28.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3354671/c280b761-c62c-6884-e9f1-c81ce6ee6d2d.png)

別のエラー発生

実は、def post.paramは直したが、Post.create(post.param)を直してなかった。

直すと？

![スクリーンショット 2023-05-26 14.31.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3354671/65640f3a-2ea2-ac03-c574-79e7d577c36e.png)

直りました！

単純なミスでしたが、コード量が多くなるとこういったことが原因でも見抜きにくくなるので、気をつけたいです。
amplifyでjestを使用した時のwindow.URL.createObjectURLエラー

# 解決方法
src配下のsetupTests.jsに以下のように記載する。
```js
import {jest} from '@jest/globals';
if(typeof window.URL.createObjectURL === 'undefined'){
    window.URL.createObjectURL = jest.fn()
}
```
## 参考記事
- [import 'useAuthenticator' from aws-amplify outputs "TypeError: window.URL.createObjectURL is not a function" when jest testing](https://stackoverflow.com/questions/74063650/import-useauthenticator-from-aws-amplify-outputs-typeerror-window-url-create)
Pardot のレポート


+ [Pardot user reports](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000QLtEXSA1)

Pardot でユーザーレポートを作成してロール、メール、ログイン、プロスペクトを表示したり、これを毎日、毎週購読したりすることはできますか?

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/d37a3eee-eb0b-4404-2d54-c0fe85650c8d.png)


標準レポートは利用できませんが、MCAE (別名 Pardot API) を使用できます。 
https://developer.salesforce.com/docs/marketing/pardot/guide/user-v5.html

スクリーンショットの Pardot ビューを Pardot で直接フィルタリングすることはできませんが、右上に [ツール] ボタンがあるため、表示されたデータを CSV エクスポートして、Excel などでフィルタリングすることができます。

API は Pardot のすべてのライセンス (および Classic と Lightning) で利用できますが、違いは 1 日あたりの呼び出し数のみです。
BizRobo!である時間になったら処理を止める～時間判定や時間取得～

就業先で、RPAツールのBizRobo!を使用しています。BizRobo!開発で悩み、BizRobo!ナレッジベースで色々と検索しています。

BizRobo!である時間になったら処理を止めるように開発したかったのですが、中々上手く作れませんでした。時間判定や時間取得について、BizRobo!ナレッジベースで調べても、解決策が見つかりませんでした。
今回は、BizRobo!である時間になったら処理を止める方法について、共有いたします。

※間違っている箇所や不適切な表現があるかもしれませんが、その時は都度修正いたしますので、ご指摘いただけると幸いです。


## BizRobo!でやりたかったこと
今回の記事を書こうと思ったきっかけは、開発現場でのある要望から始まりました。
RPAでデータ移行をやってほしいという依頼がありました。AシステムからBシステムにデータを移行することはできたのですが、Aシステムのデータに紐づいていたファイルまでBシステムに移行できなかったようでした。

下記図で説明します。
```
　Aシステム
　　データAーファイル1、ファイル2
　　データBーファイル3
　　　　↓
　Bシステム
　　データA
　　データB
```

Bシステム内にあるデータに、ファイル1、ファイル2、ファイル3を紐づける必要がありました。その紐づけ作業をRPAでやってほしいという依頼となります。

上記依頼は可能でした。紐づけ作業は夜から始める計画でしたが、それでも翌朝までかかってしまうことがわかりました。
Bシステムは日常の業務で使用しているため、データ移行作業で日常業務に支障がでるのを避けたいと要望がありました。そのため、翌朝7時以降までRPAが動いていた場合、停止させる必要がありました。

MCで停止させる方法は残念ながらありませんでした。MCではスタート時刻しか設定できません。
RPAの時間を短くすることも考慮しましたが、どうしてもできなかったため、翌朝7時過ぎたらRPAを停止させる処理を考えることになりました。


## 実装内容
今回開発したステップは下記の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955689/3385c5f9-5741-cbec-964d-ca791a2d2fe0.png)

ポイントは下記の通りです。

:::note
- Interger型を用いる
- now()関数で付随するハイフンやコロンを削除する
- 数値として比較する
:::

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955689/dc61af26-7e11-5b37-e687-ae4eb4b1ce3b.png">

現在時刻を取得することは、now()関数でできます。そのため、日付型変数で対応しようと思いましたが、対応できる関数やステップがありませんでした。
そのため、Interger型で比較することにしました。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955689/22ba3118-0faa-0bb6-57cf-63acbc313b23.png">

now()関数で取得すると、ハイフンやコロンが邪魔なので、削る必要がありました。そのため、パターン置き換えで削り、現在時刻用の変数に格納しました。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955689/8515f759-c5a4-ffee-a752-abe46fe13d81.png">

停止時刻は翌日の朝7時だったので、1日加算しました。停止時刻も同様にパターン置き換えで削り、停止時刻用の変数に格納しました。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955689/fc417300-92b6-1475-4d00-c1ec1a061604.png">

Interger型で比較することで、処理を分岐させ、STOPで停止させることができました。

実装内容は以上になります。
下記ナレッジベースも参考にしましたので、ご確認ください。
[現在の日付/時刻を取得する](https://knowledge.bizrobo.com/hc/ja/articles/360054288052)
[日付や時刻の間隔を計算する](https://knowledge.bizrobo.com/hc/ja/articles/10083831602841)


## 最後に
BizRobo!である時間になったら処理を止める方法について、解説いたしました。BizRobo!のeラーニングでDSにおける開発について座学で学びましたが、現場でしか経験できない開発ができました。

時刻を判定し、処理を停止することが思った以上に難航しました。変数を日付型にすることにこだわってしまい、数値型で比較することが思い浮かびませんでした。今回と同じことで悩んでいる人の為になれば幸いです。

今後もBizRobo!開発に役立つような記事を書いていきます。
Proxmoxでログイン画面を日本語にする

標準では英語のログイン画面になりますが、毎回変更するのが大変なので、コンフィグを変更。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/9adaf373-38c2-9e8a-629a-4d72a52bf68c.png)

```/etc/pve/datacenter.cfg
language: ja
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/3258b41f-af36-9b65-35ab-525d58cabfb4.png)
# 参考にさせていただいたサイト

https://forum.proxmox.com/threads/how-can-i-change-the-language-in-the-login-mask-to-default.11482/
リソースプロバイダーを登録済みだが、「このサブスクリプションのCDNリソースプロバイダーを登録できません。」と表示される

Azureのリソースプロバイダーは、対象のリソースプロバイダーが登録済みであればリソース作成可能と思っていましたが、必ずしもそうではないようです。

# ぶつかった問題
以下のカスタムロールを付与したユーザーでAzure CDNを有効にしたApp Serviceを作成しようとすると、「このサブスクリプションのCDNリソースプロバイダーを登録できません。」とエラーが表示され、作成できない。

#### 付与したカスタムロール
- ロール：共同作成者
- スコープ：リソースグループ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332975/0696eef8-bf2c-cd66-ea90-39b66f5f8dee.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332975/1ad6e5a3-8ce1-18db-78bc-bb4413b73272.png)


なお、対象のサブスクリプションのリソースプロバイダー「Microsoft.cdn」は登録済み。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332975/84de92b8-ab78-730f-bc3d-b61bcd7b41f3.png)

# 解決方法
以下のカスタムロールを作成し、操作対象のユーザーに権限を付与する。

- 許可するアクション：CDNのリソースプロバイダーの登録
- スコープ：サブスクリプション

#### CDNのリソースプロバイダーの登録のみを許可したカスタムロール
```json:CDNregister.json
{
    "properties": {
        "roleName": "CDN_register",
        "description": "CDNのリソースプロバイダー登録のみ許可するロール",
        "assignableScopes": [
            "/subscriptions/<サブスクリプションのID>"
        ],
        "permissions": [
            {
                "actions": [
                    "Microsoft.Cdn/register/action"
                ],
                "notActions": [],
                "dataActions": [],
                "notDataActions": []
            }
        ]
    }
}
```
付与後、改めて作成してみると、先ほどのエラーが消えて作成できるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332975/456b73fb-1687-8e76-9a56-47f29e5eb746.png)

# まとめ

リソースプロバイダーはサブスクリプション単位で設定が行われるため、リソースグループがスコープの権限をユーザーに与えても、リソースプロバイダーの操作には関与できない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332975/5795515b-376c-abdf-ada6-3e5a0657d239.png)

そのため、ユーザーにサブスクリプションをスコープにした「Microsoft.cdn」の登録権限を付与する必要がある。

とはいえ、登録だけしておけば権限を与えなくても使えるリソースプロバイダーもあるし「Microsoft.cdn」は例外??リソースプロバイダの現在の登録状態に関わらず、一度状態を確認しに行く仕様なのかしら??

難しいですね。