OmniAICreator/Qiita-1.07M huggingface dataset:
Termux: Grimler repoでGPG Error

この記事では主に

```
W: GPG Error: https://grimler.se/... stable InRelease: The following signatures couldn't be verified because the public is not available: NO_PUBKEY B0076E490B71616B
```

これが出てしまう対処法について紹介します．

# Termuxのインストール
まず，**Playストアのものは選ばないようにしましょう**．Playストアにあるものは更新がされていません[^1]．

インストールは，F-Droid経由か，直接APKを用いて行います．

F-Droid:

https://f-droid.org/en/packages/com.termux/

直接APKから

https://github.com/termux/termux-app/releases/latest

# 始める前に
今回Repositoryの変更に必要なツールを事前にインストールするため，手順を間違えたら割と面倒くさいことになることがあります．直せないこともないと思いますが，もしどうしようもなくなったら，**アプリのデータを消すことでリセットできる**ということを覚えておいてください(**当然Termux内に作成したファイル等はすべて消えます**)．
JoyUIの場合，アプリ設定から一番下の「データをクリア」で消すことができます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601799/fde41388-ef4f-3d0e-2a6f-de86488c4a86.png)


# パッケージのインストール
Termuxが入ったら，このあとの作業で使うパッケージを先に入れます．aptよりpkgを使うことをおすすめします．
このとき，すでに`termux-change-repo`でGrimler repoを選択している場合は，一度デフォルトに戻してください．
```
pkg install wget openssl gnupg
```

このあと，`termux-change-repo`でGrimler repoを選択しますが，このままやると`GPG Error`に当たります．

# なにが起きているのか
確認のため，`grimler.se`にアクセスすると，

> I switched to a new GPG key in August 2021, when starting to use a yubikey. 
> *https://grimler.se/pubkey/*

> 2021年8月にYubikeyを使い始める際，新しいGPGキーに切り替えました

とのことだそうですので，こちらも新しい公開鍵に切り替えなければいけませんね．

# 新しいGPGキーを取り込む
curlでやりたかった[^2]のですが，`libssl.1.1`がないと言われます[^3]ので，wgetでやります．
(少し長いですが，頑張ってください...)
```
wget -O - grimler.se/pubkey/raw | gpg --dearmor | tee $PREFIX/etc/apt/trusted.gpg.d/grimler-repo.gpg > /dev/null
```

あとは，`termux-change-repo` します
```
termux-change-repo
```

3つすべて選ぶ．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601799/048d31e4-797f-6cab-1124-33fe7c3c7bfd.png)

Grimler repoを選ぶ．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601799/deddd824-21a0-0b7e-e3f2-e85be8db339d.png)

最後に，

```
pkg upgrade
```

を実行すれば，主要なパッケージが入り，CLangなども動くようになります．

[^1]: https://wiki.termux.com/wiki/Termux_Google_Play
[^2]: https://github.com/termux/termux-packages/issues/6923#issuecomment-850878913
[^3]: この問題も，Grimler repoに変更すると解消しました
AtCoder Beginner Contest 244 参戦記

# AtCoder Beginner Contest 244 参戦記

## [ABC244A - Last Letter](https://atcoder.jp/contests/abc244/tasks/abc244_a)

1分半で突破. 書くだけ.

```python
N = int(input())
S = input()

print(S[-1])
```

## [ABC244B - Go Straight and Turn Right](https://atcoder.jp/contests/abc244/tasks/abc244_b)

4分で突破. 書くだけ.

```python
N = int(input())
T = input()

d = 0
t = [(1, 0), (0, -1), (-1, 0), (0, 1)]
x, y = 0, 0
for c in T:
    if c == 'S':
        dx, dy = t[d]
        x += dx
        y += dy
    elif c == 'R':
        d += 1
        d %= 4
print(x, y)
```

## [ABC244C - Yamanote Line Game](https://atcoder.jp/contests/abc244/tasks/abc244_c)

10分で突破. リストでやると TLE するかなーと思っていたが、後で試したらそんなこともなかった. インタラクティブは珍しい.

```python
N = int(input())

s = set(range(1, 2 * N + 2))
while True:
    print(s.pop())
    x = int(input())
    if x == 0:
        break
    s.remove(x)
```

## [ABC244D - Swap Hats](https://atcoder.jp/contests/abc244/tasks/abc244_d)

9分で突破、WA1. 出した瞬間に No を Np と typo してることに気づいてグエッとなった. 揃っている状態から1回交換している状態と同等だと駄目で、それは2つ違っている状態.

```python
S = input().split()
T = input().split()

c = 0
for i in range(3):
    if S[i] != T[i]:
        c += 1

if c == 2:
    print('No')
else:
    print('Yes')
```

## [ABC244E - King Bombee](https://atcoder.jp/contests/abc244/tasks/abc244_e)

27分半で突破. 偶奇分けする必要こそあるものの、DPするだけじゃんってなった. どこがキングボンビーなのかが分からない.

```python
from sys import stdin

readline = stdin.readline
m = 998244353

N, M, K, S, T, X = map(int, readline().split())
S, T, X = S - 1, T - 1, X - 1
UV = [tuple(map(lambda x: int(x) - 1, readline().split())) for _ in range(M)]

dp = [[0] * N for _ in range(2)]
dp[0][S] = 1
for _ in range(K):
    t = [[0] * N for _ in range(2)]
    for u, v in UV:
        if v == X:
            t[1][v] += dp[0][u]
            t[1][v] %= m
            t[0][v] += dp[1][u]
            t[0][v] %= m
        else:
            t[0][v] += dp[0][u]
            t[0][v] %= m
            t[1][v] += dp[1][u]
            t[1][v] %= m
        if u == X:
            t[1][u] += dp[0][v]
            t[1][u] %= m
            t[0][u] += dp[1][v]
            t[0][u] %= m
        else:
            t[0][u] += dp[0][v]
            t[0][u] %= m
            t[1][u] += dp[1][v]
            t[1][u] %= m
    dp = t
print(dp[0][T])
```
kotlinで平仮名をカタカナにしたい

文字列の平仮名をカタカナに置き換えます。
特に難しくないので詳しくは書きません。

## コード
```kotlin
object JpConverter{
    fun hiraToKata(str: String) = 
        str.map { 
            if (it.code in 0x3041..0x3093) {
                it + 0x60 
            } else {
                it
            } 
        }.joinToString("")
}
```

`it + 0x60`だけつまづきました。`it + "0x60"`と書いたら動かなかったので、、

## 最後に
ミスは指摘お願いします。
もっといい方法あれば教えてください。
【Swift】Delegateメソッドでジェネリクスを使いたい時にassociatedtypeは使えない

## はじめに
今回は、Protocolにジェネリクスを引数に受け取るメソッドを定義したとき、
そのProtocolに書いたメソッドをDelegateメソッドとして、使いたい場合の書き方を記事にしました。

## 前提条件
Swiftにおける下記の3点について知っていること
- Protocol
- Delegate
- ジェネリクス

## このように書くとコンパイルエラーになる
#### ソースコード
```swift
protocol SampleDelegate: AnyObject {
    associatedtype T
    func getSampleData(_ data: T)
}

class Fuga: SampleDelegate {
    typealias T = String
    func getSampleData(_ data: T) {
        print(data)
    }
}

class Hoge {
    weak var delegate: SampleDelegate?     // コンパイルエラー
}
```

#### エラーの内容
`Protocol 'SampleDelegate' can only be used as a generic constraint because it has Self or associated type requirements`
自分が実装していたときは、このエラーが出ました。
もしかしたら、この記事を見ていただいている方の中で、このエラーが出ている方がいるかも知れません。

和訳すると、
「プロトコルは、Selfまたは関連する型の要件があるため、一般的な制約としてのみ使用することができる」
とのことですが、これだけではよくわかりませんでした。

`associatedtype`を`Fuga`側で`typealias T = String`というように、Stringに型決めしたところで、
delegateを持つ側の`Hoge`は、実際に処理を行うクラスが持っている型を知らないのでコンパイルエラーになってしまうと自分は解釈しました。

#### こうすればコンパイルが通る
```swift
protocol SampleDelegate: AnyObject {
    func getSampleData<T>(_ data: T)
}

class Fuga: SampleDelegate {
    func getSampleData<T>(_ data: T) {
        print(data)
    }
}

class Hoge {
    weak var delegate: SampleDelegate?
}
```

問題点を1つ上げるとすれば、コンパイルエラーのときは、`Fuga`側で、型付けをすることができましたが、
今回は、`associatedtype`が使えないため、残念ながら型を確定させてあげることができません。

なので、そのあたりは、`func getSampleData<T>(_ data: T)`で考慮してあげる必要がありそうです。

以上！
[OutSystems]Producerモジュールをプログラムで知る方法

レビュー対象モジュールの参照モジュールを自動取得し、開発中のものがないかチェックするプログラムを作りたい。
というわけで、モジュール名を指定し、そのモジュールで参照しているProducerモジュール名を取得する方法を考える。

Consumer/Producerという用語について。
AというモジュールがBというモジュールのCというActionを参照する場合、AがConsumerでBがProducerになる。つまりConsumerは参照する側、Producerは参照される側。

# 結論から
注意：ドキュメントが見当たらないので公式情報ではない

1. (System)モジュールに含まれるEspace EntityとEspace_Reference Entityを、Espace_Version Identifier型の属性で結合する。
2. そして、EspaceのNameプロパティを対象モジュール名でフィルタ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/c96422a0-59ba-852e-c0c4-bf39f824cfab.png)

検索結果のEspace_Referenceとして帰ってくるものが、対象モジュールから参照利用している各要素（Actionなど）。
Espace_ReferenceのProducer_Name属性がProducerモジュール名。Group ByをかけるとProducerモジュール名だけになる。

# Espace Entity
(System)モジュールから。
Service Studioで作成するeSpaceの各種情報が入っている。

- Name属性：モジュール名
- Version_Id属性： Espace_Versionという別のEntityのId型。このEntityはPublishされた各モジュールの各バージョンを管理している様子。つまり、Version_Id属性には、対象Espaceの現在有効なバージョンのEspace_Version Identifierが入っていると判断できる

# Espace_Reference Entity
(System)モジュールから。
あるモジュールが他モジュールの「要素」（Actionなど）に対して持っている参照を持っている。

- Consumer_Version_Id： 参照のConsumer側のモジュールのバージョンに対応するEspace_Version Identifier。つまり、Espace.Version_Idと結合すればよい
- Producer_Name： 参照のProducer側のモジュール名
- Name： 参照されている要素の名前

参考として、こんな感じでデータが入っている。
この例では、あるモジュールが参照している要素をEspace_Referenceから一覧表示したケース。AssociateReactiveLibraryモジュールのThrowErrorTestというClient Actionを参照していることになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/f683cea4-d19d-a9bb-aae2-a82bdcf3eb12.png)
terraformで作ったECSで構築したタイミングで１発のみ初期化スクリプトを流し込みたいとき

## 使いどころさん
- migrationやDB初期化など
- ECSにて1発のみスクリプトを流し込みたい場合は、aws ecsコマンドのサブオプションである`run-task`を使う必要がある
- `rnn-task`はいわば、タスクを手動で起動するイメージ
    - `docker run`とか、`kubectl run`とかで初期化したりしますよねそれと同じイメージかな
- ECSの場合、kubernetesにはある`init_container`をサイドカーで用意することはできなさそう
    - これはちゃんと調べていないけれど、サービスの中で一つでもコンテナが落ちるとサービス全体が落ちてしまう
    - それを許容するようなパラメータもあったかもしれない


## やりかた
- ローカルで`aws ecr run-task`を実行すればよい
- それをterraformでやろうとすると`local-exec`を使うことでローカルのコマンドを実行することができる

## 例
- `triggers`は指定しているパラメータが変更されると、本リソースが実行されるという意味になる
    - そのため、クラスタやタスク定義が更新されたらこのリソースも実行される
- そもそも、クラスタが起動していないと実行できないスクリプトなので、`depends_on`をつけている

```tf
resource "null_resource" "init_db" {
  triggers = {
    cluster_arn = aws_ecs_cluster.vamdemic_ecs_cluster.arn
    task_definition_arn = aws_ecs_task_definition.vamdemic_db_init_task.arn
  }
  provisioner "local-exec" {
    command = <<EOT
    aws ecs run-task \
      --region $AWS_DEFAULT_REGION \
      --profile $PROFILE \
      --launch-type FARGATE \
      --network-configuration "awsvpcConfiguration={subnets=[$SUBNET_ID],securityGroups=[$SECURITY_GROUP_ID],assignPublicIp=ENABLED}" \
      --cluster $CLUSTER_NAME \
      --task-definition $TASK_NAME
EOT


    interpreter = ["/bin/bash", "-c"]

    environment = {
      AWS_DEFAULT_REGION = "ap-northeast-1"
      PROFILE            = "aws-vamdemic-dev"
      SUBNET_ID          = tolist(data.aws_subnet_ids.private.ids)[0],
      SECURITY_GROUP_ID  = aws_security_group.vamdemic_sg_ecs.id
      CLUSTER_NAME       = aws_ecs_cluster.vamdemic_ecs_cluster.name
      TASK_NAME          = aws_ecs_task_definition.vamdemic_db_init_task.family
    }
  }

  depends_on = [
    aws_ecs_cluster.vamdemic_ecs_cluster,
    aws_ecs_task_definition.vamdemic_db_init_task
  ]
}

```

## シェル

```bash
#!/bin/bash

PROFILE="aws-vamdemic-dev"
AWS_DEFAULT_REGION="ap-northeast-1"
SUBNET_ID="subnet-00000000000000000"
SECURITY_GROUP_ID="sg-00000000000000000"
CLUSTER_NAME="vamdemic-dev-user01-ecs-cluster"
TASK_NAME="vamdemic-dev-user01-init-db-definition"

aws ecs run-task \
  --region ${AWS_DEFAULT_REGION} \
  --profile ${PROFILE} \
  --launch-type FARGATE \
  --network-configuration "awsvpcConfiguration={subnets=[${SUBNET_ID}],securityGroups=[${SECURITY_GROUP_ID}],assignPublicIp=ENABLED}" \
  --cluster ${CLUSTER_NAME} \
  --task-definition ${TASK_NAME}

```
HTTPでgetしたデータがconsole.logで見えないと思ったら非同期処理が原因だったらしい


# HTTPでgetしたデータがない
vueで以下のようなコードを書いていたが、console.logにはなにも出力されなかった。
HTTPでgetしたデータをthis.postに代入して出力させているつもりだったが、確認できない。
```
  mounted() {
    const url = location.pathname;
    const id = url.replace(/[^0-9]/g, "");
    axios
      .get(`/api/v1/posts/${id}.json`)
      .then((response) => (this.post = response.data));
    console.log(`this.post: ${JSON.stringify(this.post)}`);
  }
```
ただ、その後の処理は問題なく動作しているので、HTTPのgetは成功している様子。

# 原因と修正内容
メンターの方に伺ったところ、非同期処理が原因とのことだった。
以下のように修正したらconsole.logでみえるようになった。
```
  mounted() {
    const url = location.pathname;
    const id = url.replace(/[^0-9]/g, "");
    console.log(`this.post_1: ${JSON.stringify(this.post)}`);
    axios
      .get(`/api/v1/posts/${id}.json`)
      .then(
        (response) => (
          (this.post = response.data),
          console.log(`this.post_2: ${JSON.stringify(this.post)}`)
        )
      );
  },
```


# 各コード毎の非同期処理動作イメージ

以下のサイトを参考に今回のコードの動作イメージを作成してみた
[参考サイト](https://dev.classmethod.jp/articles/javascript-asynchronous-processing/)
[参考qiita](https://qiita.com/hirokikondo86/items/226905890944603dba39)
[参考youtube](https://www.youtube.com/watch?v=8aGhZQkoFbQ)

### 最初のコードの動作イメージ
![問題イメージ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1193244/e2a3314d-0ded-79fd-30a8-5e89b8022731.gif)

このコードでは、

```
コードA
.then((response) => (this.post = response.data));
```

```
コードB
console.log(`this.post_2: ${JSON.stringify(this.post)}`);
```

上記２つのコードがそれぞれセミコロンで分割されてしまっているから、コードAがコードBの後に処理されてしまったために、console.logでは、何も表示されなかった。


### コード修正後の動作イメージ
![修正イメージrev03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1193244/d5aa1460-17d0-0317-720a-a19e299efbf7.gif)

修正後のコードでは、

```
.then(
   (response) => (
          (this.post = response.data),
          console.log(`this.post_2:${JSON.stringify(this.post)}`)
   )
)
```

上記のように2つのコードを一つにまとめることで、一緒に非同期処理されるからconsole.logにちゃんとHTTPでgetしたデータが出力された。
Yolov5を読み解く

Yolov5をざっくり読み解いた内容です。記事内容の元はこのリンク先から。
https://github.com/ultralytics/yolov5

# ネットワーク構造
全体のネットワーク構造はこのようになっています。
![Screen Shot 2022-03-14 at 0.30.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420844/fe08b350-4c63-3dd3-0776-6aeaaef8fc9b.png)

FPNのの後にbottom-upでさらに特徴量を抽出する経路が追加されたPAN(Path Aggregation Network)を構成し、最後は複数スケールの特徴量画像からそれぞれBounding boxを推論する形をとっています。
※ オリジナルのPANではshortcut connectionで特徴量どうしを足しているが、YoloではConcatenate
- 6x6, 3x3 Conv
  普通のConv層 + BatchNormalization + Swish関数
  Swish関数は活性化関数で、ReLUからSwish関数に代えるだけで精度が良くなる例も多く見られているようです。
- 1x1 Conv
  途中の1x1 Convは冗長な特徴量を集約して計算量を抑える働きを持たせています。最後の1x1 Convは特徴量画像のピクセル毎にbounding boxを出力させるためのものです。
- C3(n)
  C3(n)はCSPNet(Cross Stage Partial Network)の考えがベースになっています。
<img width="400" alt="Screen Shot 2022-03-16 at 0.07.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420844/2f333e0c-e097-8707-fb2c-7c0a33a9553b.png">


入力の特徴量を2つに分けて一方はそのまま。もう一方は通常の畳み込みを行い、両者をConcatenateしています。この仕組みにより計算量を抑えつつ、より豊かな勾配の組み合わせが実現され、精度の良い推論ができるらしい・・・
Yolov5ではResNetに対してCSPを適用したCSPResNetがベースになっていますが、ResNetの残差ブロックの考えが崩れてしまわないのか、の部分が正直よくわかっていません。

- SPPF
  1x1 Conv + 1x1、5x5、9x9、13x13のMaxPoolingをConcat + 1x1 Conv
  異なるサイズのPoolingを組み合わせることにより、サイズの異なる検出対象に対してロバスト性が出るようです。
  

- Upsample
- Concatenate

いくつか1x1 Convが連続して配置されている箇所があります。個人的には連続で1x1 Convを重ねることが精度向上に寄与しているのか疑問に感じました。


以下、後述予定。。。

---
# 正解ラベル・誤差関数

# 学習
基本情報技術者試験対策　12日目

基本情報技術者試験勉強　12日目
-
この記事の目的
-
今年の5月に基本情報技術者試験を合格するために、過去問で間違えた箇所をただまとめる自分のための記事

プロフィール
-
・文系大学の３年生
・ITパスポートは保有
・ウェブアプリやサイト作成を個人で行ったことがある程度
・猫好き

今日の課題
-
計算問題をメインに取り組む。とりあえず、範囲は関係なく、テクノロジー系とマネジメント系、ストラテジ系の計算問題を取り組む。最低でも5問は取り組んで、4問正解を目指す。


間違えた箇所
-
①開発工数の求め方
見積もられた開発工数（FP) ＋　（人月数　× １人月数あたりのFP）

（マネジメント系/プロジェクトマネジメント/プロジェクトのコスト）


②MTBFの求め方
MTBF ＝　システムの稼働時間 / 故障回数
１、総稼働時間を求める
パソコンの台数　× 一台におけるパソコンの稼働時間　× 稼働日数
２、総稼働時間を故障回数で割る
（テクノロジ系/システム構成要素/システムの評価指標)


③年間総額,発注費用の求め方
年間総額　＝　発注費用の合計　＋　在庫の保管費用
１、発注費用を求める
(1個あたりの仕入額　× 1回の発注量　＋　1回あたりの発注費（× 割引率）)/1回あたりの発注量

２、在庫の保管費用を求める
1個あたりの年間保管費用　× 1個の発注量（在庫がなくなると同時に入荷などの条件がある場合、２で割る）
（ストラテジ系/企業活動/ORーIE）


③システム全体の稼働率の求め方
コンピュータA、Bの各稼働率を求める
稼働率　＝　MTBF / (MTBF + MTTR)
ここが重要
全体の稼働率　＝1 - (1 - コンピュータAの稼働率)(1 - コンピュータBの稼働率）


今日の振り返り
-
5問しか取り組めなかったが、やはり計算問題がまったくわかっていない。
計算を毛嫌いせず、何回も反復するしかない。
次回も引き続き、計算問題をメインに取り組み、まずは一通り解く。

>引用
基本情報技術者試験ドットコム
https://www.fe-siken.com
APIgatewayのプロキシ統合と非プロキシ統合についてわかってなかった

・勘違いポイント
プロキシ統合、非プロキシ統合、なにもしないの３択だと思ってた
・実際
APIgateway（少なくともRESTAPI）は統合をする必要がある
→統合方法としてプロキシ統合をするかプロキシを使わないか（非プロキシ統合か）を選ぶという考え方だった

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/705ee572-f71a-28b4-7d16-14d7b223c79a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/a60f295f-44f4-5564-6881-26fd0404c6a7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/36713737-1105-c5a1-1456-7e176d243fe9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/a553980d-81bd-2a74-ae6c-25255a8e54df.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/6a74d9b1-828a-89da-e367-4d97b4647292.png)
 
このようにプロキシ統合できるものとプロキシ統合ができないもの（非プロキシ統合しかできない）ものがある
EnvaderでLinuxコマンドを学ぶ第3回(mv/cp編)

## この記事の内容
はじめまして、a-min3150です。エンジニアへの転職を目標に日々、学習中です。
アウトプットのためEnvaderで学習したこと、ハマったことなどを書いていきたいと思います。

## Linuxコマンドとは
LinuxOSで使うことのできるコマンドで主にサーバーのシステムを操作するのにCUI(いわゆる黒い画面)での操作が必要となるため、サーバー管理やインフラ構築をするエンジニアは知っておかなければならないコマンドとなります。

## 今回の学習アウトプットは
Linuxコマンドの基礎コマンドの3回目で、(mv/cp)の2つのコマンドについてです。
これらを学ぶことにより、「ディレクトリ・ファイル」 の移動と複製ができるようになります。

第1回（cd/ls/cat編）は[こちら](https://qiita.com/a-min3150/items/1a9cc84d1543e1067f8c)
第2回(pwd/rm/mkdir/rmdir編)は[こちら](https://qiita.com/a-min3150/items/deb9f1de7ebb2b2ac361)


## mvコマンドとは
mvとは、(MoVe)の略でコマンドの機能として２つあり、１つはディレクトリやファイルを別のディレクトリへ移動する際に使用するコマンドです。
もう１つは名前を変更したいディレクトリ（またはファイル）を先に、変更によって表示したいディレクトリ名（またはファイル名）を後に指定することで、リネーム処理となります。

### 基本的な使い方(mv-移動)
mv [オプション] 移動させたいディレクトリ(またはファイル)名 移動先のディレクトリ名 
主なオプション
|オプション|	説明|
|:-:|:-:|
|-f	|移動先に同名のファイルがある場合、強制的に移動（上書き）されます。
|-i	|移動先に同名のファイルがある場合、確認メッセージが表示されます。
|-b	|移動により上書き（削除）されるファイルのバックアップを作成します。
|-n|移動先に同名のディレクトリ（またはファイル）がある場合は、処理を実行しません。
|-v	|移動処理を行う際の詳細情報を表示します。


移動先に同名ファイルがある場合は“上書き”となるので注意が必要です。-iオプションを使用し確認メッセージを表示するか、-nオプションを使用し上書き処理が実行されないようにしましょう。
```
mv hoge.txt hogehoge/.  #hoge.txtをhogehogeディレクトリに移動
```

そしてファイルをディレクトリに移動する場合には、移動先のディレクトリ名に/.をつけることで、より安全に作業を行えます。
この/.には「ディレクトリ直下の」という意味があります。もし/.を付けずに上記のコマンドを指示し、且つhogehogeディレクトリが存在していなかった場合、hoge.txtファイルはhogehogeというファイルにリネームされるという挙動をとります。


### 基本的な使い方(mv-名前変更)

名前を変更したいディレクトリ（またはファイル）を先に、変更によって表示したいディレクトリ名（またはファイル名）を後に指定することで、リネーム処理となります。

```
mv ファイル1 ファイル２　　　#ファイル１の名前をファイル２に変更
```




## cpコマンドとは
cpとは、(CoPy)の略で、既存のファイルを複製（コピー）する際に使用するコマンドです。

### 基本的な使い方
cp [オプション] コピー元ファイル コピー先ファイル

主なオプション
|オプション|	説明|
|:-:|:-:|
|-i| コピーによって上書きされるファイルがある場合、確認メッセージを表示します。|
|-v	|コピーの実行内容を表示します。|
|-n|	コピー先に既に同名のファイルが存在する場合、処理を中断します。|
|-f	|コピー先に同名のファイルが存在していても、強制的にコピー（上書き）を実行します。|
|-b|	コピー（上書き）時に、バックアップファイルが作成されます。|

コピー先にディレクトリを指定する場合は、コピー元ファイルの次にコピー先ディレクトリを指定します。


```
cp [オプション] コピー元ファイル コピー先ディレクトリ
また-rオプションを使用した状態でコピー元にディレクトリを指定すると、その中にある子ディレクトリやファイルを含めてコピーすることが出来ます。

cp [オプション] コピー元ディレクトリ コピー先ディレクトリ
```

## まとめ
今回はLinuxの基本コマンド(mv/cp)の2つのコマンドについて解説しました。
- ```mv```は「ディレクトリまたはファイルを移動させる機能」と「名前変更させる機能」
の２つの意味合いがあることを覚えましょう。
- ```cp```は既存のファイルをコピーさせるコマンドでした。


## 引用サイト/資料
- Envader(エンベーダー):https://envader.plus/
- Envaderコース一覧:https://envader.plus/course
- 基本的なコマンドの練習(mv/cp編):https://envader.plus/course/1/scenario/1003
- Linux基礎コース:https://envader.plus/course/1
- Linux標準教科書:https://lpi.or.jp/news/press/page/20180327_01/
Dockerfileでファイルやディレクトリごとコンテナにコピーする方法

## ファイルをコピー
事前準備として、Dockerfileがあるディレクトリの中にコピーしたいファイルを配置しておきます。
配置できてることが前提でDockerfileにコピーコマンドを記述します。

```
# Dockerfileがあるディレクトリに配置したコピーしたいファイル（test.file）をコンテナ内の/home/sample-dir/下にコピーさせる
COPY test.file /home/sample-dir/
```

コピー後は、/home/sample-dir/test.fileとコピーされます。
こんな感じで、コピーしたいファイルの後にコンテナ内のコピーさせたい場所のパスを記述します。

## ディレクトリごとコピー
ディレクトリの中を全部そっくりコンテナの中にコピーさせたい場合は、ファイルではなくディレクトリで指定してあげます。

```
# Dockerfileがあるディレクトリに配置したディレクトリ（/testディレクトリ）をコンテナ内の/home/sample-dir/下にコピーさせる
COPY test/ /home/sample-dir/
```

コピー後は、/home/sample-dir/test/とコピーされます。

## 参考記事

https://t8.dev/ja/blog/docker_dockerfile_copy/

https://eng-entrance.com/linux_command_cp#i
別PCのWSL2にSSHログイン


WSL側の更新で色々と変化があるようなので現時点でのまとめ

## 要点
- sshdが起動しているか、接続に使う手法は許可されているか
- Windowsのport
- WSL2へのポートフォワーディング

## 参考
- [wsl2でsshサーバを起動し、外部からそこに接続 \- Qiita](https://qiita.com/yabeenico/items/15532c703974dc40a7f5)
- [Windows/WSL/ネットワーク/WSL2のホストへ外部からSSH接続する \- yanor\.net/wiki](http://yanor.net/wiki/?Windows/WSL/%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF/WSL2%E3%81%AE%E3%83%9B%E3%82%B9%E3%83%88%E3%81%B8%E5%A4%96%E9%83%A8%E3%81%8B%E3%82%89SSH%E6%8E%A5%E7%B6%9A%E3%81%99%E3%82%8B)

## SSH設定
ディストリビューションや利用したい接続方式に応じて適切に
（デフォルト設定が時代とともに変わるので要確認）

## Windowsのport
### 確認手段

接続元PCから接続先PCに向けて

```shell
$ telnet 接続先PCのIP 22
```

### Port開放

セキュリティソフトに応じて異なる
Windows Firewallの場合は管理者権限にて

```
New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort 22 -Action Allow -Protocol TCP
New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort 22 -Action Allow -Protocol TCP
```

## WSL2へのポートフォワーディング
### 確認手段

接続先PCにて設定状況を確認

```
netsh.exe interface portproxy show v4tov4

ipv4 をリッスンする:         ipv4 に接続する:

Address         Port        Address         Port
--------------- ----------  --------------- ----------
*               22          172.30.242.166  22
```

### ポートフォワーディング設定

xxx.batにコマンドを記載、このショートカットを作成して管理者で実行できるように設定する
ついでなのでsshdや別途入れたdockerもここで起動させる
docker起動後だとIPが2個出てしまったり色々あったので最終的にはこんな感じにして、最初とリセットしたいとき用にした
自動化が必要ならタスク化

```
wsl --shutdown

for /f "usebackq delims=" %%A in (`wsl hostname -I`) do set IP=%%A
netsh.exe interface portproxy delete v4tov4 listenport=22
netsh.exe interface portproxy add    v4tov4 listenport=22 connectaddress=%IP%
sc.exe start  iphlpsvc

wsl -u root -- service ssh start
wsl -u root -- service docker start
```
AWS公式資料で挑むSCS認定(20)-こんな時どうする(分野2:ログと監視)

##### [前回] [AWS公式資料で挑むSCS認定(19)-こんな時どうする(分野1:インシデント対応)](https://qiita.com/mingchun_zhao/items/62c7d4a69dafb3f46e66)

## はじめに

引き続き「こんな時どうする」集の作成です。
今回は「分野2: ログと監視」がテーマとなります。

## 「分野2: ログと監視」基本知識のおさらい

### 監視(モニタリング)に使用されるサービス

- AWS CloudWatch Logs
- AWS Config
- Amazon CloudTrail

### ログの種類

- AWSサービスログ
    - CloudWatch Logs
    - CloudTrail
    - ELB
    - VPCフローログ
    - S3バケットログ
    - CloudFrontアクセスログ
- 各環境固有のログ
    - OSログ
    - アプリケーションログ
    - セキュリティログ
    - アクティビティログ
    - アクセスログ
    - センサーログ

### ログ処理に使用されるサービス

- Kinesis Data Streams
- Kinesis Data Firehose
- Athena

## 「分野2: ログと監視」の「こんな時どうする」

- EC2インスタンスのメモリ使用率とディスク使用率を、CloudWatchのメトリクスとして収集したい
    - カスタムメトリクスのため(標準でなく)、CloudWatchエージェントのインストールが必要
    - [CloudWatchエージェントのインストール手順](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-on-EC2-Instance.html)

- VPCネットワーク内でネットワークACL(NACL)、セキュリティグループ(SG)の許可・禁止についてのトラフィックログを監視したい
    - VPCフローログで監視可能

- 複数AWSアカウントのログを集中管理したい
    - すべてのログを集中型ログ記録アカウントのS3バケットに送信
    - セキュリティ管理者へのみ読み取りアクセスを許可するようにバケットポリシーを設定

- 別リージョンのS3に保存されたログをロード・集計することなく、標準SQLを用いて特定条件で絞り込んで取得したい
    - Athenaを利用

- 過去のログデータを参照はしないが、コンプライアンスのため5年間コスト効率よく保持したい
    - 参照しないログデータをS3 Glacierに移動しアーカイブする

- 特定のEC2インスタンス間で送受信されるトラフィックの完全なパケット分析
    - パケットキャプチャをサポートするAWS MarketPlaceのAMIを使用
    - トラフィックがそれを通るように制御するためルートテーブルを設定

- EC2インスタンスのENIを通過するトラフィックを、EC2サーバーにログインせずパケット分析したい
    - Amazon VPC traffic mirroringを使用
    - EC2インスタンスのENIからネットワークトラフィックをミラーリング
    - 任意のENIやNLBにパケットをコピーし分析

## おわりに

「分野2: ログと監視」に対し、「こんな時どうする」でした。
次回は「分野3: インフラストラクチャのセキュリティ」です。
お楽しみに。

##### [次回] [AWS公式資料で挑むSCS認定(21)-こんな時どうする(分野3:インフラストラクチャのセキュリティ)](https://qiita.com/mingchun_zhao/items/1eb8ca9bd126fd36d705)
AWS SAP　合格体験記（初心者向け）

<h2>はじめに</h2>

2022年1月30日　無事に目標としていたAWS認定ソリューションアーキテクトプロフェッショナル（AWS SAP）に合格することが出来たので記録として残します！

---
<h2>受験のきっかけ</h2>

業界未経験でSES企業に転職してダラダラ過ごしてきましたが
世界的に猛威を奮っている某ウイルスの影響により、IT業界へ参入してくる人が増えてきている状況。
やはり新しい人たちには負けたくない！その気持ちから勉強を開始！

---
<h2>前提</h2>

そもそもAWSの有識者がほぼいない弊社・・・ちょうどAWSに関わる案件に参画し、２.3ヶ月目に取得しているので経験が浅い方、ない方も参考になるかと思います。

---
<h2>結果</h2>


１回目の受験・・・結果は・・・


---
854点で見事突破！！
![スクリーンショット 2022-02-19 17.16.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2411418/279f710d-7964-98d9-5f0c-d4ce96444f9d.png)

---
<h2>勉強方法</h2>
ありとあらゆる合格体験記を見ましたが、経験が浅い方・ない方にはこれが良いかと思います。




---
[試験の概要](#https://aws.amazon.com/jp/certification/certified-solutions-architect-professional/)
まずは、ここで試験の概要を確認！
この認定の詳細と、準備すべき内容をチェックしよう。

---
[AWS ホワイトペーパーとガイド](#https://aws.amazon.com/jp/whitepapers/?whitepapers-main.sort-by=item.additionalFields.sortDate&whitepapers-main.sort-order=desc&awsf.whitepapers-content-type=*all&awsf.whitepapers-tech-category=*all&awsf.whitepapers-industries=*all&awsf.whitepapers-business-category=*all&awsf.whitepapers-global-methodology=*all)
クラウドの知識を深めるためにAWSとAWSのコミュニティによって作成されている提供される技術情報書！AWSの考え方を知ることで、問題を解くときの手がかりを見つけることに繋がる！

---
[サービス別資料 | AWS クラウドサービス活用資料集](#https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/)
定番のBlackBelt！知らないサービスが出てきた際は都度都度BlackBeltで調べて理解を深めましょう！

---
[AWS WEB問題集で学習しよう](#https://aws.koiwaclub.com/)
実際の試験に似た問題が多数出題される！最初のころは全く解けないですが、繰り返し繰り返ししておくと合格の近道になる！

---

[AWS 認定ソリューションアーキテクト プロフェッショナル模擬試験問題集（全5回分375問）](#https://www.udemy.com/course/aws-53225/)
おなじみのUdemyより、AWS SAP問題集！
模擬試験が全5回計375問あり、回を重ねるごとに難しくなりますが確実に実力が付きます！
（自分は3回目までしかやっておりませんが…）

---

[AWS Skill Builder](#https://explore.skillbuilder.aws/learn)
去年の年末あたりから数千円かかっていたAWS認定の模擬試験が無料になったので、有効活用しよう！


<h1>以上！！</h1>
---

<h2>さいごに</h2>
試験について、何か質問等がありましたらお気軽にコメントやメッセージ等ください。
自分も業界経験は長くないのでそういった方に、これまでのカウンセリング経験等を活かして
心身に対応できればと思います！
これを見た方が受かりますように！！
Vue.jsで'Invalid Host header'が出た時の対処(webpack 5対応版)



ほとんどの記事は、以下の設定が紹介されています:frowning2:
```disableHostCheck: true```
非推奨だと思いつつも、お手軽に使っていましたが、webpack5になりオプションがなくなってしまいました。開発環境とはいえ、セキュリティのためとのこと。
仕方なくあちこち探していたところ、こんな設定があるじゃないですか:thumbsup:
```allowedHosts```

以下、サンプルです。

```vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  publicPath: '/hoge/',
  devServer: {
    allowedHosts: ['hogehost','hogehost.foo.local'],
    compress: true,
  },
})
```
:::note info
本家のサイトを見ると、auto, all というオプションもある
:::

意外に簡単に実現できることがわかりました。お困りの方がいましたら、ぜひご活用ください。

 __参考にした情報__

https://webpack.js.org/configuration/dev-server/#devserverallowedhosts

https://zenn.dev/sa2knight/articles/9b19ffd391bca87d7b8c

*****
 _確認した環境_ 
webpack@5.70.0
webpack-dev-server@4.7.4
１つのフォームから複数のテーブルへ複数のレコード保存の実装

## 目的
Railsで１回のフォーム送信で２つのテーブルにデータを登録しつつ、片方のテーブルには複数のレコードにデータを保存したい。

## 自身が行った実装方法
1. フォームオブジェクトパターンの実装で２つのテーブルへ保存できるようにする
2. 複数のレコードを作成したいフォームのパラメーターを配列で送られてくるようにする
3. 2で送られてきたパラメーターを変形して要素の数だけcreateメソッドで保存

**※2と3について記録致します。**

```フォームのある.html
      <div class="ingredient">
        <div class="ingredient-name">
          <%= f.label :name, "材料名" %>
          <%= f.text_field :name, name:"[recipe_ingredient][name][]" %>
        </div>

        <div class="ingredient-amount">
          <%= f.label :amount, "分量" %>
          <%= f.text_field :amount, name:"[recipe_ingredient][amount][]" %>
        </div>

        <div class="ingredient-unit">
          <%= f.label :unit_id, "単位" %>
          <%= f.collection_select(:unit_id, Unit.all, :id, :name, {}, {name:"[recipe_ingredient][unit_id][]"}) %>
        </div>
```
フォームの中に
name:"[recipe_ingredient][name][]
name:"[recipe_ingredient][amount][]
name:"[recipe_ingredient][unit_id][]
と記述することで

```vim
"recipe_ingredient"=>{"name"=>["豚バラ", "卵"], "amount"=>["300", "2"], "unit_id"=>["2", "3"]}
```
と配列に入って送られてきます。（上記は一部切り取ったパラメーターです）

```フォームオブジェクトパターン用のmodel.rb
class RecipeIngredient
  include ActiveModel::Model
  attr_accessor :title, :source, :user_id, :name, :amount, :unit_id, :recipe

  with_options presence: true do
    validates :title
    validates :user_id
  end

  def save
    recipe  = Recipe.create(title: title, source: source, user_id: user_id)

    ingredients = [name, amount, unit_id].transpose
    
    ingredients.each do |ingredient|
      header = ["name", "amount", "unit_id"]
      ingredient_parameter = Hash[header.zip(ingredient)]
      ingredient_parameter["recipe_id"] = recipe.id
      Ingredient.create(ingredient_parameter)
    end
  end
end
```
送られてきた
```vim
"recipe_ingredient"=>{"name"=>["豚バラ", "卵"], "amount"=>["300", "2"], "unit_id"=>["2", "3"]}
```
をsaveメソッドの２行目の
ingredients = [name, amount, unit_id].transposeで
```vim
[["豚バラ", "300", "2"], ["卵", "2", "3"]]
```
に変形させeach文で配列の回数繰り返し処理を行い
header = ["name", "amount", "unit_id"]で保存したいカラム名を入れ
ingredient_parameter = Hash[header.zip(ingredient)]で
```vim
{"name"=>"豚バラ", "amount"=>"300", "unit_id"=>"2"}と{"name"=>"卵", "amount"=>"2", "unit_id"=>"3"}
```
に変形してそれぞれcreateの引数に渡して保存しています。
こうすることで一度の送信で複数のレコードを保存する事ができました。

## 終わりに
思い描く実装の記事には出会えなかったので試行錯誤の中、とりあえず形にはなりましたが、正しい実装方法なのかは分かりません。
改善点等あれば指摘していただければ幸いです。
初めての投稿で読みにくい箇所があるかもしれませんがお許し下さい・・・汗
もしこの投稿が誰かのためになれば幸いです。
ブートボリュームとかルートボリュームとかインスタンスストアとかEBSとかがわかってなかったので整理

ブートボリュームというのがありその実体は何なのかってのがいまいちピンとこなかったのでそこを調べた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/0267a2b8-8cbb-9685-3da9-61d5f7594417.png)
↑ブートボリュームはルートボリュームです（間違ってたらすいません）

このドキュメントを見るとブートボリュームはEBSかエフェメラルストレージ（インスタンスストア）か選択できるようです
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/RootDeviceStorage.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/ca538889-4084-2306-a0d9-0cfa565d9810.png)
↑ここでも書いてあるとおり基本的にこれ以外のインスタンスタイプはEBSのブートボリュームを使っています。
だからインスタンス再起動するとインスタンスストアは揮発性なのでデータ消えるとか心配してましたが、そもそもt2とかの汎用タイプのインスタンス使っていたらこのような心配は無用です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/e76825f9-60c7-fbdb-eec1-5f428d42846b.png)
↑余談ですが追加のインスタンスストレージでインスタンスストア使えるものも限られています。

https://blog.e2info.co.jp/2019/02/20/%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%82%B9%E3%83%88%E3%82%A2%E3%83%9C%E3%83%AA%E3%83%A5%E3%83%BC%E3%83%A0%E3%82%A8%E3%83%95%E3%82%A7%E3%83%A1%E3%83%A9%E3%83%AB%E3%82%B9%E3%83%88/

https://dev.classmethod.jp/articles/ec2-windows-support-hibernation/
↑と思い2019年の記事を見てみると起動時に暗号化ができてるし、ハイバネーションを利用する場合は暗号化必須みたいです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/d0cc211d-bceb-70a2-a63b-c3b9dc20d736.png)

実際、設定した見たところwindowsインスタンスに限らず暗号化を選択できます、これはハイバネーション有効にしてみましたが有効にしなくても暗号化の有無は起動時に設定できました
【Solana, TypeScript】自分のウォレットでSPLトークンを作成する


# 内容
Solana Token Programの公式ドキュメントを見ると、新しく作成したキーペアを使ってSPLトークンを発行する方法は書いてあったのだが、自分のPhantomウォレットなどを使って発行する方法が分からなかったので、メモとして書き残しておく。

https://spl.solana.com/token#example-creating-your-own-fungible-token

# 動作確認環境
- M1 Mac (macOS Monterey 12.3)
- @solana/web3.js : 1.36.0
- @solana/spl-token : 0.2.0

# コード
`connection`変数および`wallet`変数は[@solana/wallet-adapter](https://solana-labs.github.io/wallet-adapter/)で取得したもの。
トークンのnameやsymbolといったメタデータは登録していないので、Phantomウォレットで見ると表示名がmintアドレスになっているはず。


```sample.ts
import * as spl from '@solana/spl-token';
import * as web3 from '@solana/web3.js';

const createSplToken = async (decimals: number, amount: number) => {
  if (!wallet.publicKey) {
    console.log('Please connect a wallet before.');
    return;
  }

  // Generate/Get keys
  const mint = web3.Keypair.generate();
  const associatedTokenAddress = await spl.getAssociatedTokenAddress(
    mint.publicKey,
    wallet.publicKey
  );

  // Transaction for creating NFT
  const transaction = new web3.Transaction().add(
    // create mint account
    web3.SystemProgram.createAccount({
      fromPubkey: wallet.publicKey,
      newAccountPubkey: mint.publicKey,
      space: spl.MINT_SIZE,
      lamports: await spl.getMinimumBalanceForRentExemptMint(connection),
      programId: spl.TOKEN_PROGRAM_ID,
    }),
    // init mint account
    spl.createInitializeMintInstruction(
      mint.publicKey, // mint pubkey
      decimals, // decimals
      wallet.publicKey, // mint authority
      wallet.publicKey // freeze authority
    ),
    // create associated-token-account
    spl.createAssociatedTokenAccountInstruction(
      wallet.publicKey, // payer
      associatedTokenAddress, // associated-token-address
      wallet.publicKey, // owner
      mint.publicKey // mint
    ),
    // mint to
    spl.createMintToInstruction(
      mint.publicKey, // mint
      associatedTokenAddress, // receiver
      wallet.publicKey, // mint authority
      amount // amount
    )
  );

  // Transaction実行
  console.log('sending a transaction...');
  const signature = await wallet.sendTransaction(transaction, connection, {
    signers: [mint],
  });
  await connection.confirmTransaction(signature, 'processed');
  console.log('successfully create SPL tokens');
};

// How to use (Create and mint 100 new tokens)
const decimals = 9;
const amount = 100 * 10 ** decimals;
await createSplToken(decimals, amount);
```


# メタデータを登録するには
発行したSPLトークンのnameやsymbol等がPhantomウォレットで表示されるようになるには、"Solana Token Registry"というものに登録される必要があるらしい。以下のGitHubリポジトリにプルリクを送ってマージされないといけないようだが、実際に試したことはないので詳しいことは分からない。

https://github.com/solana-labs/token-list
VirtualBoxを使いホストOSからOpenSIMにアクセスできました

この数日、VirtualBoxのゲストOSのWindows11に、opensimulatorをインストールしてOpenSimのサーバーを起動することを試していました。

今までのことは、こちらに書きました。

https://qiita.com/masaru21/items/b8292d6b0f2934466ede

今回ようやくホストOSのMacにインストールしたSingularityというビューアで、自分のSIMに接続することが出来ました。

## VirtualBoxのホストOSからゲストOSへの通信ができるようになりました。
今回は、ホストOSからゲストOSに対して通信できるようになるためのスキルを身につけることが出来ました。

こちらの記事を参考にしました。

https://blog.proglus.jp/3315/

https://omulettekobo.hatenablog.com/entry/2012/04/25/014259

私は、今までVirtualBoxのネットワークの設定は、NATしか使ったことが無かったです。
でも、今回VirtualBoxのネットワーク設定の違いを知ることが出来ました。

結論を書くとNATの設定とホストオンリーアダプターの二つを設定すると、ホストOSからゲストOSに通信できる環境を作ることが出来ます。

NATは、ホストOSからゲストOSに通信できないことを今回学びました。
ゲストOSをインターネット接続するときは、NATで良いです。

でも、今回は、ホストOSからゲストOSに接続してOpenSimのビューアを使えるようにしたかったのです。
VirtualBoxにインストールしたビューアでは、解像度を高くすることが出来ないからです。


## IPアドレスの指定
ゲストOSで、IPアドレスを確認します。

このコマンドをコマンドプロンプトで、入力します。
```
ipcinfig
```
![VirtualBox_Win11_21_03_2022_22_03_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20977/d92ce78f-62e9-b607-f4f4-9ce5e591bf27.png)

今回は、イーサネットアダプター１に、NATが設定されています。
そして、イーサネットアダプター２に、ホストオンリーアダプターを設定しています。

そのためイーサネットアダプター２のIPv４アドレスを、OpenSimの設定ファイルに設定します。
赤丸で囲まれた部分のIPv4アドレスを控えてください。

ビューアのSingularityに、グリッドのログインURLを追加するときも、このイーサネットアダプター２のIPv４のアドレスを使います。

```
http://xxx.xxx.xxx.xxx:9000
```
のような形で、ポート９０００を指定して設定します。

opensimulatorの設定ファイルのRegions.iniを下記のように設定します。
```
[SIM NAME]
RegionUUID = ここは実際の内容のまま
Location = 1000,1000
SizeX = 256
SizeY = 256
SizeZ = 256
InternalAddress = ここに、イーサネットアダプター２のIPv４のアドレスを設定します。
InternalPort = 9000
ResolveAddress = False
ExternalHostName = SYSTEMIP
MaptileStaticUUID = 00000000-0000-0000-0000-000000000000
```

Regions.iniの設定に関しては、公式のPDFファイルの説明を読んで確認してください。
４０ページ以降に、書かれています。

https://www.jogrid.net/wi/pluginfile.php/1872/mod_resource/content/5/OpenSim_man2_2.0.0.pdf

上記の”InternalAddress = ”は、初期設定の０.０.０.０のままでも接続できました。
ネットワークの状況に応じて、上記の公式PDFの説明に合わせて設定してください。

## 接続できました。

MacにインストールしているSingularityで、普通に使えるようになり助かっています。
解像度を高くして、使うことができるからです。

![Snapshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20977/c21ef4af-60ca-2d04-12f8-26d53232f15a.png)

## 今回の経験で得たもの
今回VirtualBoxのホストOSとゲストOSとの通信の設定を学びました。
VirtualBoxのネットワーク設定も学ぶことが出来ましたので、ゲストOSで開発したウェブサイトへの接続など応用できる場面もあります。

またOpenSimに、IPアドレスを指定して接続することを学びましたので、JOGのグリッドに接続するなど本格的なOPEN SIMの運営もできると思います。
VPSを契約するなどしてIPアドレス固定して、安定してSIMの運営ができるようになれば、試してみたいと思っています。
Azure Functionsを用いたサーバーレスなTwitter botを開発してみた（その４、Pythonのバージョンを上げる）

# これまでのお話

前回の記事はこちら。

https://qiita.com/ataraken/items/2a1acf4c814b6fba51e0

開発当初、Python 3.7 で開発していたのですが、さすがに時代遅れになってきたので 3.9 にアップデートします。

# ローカル開発環境のアップデート

## Python 公式ページからダウンロード・インストール

Python の公式ページからインストーラをダウンロードしてインストールしてください。

https://www.python.org/

今回は2022.3.21時点で 3.9 の最新である 3.9.11 をインストールしました。

Azure Functions は 3.10 系はまだ未サポートなので 3.9 系にしています。

https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-python?tabs=asgi%2Cazurecli-linux%2Capplication-level#python-version

## Microsoft Store からのインストール

Microsoft Storeからもインストールできます。マイナーバージョンは指定できません。

# Azure Functionsのアップデート

公式ページの手順に従って行います。

https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-python?tabs=asgi%2Cazurecli-linux%2Capplication-level#changing-python-version

## Azure CLI インストール

Azure Portal は Python のバージョンアップをサポートしていないようなので Azure CLI をインストールします。
こちらを参考にインストールします。

https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli

## Azure CLI でのアップデート

まずはコンソールを立ち上げてログインします。次のコマンドを実行すると、Webブラウザ経由で Azure にログインします。

```powershell
> az login
A web browser has been opened at https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize. Please continue the login in the web browser. If no web browser is available or if the web browser fails to open, use device code flow with `az login --use-device-code`.
...
```

後は公式の手順で実行するだけです。

https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-python?tabs=asgi%2Cazurecli-linux%2Capplication-level#changing-python-version

`linuxFxVersion` を確認します。次のコマンドを実行したレスポンスの中に情報があります。私の環境では`  "linuxFxVersion": "PYTHON|3.7",`でした。

```powershell
> az functionapp config show --name <function_app> --resource-group <my_resource_group>
```

次のコマンドで更新します。今回は`LINUX_FX_VERSION`を`python|3.9`にして実行しました。公式ページは小文字で`python`としていたのでそれに倣っています。

```powershell
az functionapp config set --name <FUNCTION_APP> --resource-group <RESOURCE_GROUP> --linux-fx-version <LINUX_FX_VERSION>
```

実行するとレスポンスが返ってきて、無事に`"linuxFxVersion": "python|3.9",`になっていました。

# まとめ

地味な作業ですがサービスを運用していく上では大切なことだと思います。まだサービス運用前なのでワークフローにテストが入っていませんが、まじめにやるとそれなりに大変でしょうね。

今回は見送りましたが、 Azure Functions 自体のバージョンアップのやり方もまとめたいです。
Dockerでfrourioを動かそうとしたら「System limit for number of file watchers reached」エラーの解決法について

こんにちは。
frourioいいぞ〜と聞いていたので今回の３連休で触ってみようと思ったら、環境構築時点でDocker周りのエラーに苦戦したので解決した方法を備忘録として残してみました。

# 環境
- MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) / Intel Chip
- Docker version 20.10.12, build e91ed57
- Docker Compose version v2.2.3
- Rancher Desktop Version: 1.1.1
- Container image node:16.13.2
- frourio 0.27.1

# 実際に起きたエラー
Docker環境を立ち上げてからyarn runを実行した歳に発生したエラーです。エラーの内容は一部省略しています。

```shell
Error: ENOSPC: System limit for number of file watchers reached
```

調べてみるとNode.js系ではよく見かけるエラーのようですね。
具体的には、Linuxでファイル監視を行う処理がシステムで設定されている監視対象ファイルの上限数に到達すると出力されるようです。

# 原因
Linuxではinotifyという仕組みを使ってファイル監視を行っているようで、システムのデフォルトで監視対象の上限数が8192に設定されています。今回はそれを超えるファイル数が監視対象になったことが原因のようです。

実際に確認する場合は、次のコマンドを実行すると確認できます。

```shell
$ cat /proc/sys/fs/inotify/max_user_watches
8192
```

# 解決策(？)
やることは単純で次のコマンドを実行して増やしてあげればよさそうです。
ただ次のようなエラーが表示されて変更できませんでした。

```shell
$ sudo sysctl fs.inotify.max_user_watches=24288
sysctl: setting key "fs.inotify.max_user_watches": Read-only file system
```

# 問題
もう少し色々と調べてみるとコンテナ側では読み取り専用になっており変更できないようです。
具体的に検証して確かめていないですが、基本的にはホスト側の設定を引き継いでいるという記事を見かけたりしたのですが
ホスト側とコンテナ側でOSが一致しない場合はどこの値を参照しているのかそのあたりの仕組みがよく分かりませんでした。
もしかするとホストOSの値を継承せずに初期値が設定されいそうな気もします。

# 解決策
色々とやり方を調べている中でRancher Desktopの場合は設定をオーバーライドしてくれる仕組みがあるようなので
今回はその仕組みを使って値を変更してみようと思います。
ホスト側の端末で`override.yaml`に記述することで変更ができるようです。

```yaml:~/Library/Application Support/rancher-desktop/lima/_config/override.yaml
provision:
- mode: system
  script: |
    #!/bin/sh
    sudo sysctl fs.inotify.max_user_watches=24288
```

念の為再起動して、もう1度コンテナ内で次のコマンドを実行してみると無事に値が変わりました。

```shell
$ cat /proc/sys/fs/inotify/max_user_watches
24288
```

今回初めてDockerまわりの設定をいじる機会だったのですが、もう少しこのあたりの仕組みも理解していきたいですね。
無事にfrourioも動いたのでようやく触って遊べそうです。
Laravelのコンポーネントとサブビューと@each【個人的なお勉強アウトプット】

## 参考図書
https://www.amazon.co.jp/dp/B07CLLW4MX/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

## コンポーネント
継承を利用したレイアウトは、親レイアウトの必要な部分にはセクションをはめこんで表示する。
このやり方は全体を一式そろえて作成するのに便利。
しかし、ときには一部を切り離して組み込みたいということもある。
例えばタイトルやフッターの表示などは、それぞれ独立した部品として用意しておけば便利。
切り離しておけば、必要に応じてそれらの部品だけを修正すればサイト全体を更新できるようになる。

@componentというディレクティブをつかって表示場所を設定する。


### コンポーネントのテンプレートファイル
```/resources/views/components/message.blade.php
<div class="header">
<p>{{$msg_title}}</p>
<p>{{$msg_content}}</p>
</div>

```

### 読み込むテンプレートファイル
```/resources/views/index.blade.php
@component('components.message')
@slot('msg_title')
タイトルだよ
@endslot

@slot('msg_content')
メッセージの表示だよ
@endslot
@endcomponent
```
@componentで読み込むファイルを指定。

#### `@slot`
コンポーネントファイルの中に`{{$msg_title}}`、`{{$msg_content}`という変数を用意していた。
コンポーネントを利用するときに、変数に必要な値を渡せる。


## サブビュー
単純に用意したテンプレートをただはめ込んで表示する場合にはサブビューが良い。
普通のテンプレートを用意しておき、そのままはめ込んで表示おくだけのシンプルな仕組み。

### サブビューを読み込む
上記のコンポーネントファイル（message.blade.php）を読み込む場合・・・
サブビューを読み込むテンプレートファイル（index.blade.php）に対して
```/resources/views/index.blade.php
@include('components.message'. ['msg_title'=>'OK','msg_content'=>'サブビューです。'])
```
第一引数でファイルを指定、第二引数で値を連想配列として渡す。
同じキーの名前の変数として値を渡すことができる。

## @eachによるコレクションビュー
あらかじめ用意されていた配列やコレクションから値を取り出し、指定のテンプレートにはめこんで出力するもの。

### 繰り返す指定のテンプレートファイル
```/resources/views/components/item.blade.php
<li>{{$item['name']}}：{{$item['mail']}}<li>
```

### 表示するテンプレートファイル
```/resources/views/index.blade.php
<ul>
@each('components.item',$data,'item')
</ul>
```
$dataという変数を`item`に入れて繰り返す。
コントローラーのアクションメソッドで$dataを用意しておき、渡す。

### コントローラー
```
public function index(){
$data  = [
['name'=>'山田たろう', 'mail'=>'taro@yamada'],
['name'=>'田中はなこ', 'mail'=>'hanako@flower'],
['name'=>'鈴木さちこ', 'mail'=>'sachico@happy'],
];
return view('index',['data'=>$data])
}
```
@eachで一つ一つ配列が取り出され出力される。
@eachはテンプレート名を指定して呼び出すだけだから、新しいテンプレートを作成したらテンプレート名を書き換えるだけでデータの表示をガラリと変えてしまうことができる。
だから便利。
AtCoder Beginner Contest 243 参戦記

# AtCoder Beginner Contest 243 参戦記

終了1分前にE問題が通って、1回で水色に復帰.

## [ABC243A - Shampoo](https://atcoder.jp/contests/abc243/tasks/abc243_a)

4分で突破. 書くだけではあるけど、A問題にしてはむずい.

```python
V, A, B, C = map(int, input().split())

while True:
    V -= A
    if V < 0:
        print('F')
        break
    V -= B
    if V < 0:
        print('M')
        break
    V -= C
    if V < 0:
        print('T')
        break
```

## [ABC243B - Hit and Blow](https://atcoder.jp/contests/abc243/tasks/abc243_b)

4分で突破. 書くだけではあるけど、B問題にしてはむずい.

```python
N = int(input())
A = list(map(int, input().split()))
B = list(map(int, input().split()))

c = 0
for i in range(N):
    if A[i] == B[i]:
        c += 1
print(c)

c = 0
for i in range(N):
    for j in range(N):
        if i == j:
            continue
        if A[i] == B[j]:
            c += 1
print(c)
```

## [ABC243C - Collision 2](https://atcoder.jp/contests/abc243/tasks/abc243_c)

11分で突破. あるYにおいてLの左側にRがいたらアウト.

```python
from sys import stdin

readline = stdin.readline

N = int(readline())
XY = [tuple(map(int, readline().split())) for _ in range(N)]
S = readline()[:-1]

L = {}
R = {}
for i in range(N):
    X, Y = XY[i]
    if S[i] == 'L':
        if Y in L:
            L[Y] = max(L[Y], X)
        else:
            L[Y] = X
    elif S[i] == 'R':
        if Y in R:
            R[Y] = min(R[Y], X)
        else:
            R[Y] = X

for k in L:
    if k not in R:
        continue
    if L[k] > R[k]:
        print('Yes')
        exit()
print('No')
```

## [ABC243D - Moves on Binary Tree](https://atcoder.jp/contests/abc243/tasks/abc243_d)

13分半で突破、TLE1. 上に行くと半分(端数切捨て)になって、左下に行くと倍になって、右下に行くと 2*n*+1 になることを確認した瞬間に Python はオーバーフロー無いしと出して無事死亡. 下行って上はキャンセルなので、それを再帰的に消せれば OK かなと思ってスタックで消したら通った.

```python
N, X = map(int, input().split())
S = input()

q = []
for c in S:
    if c == 'U' and len(q) != 0 and q[-1] != 'U':
        q.pop()
    else:
        q.append(c)

for c in q:
    if c == 'U':
        X >>= 1
    elif c == 'L':
        X <<= 1
    elif c == 'R':
        X <<= 1
        X += 1
print(X)
```

追記: 2進数の文字の列としてやると消さなくても行ける.

```python
N, X = map(int, input().split())
S = input()

a = list(bin(X))[2:]
for c in S:
    if c == 'U':
        a.pop()
    elif c == 'L':
        a.append('0')
    elif c == 'R':
        a.append('1')
print(int(''.join(a), 2))
```

## [ABC243E - Edge Deletion](https://atcoder.jp/contests/abc243/tasks/abc243_e)

65分半で突破、WA1. 他を経由するルートが直通以下の距離であればその辺は不要というポリシーで数えたら合っていたらしく通った.

```python
from sys import stdin

readline = stdin.readline

def warshall_floyd(n, d):
    for i in range(n):
        for j in range(n):
            for k in range(n):
                d[j][k] = min(d[j][k], d[j][i] + d[i][k])

INF = 10 ** 15

N, M = map(int, readline().split())
ABC = [tuple(map(int, readline().split())) for _ in range(M)]

d = [[INF] * (N + 1) for _ in range(N + 1)]
for k in range(N):
    d[k][k] = 0
for a, b, c in ABC:
    d[a][b] = c
    d[b][a] = c
warshall_floyd(N + 1, d)

result = 0
for a, b, c in ABC:
    for x in range(1, N + 1):
        if x in [a, b]:
            continue
        if c >= d[a][x] + d[x][b]:
            result += 1
            break
print(result)
```
初心者ブロックチェーンに挑戦する　18

# 学ぶは真似ぶである。

　引き続きNFTをつくる。昨日はImgurに画像をアップして、そことリンクする形でつくったが、どこか１カ所に置いたデータは、その１カ所がダウンすればだめになってしまう。
　同じことは、JSONkeeperに置いたメタデータにもいえる。

　なので今日は、NFTそのものをブロックチェーンに刻んでしまう「on chain」を学ぶ。

- 画像をSVGで表記する。･･･ここはよくわからないので、丸写し。
- このSVGコードをエンコードしてbase64に変換する。・・・[変換サイト](https://www.utilities-online.info/base64)がやってくれる。
- data:image/svg+xml;base64,{変換したコード}　をブラウザのアドレス欄に貼り付けると、あら不思議、画像が出る。
- 変換されたbase64を使って、jsonファイルでNFTのメタデータをつくる。
- このメタデータ全体をさらにbase64にエンコードする。
- 新しい入れ子のbase64をsolidityファイルに貼ってdeployすると、はい、NFTのできあがり。

　明日は、丸写しだった元画像を編集して、オリジナルにします。
　randomと配列が出てくるらしい。
　つまり、サイト上でNFTほしいです、とクリックしたら、randomなNFTが出てくる。好きなの選べんのかい！ていうか、当たり外れがある、という仕組みらしい。

　ちなみに、もうできあがった人のサイトで挑戦して、はずれました笑
　さあ、明日も頑張ろう〜。
Python リスト内包表記とmap,lambda攻略(基礎)

# リスト内包表記はよく見かけるので、仕組みを理解しよう(ついでにmapやlambdaも)

## 目次
01. [リスト内包表記](#listin)
02. [リスト内包表記_if文](#listin_if)
03. [lambdaやmap](#lambda)

---
### 今回使用するテストデータは以下とします

```python
TestList = [1,2,3,4,5]
```



<a id="listin"></a>
## 01.リスト内包表記

リスト内の要素に対して演算(２倍)をします

```python
processed_list = [num*2 for num in TestList]
```

この結果は以下になります
```
[2,4,6,8,10]
```

---

あえて、言葉で書くならこんな感じでしょうか。

![スクリーンショット 2022-03-21 21.03.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/906162/f0a169fb-903f-4d56-27dd-c97bcc5e4917.png)


---

<a id="listin_if"></a>
## 02.リスト内包表記(if文)

偶数の値に対して演算(２倍)し、リストに残留させます

```python
processed_list = [num*2 for num in TestList if num%2 == 0]
```

この結果は以下になります

```
[4,8]
```
奇数に関してはリストにすら残りませんでした
言葉で書くならこんな感じです。

---

![スクリーンショット 2022-03-21 21.32.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/906162/971c2b04-1eeb-2661-6646-93f0e9d08661.png)

---

奇数もリストに残したい場合は「else」を使います(※elifは使えません)

elseも書く場合は、if文(条件式)とforの順番が入れ替わります

```python
processed_list = [num*2 if num%2 == 0 else num for num in TestList]
```

順番が逆になるものの、考え方は同じです

※else pass は効かないのでそのままnumを残留させています

<a id="lambda"></a>
## 03.lambdaやmap

### lambda(無名関数)

lambdaとは...
一言で言えば def と同じです
ただdefで書くにはおおげさだなーっていう時に使われたりします。

書き方は以下です

```
lambda 引数: 返り値
```


#### 例
●値を２倍する関数

defだと

```python
def double(n):
    n = n*2
    return n
```

lambdaだと

```python
double = lambda n:n*2
```
変数にいれてあげるとdefで定義したのと同じ操作ができます
よって、どちらも以下のように関数を使えます

```python
double(1)
```

outputは
```
2
```

１回で分からなくても数回読み返せば理解できるはずです！

リスト内包表記みたく１行で書くには...map関数を使います


---

### map

mapとは...
リスト、タプルなどの複数要素を持つデータ型に対して、それぞれの要素に同じ処理を行なうための関数です
(for文が不要になります！)

書き方は以下です

```
map(関数, シーケンス)
```
シーケンスには,リストやタプルの処理させたいデータが該当します
では、早速例で確認していきましょう

#### 例

●値を２倍する

使用するリストデータは同様に以下のものを使います

```python
TestList = [1,2,3,4,5]
```

```python
map_output = map(lambda n:n*2, TestList)
```
アウトプットは
```python
<map at 0x7fb609b08f10>
```
オブジェクトが出てきました。

リストで欲しいので、リストとして出力しましょう。

```python
list(map_output)
```

アウトプットは

```python
[2, 4, 6, 8, 10]
```

無事できました。

一見難しそうですが、
冷静になれば大したことは無いです。

諦めず理解しましょう！
5分で終わるpython & jupyter labの導入方法

# はじめに
この記事はpythonの導入から、jupyter labの導入までを行う記事となります。
windows環境の記事となります、macは保証していないためご了承ください。

# pythonの導入
以下のサイトにアクセスし、pythonをダウンロードします．

https://www.python.org/

サイトより、Downloads→ Python3.9.5(当時の最新版)をダウンロードします．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1679717/23685f9f-e5c3-a0c9-4761-b36dc379dec7.png)

ダウンロードが終わり、ファイルを起動すると以下のような画面となります。

:::note alert
**この際に必ず「Add Python 3.9 to PATH」にチェックを入れてください．**
:::
※もし入れ忘れてもあとで環境変数をいじればパスを追加できますが面倒です。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1679717/8ed158c5-f6f2-8178-ccdb-2f7135dd5acc.png)

その後Install Nowをクリック。

そのまま進めるとpythonのインストールが完了します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1679717/17ef53c5-4e01-b249-8f60-a68c0084f6cc.png)

# jupyter labの導入
コマンドプロンプトをおよびpipコマンドを使用してjupyter labを導入していきます。

winキー + R を押すと出てくる
「ファイル名を指定して実行」ダイアログに [cmd] と入力してOK（Enter）します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1679717/63ca751d-2b9f-1254-92d3-e37d28511b64.png)


出てきたコマンドプロンプトに以下を入力してEnterを押します。
```
pip install jupyterlab
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1679717/8c939a7d-f8d1-2f7a-d40c-835041a6832c.png)


放っておくと順次jupyter labがインストールされていきます。

※ここでpipに関するエラーが出た場合、pythonのダウンロード時に「Add Python 3.9 to PATH」にチェックを入れ忘れている可能性があります。
where pythonなどのコマンドを入れてpipのパスを確認後，環境変数を追加すると動くと思いますが、ここでは詳細を割愛させていただきます。

# jupyter labの起動
ダウンロードが無事終われば、同様にコマンドプロンプトで以下を入力しEnterを押すと
jupyter labが起動します。お疲れさまでした。

※スペースも判定されるため注意してください．
```
jupyter lab
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1679717/05d0d326-887a-e428-812a-80d83530f184.png)

一つのコマンドプロンプトに対し一つのjupyter labが対応しています。
終了するときはコマンドプロンプトをシャットダウンしてください。
PaperMCをインストールスクリプトで立ててみた

これまで何度かマイクラサーバーをバニラで立てたことはあるのですが、PaperMCというのは多分立てたことがなかったように思います。

## PaperMCとは

PaperMCというのは、Spigot(※)と互換性のあるマイクラサーバーソフトウェアで、軽いのが大きな特徴のようです。

https://papermc.io/

※Spigotというのは、とてもメジャーなマイクラサーバーソフトウェアで、たくさんのMODで遊ぶことができるのが大きな魅力みたいです。

## PaperMCのインストールスクリプト

先日、このPaperMCのインストールスクリプトが公開されているということを教えていただきました。

https://github.com/sakurayoru/installpapermc

これを使えば、私でもPaperMCがインストールできるかも……

## PaperMCをインストールスクリプトでインストールしようとしてみた

というわけで、早速トライしてみました。

さくらのクラウドでRockyLinux8.5のサーバーをさくっと立てて、root権限でインストールスクリプトを実行してみたのですが……それだけだとうまく動きませんでした。

インストールスクリプトの作者さんに助言いただきつつ（ありがたや……）いろいろ確認してみたところ、どうも、Javaのバージョンが古い（1.8.0）ためにうまく起動できなかったようです。新しいバージョンのJava(17.0.2)もインストールされていたのですが、alternativesというコマンドで切り替えてあげる必要があるようでした。

```
alternatives --config java
```

それを切り替えれば、無事起動できました！

## インストールスクリプトによる、マイクラサーバーのサービス化

このインストールスクリプトを使えば、サービス化してくれたり、 screen コマンドで起動したりしてくれて助かりました。

サービス化は、起動や終了のスクリプトを作って実行権限付与して、 `/etc/systemd/system/` の中にそのあたりを含んだサービスの定義ファイルを所定の書式で書いて保存すれば、`systemctl start hoge` といった感じでサービスとして扱えるようになるようでした。

## マイクラサーバーをscreenコマンドで起動するメリット

また、PaperMCの起動は screen コマンドを使用して行い、sshのセッションが切れてもサーバーが落ちないようになっていました。

さくらのクラウドには、シリアルコンソール機能があるので、ここで起動しておけば安心ではあったのですが、こういった機能がない時には、screen等の仮想端末から起動するのが常套手段のようです。

screen、ほとんど使ったことがなかったのですが、これを機に勉強したいと思います。


## その他、参考にさせていただいたページたち
感謝！

https://mattyan1053.hatenablog.com/entry/2022/01/29/210202

https://arkgame.com/2021/11/12/post-301717/

https://qiita.com/hnishi/items/3190f2901f88e2594a5f