OmniAICreator/Qiita-1.07M huggingface dataset:
Windows/Linuxにおけるtraceroute(トレースルート)の違い【ポート番号】

障害対応の際、とあるホストへ対して「traceroute」を打ったのだがLINUXサーバとWindwosサーバで異なる結果になった。理由は通信時において使用されるデフォルトのプロトコル/ポート番号の差異によるものだった。備忘録として記事にした。

# 原因
■Linux
プロトコル：UDP（ポート番号：33434～33499）

■Windows
プロトコル：ICMP

上記のように、デフォルトでtracerouteコマンドを打った場合、プロトコル/ポート番号が異なる。コマンド実行端末と対象ホストの間にファイアウォール(以下、FW)があり同FWのアクセスルールにおいて、別LANからのICMPは許可していたのだが、UDPは許可していなかった。これにより、結果に差異が生じたものである。

# 備考
LINUXの場合、以下のようにオプション[I]を指定すればICMPでtracerouteを実行できる
```
traceroute -I 192.168.0.XX
```
(UDP通すためにFWを弄るのがめんどくさい...社内申請的な意味で)

これにより、Windows(tracert 192.168.0.XX)と同じ結果を得られた。
ChatGPTに関するRailsの小ネタ

# 出来事
rails_adminにエディタを挿入する業務を行なっているとrails6とrails7で仕様がだいぶ違っている。chatgbtに相談しても的外れの回答が返ってきており、原因を調べてみた

# 結論
ChatGPTの3.5(無料版)は2021年9月までのデータを元にしているのでrails7の情報は本当に少ないらしい。なのでrails7で複雑な実装(gemをいじる等)は避けた方が賢明
【VSCode】ファイルツリー構造のインデントが浅くて見づらい

# はじめに
最近、VSCodeを使うことが多くなりました。
Xcodeに慣れている自分にとって、VSCodeのファイルツリーはインデントが浅くて見づらいです。
変更することができるっぽいのでやり方を記録しておきます。

# こうなる
|before|after|
|-|-|
|![スクリーンショット 2023-09-08 21.32.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/84677ff8-7e5e-459e-a274-79a526cc8284.png)|![スクリーンショット 2023-09-08 21.32.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/002b7384-6f8a-fff8-8635-f011f8a0e218.png)|

# やりかた
① 「Code」を選択します
② 「基本設定」を選択します
③ 「設定」を選択します
![スクリーンショット 2023-09-08 21.26.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/3c7f9c9a-9204-5c38-f1fc-9f3d8193fa9d.png)

④ `tree indent`を検索します
![スクリーンショット 2023-09-08 21.29.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/172672b6-f82d-d455-3600-442741067e85.png)

⑤ 「Workbench > Tree Indent」の数値を変更します
![スクリーンショット 2023-09-08 21.30.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/fbb5d793-ecbd-e028-1586-5d44912de070.png)

# おわり
めっちゃ見やすくなりました！
Excelで週次レポートのグラフ更新を楽に

## 本Excelを作成する背景と問題意識
KPIのモニタリングを週次で行う際に、Excelで可視化するとデータの更新のたびにグラフの範囲を変更する必要がある。
具体的には当週+過去24週の25週間分を可視化しつつ、毎週新しいデータを追加してグラフを更新していきたいという場合、最新週のデータを貼り付け、グラフの範囲を1行下にずらすという作業が発生する。
例えば以下のような形式であれば、9/25〜のデータを貼り付けたあとにそれぞれのグラフの範囲を2行目から26行目→3行目から27行目というふうに動かす必要がある。またグラフの数が多ければその分手間がかかり、更新漏れが発生する可能性も高くなる。
![データ&可視化.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1127172/1f30515c-3846-f22d-ef76-b727e5670c4b.png)

## 解決策
**データシートと可視化シートを分ける&必要データを関数で引っ張ることで更新を自動化する。**
データシートに最新週のデータを追加していく。
![データ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1127172/ff70ac56-cf49-870d-868b-470152cfd2b8.png)

可視化のシートでは、A26のセルを最新週に変更するのみ。
![可視化_更新前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1127172/8b72d73d-679a-3b9d-ab52-2688ed1fa019.png)

以下のように、A26のセルに入力した日付に応じて前の日付、該当週のデータ、グラフがすべて更新される。
![可視化_更新.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1127172/8e10b145-7a89-c906-4ccc-764293e1bd55.gif)

数式は以下の通り。（先頭の"="を削除した式を表示）
![数式.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1127172/4d66b736-8ca2-8b48-1f4f-fe0a4ff670a0.png)
【試験中にMSLearnが見えるようになった】AZ-400に合格した！

# 0. 自己紹介
こんにちは、yuzu_juiceです🥂
インフラ畑でセキュリティエンジニアをやっています。今2年目です。
クラウド資格はこんな感じで持っています↓
- AWS: CLP, SAA, SOA, DVA, SCS
- Azure: AZ-104
- OCI: Foundations Associate

AZ-400の勉強を始める前は、DevOpsはまったくの未経験。
CI/CDって聞いたことがあるけどよくわかんない、くらいの知識でした。
Gitの知識もほぼなく、commitとpushの違いをよく分かっていませんでした。

# 1. 受験の背景と感想
## 1.1. どうして受験しようと思ったか
https://qiita.com/hikiroku/items/0c25815067b1b60a5885

こちらの記事を見て、いい機会なので何かとってみようかなと思い、今まで全く縁のなかったDevOpsに挑戦してみようと思いました。

https://techcommunity.microsoft.com/t5/microsoft-learn-blog/introducing-a-new-resource-for-all-role-based-microsoft/ba-p/3500870

また、こちらの記事が弊社内で話題になっていたのも一つの理由です。
なんとrole-based限定ではありますが、試験中にMicrosoft Learnが見えるように。公式カンニング可能になっちゃいました。
神アプデですね。


## 1.2. 感想
スコアは770/1000 (合格点700)でした。
テストセンターで受験したのですが、Microsoft Learnで検索をするためにキーボードをカタカタする音が意外と大きく、周りの迷惑になりそうだったのでかなり気を使いました。
しかも、Microsoft Learnは予想以上に検索に癖があったのでもう少し試験前に検索力を上げておけばよかった……

# 2. 勉強方法
## 2.1. 総勉強時間
2023年6月から勉強を始め、なんやかんや5,60時間くらい勉強した気がします。

## 2.2. 学習リソース
- **Microsoft Learn**
https://learn.microsoft.com/ja-jp/users/cloudskillschallenge/collections/0168b2eqk760
前述したとおり、Skills ChallengeのDevOpsを1周しました。結構ボリュームがあって大変でした。

- **公式模擬テスト**
https://learn.microsoft.com/ja-jp/certifications/exams/az-400/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3086592/fd07d0f0-dc5b-5a17-ca30-fe312675c159.png)
「無料の練習用評価を受ける」から、50問の模擬テストを受けることができます。
何度でも受けることができましたし、出題内容も毎回全く同じではありませんでした。おそらく、内部的には100問くらいの問題があるように感じました。
この模擬テストは5周くらいしました。

- **Azure DevOpsを触ってみた**
https://azure.microsoft.com/ja-jp/products/devops
無料で利用することができるので、一通り触ってみました。

- **Github ActionsでCI/CDのハンズオン**
https://www.udemy.com/share/107ZWS/
Udemyでこちらのコースを受講しました。これがだいぶCI/CDの解像度を上げるのに役立ちました。

# 3. まとめ
AZ-400は、ネット上にもあまり情報が無く苦労する部分も多かったですが、DevOpsに関する知見を深めることができてエンジニアとして一歩前進できました。
副産物ですが、DevOpsについていろいろと調べていくうちに、SREについても少し知ることができました。

今後もスキルアップを頑張っていきます🥂
Zig言語でUTF-8の日本語を出力(Windows)

Zig から派生した Zen 言語では Windows 上でも UTF-8 で書かれたソース(文字列)をなんの手を加えることもなく、コンソールに表示させることができますが、Zig for Windows では、コマンドプロンプトで予め「chcp 65001」としてUTF-8モードにしておかないと文字化けします。

以下のソースは、Zen言語で自動的に追加される「SetConsoleOutputCP」関数(Win32 API)を手動で追加したものです。mainの先頭で一回呼んでおけば、それ以降のコンソール出力がUTF-8を正常に受け付けるようになります。(chcp 932 の状態でも表示されます。また、chcp 932 の状態でも韓国語やアラビア語も表示できます)

```zig:main.zig
const std = @import("std");
const windows = @import("std").os.windows;
const WINAPI = windows.WINAPI;
const BOOL = windows.BOOL;
const UINT = windows.UINT;

extern "kernel32" fn SetConsoleOutputCP(wCodePageID: UINT) callconv(WINAPI) BOOL;

pub fn main() anyerror!void {
    _ = SetConsoleOutputCP(65001);
    std.log.info("Zig の道へようこそ。\n道案内はこちらからどうぞ：\nhttps://ziglang.org/ja/\n", .{});
    std.log.info("漢字(韓国語)=한자\n漢字(アラビア語)=كانجي\n", .{});
}
```

英語圏以外(でかつ Windowsのコンソールアプリ)なら必須の処理なので Zen 言語のように処理系が隠蔽してくれてもよさげに思いますが、「隠された処理」を嫌う Zig では取り込んでもらうのは無理かもしれません。

せめて、Linux や macOS とソースを同一化するために、「SetConsoleOutputCP」関数の宣言と呼び出しを Windows でない場合には削除したいのですが、どうすればよいのかわかりません。もしわかる人がいたら教えてください。

それでゃ！

<b>追伸：</b>
https://zenn.dev/javacommons/articles/de2a99ecf588f9
のコメントにあるように以下のコードで Windows と Ubuntu で同一ソースで日本語(UTF-8)を出力できました。

```zig
const builtin = @import("builtin");
const std = @import("std");
const windows = @import("std").os.windows;
const WINAPI = windows.WINAPI;
const BOOL = windows.BOOL;
const UINT = windows.UINT;

extern "kernel32" fn SetConsoleOutputCP(wCodePageID: UINT) callconv(WINAPI) BOOL;

pub fn main() anyerror!void {
    switch (builtin.os.tag) {
        .windows => _ = SetConsoleOutputCP(65001),
        else => {}
    }
    std.log.info("Zig の道へようこそ。\n道案内はこちらからどうぞ：\nhttps://ziglang.org/ja/\n", .{});
}
```

----

## 追伸1

以下の質疑応答で解法がいくつかみつかりました。Windowsオンリーのアプリだったら、この記事のように main.zig にベタ書きでもいいと思いますが・・・(意見交換継続中。また zig のバージョンが上がったら修正します)

https://qiita.com/javacommons/questions/d4bc7527b59e68b7bf44

----

## 追伸2

zig 言語を現在使っている方の多くはリリース毎にブレーキングチェンジが入り、自作のコードが動かなくなったり、AIが提供してくれるサンプルコードがすぐ古くなりこちらも動かないということが頻発していると思います。
そこで、zig の動かないコードを動くように手助けするための「意見交換」を立ち上げました。

https://qiita.com/javacommons/questions/7b975368f8e03d0656e5
インターンから学ぶ「テスト」

## この記事の位置づけ
先日まで行っていたインターン中に触れた事項について復習しながらまとめる記事となっています。自分の感じたことを残しておくという意味で書いている側面もあるので、誤りも多々あると思いますがご容赦ください。これら気が向いたらご指摘いただけると幸いです。

この記事ではテストについて記述します。インターンで行ったのはウォーターフォール開発における結合テストのテスト設計となります。このため、テスト設計全般に適用される内容のものと結合テストのみに適合した話と混同されていることも多々あるかと思いますがご了承ください。

## テスト設計とは
テストは記述したコードが仕様（あるいは設計書・処理記述書）通りに動作するかを確認する過程を指します。このテストでどのような場合を確認するかを記述するのがテスト設計となります。このため、テスト設計では入力の条件とその結果の出力（画面の状態）をペアにして複数の場合を列挙する形を指します。

## テスト設計書の記述
（企業などによって記述のフォーマットなどは異なるかと思いますが、私が経験した内容を基に以下を記述します）
テスト設計書には以下の２つの内容を記載します。
* データパターン
テストで確認する項目（因子と言います）ごとにその項目がテストにおいて取りうる値（水準と言います）を表として列挙します。後述する分析方法によって項目の記述内容は変化します。
* テストパターン
各項目に対して、データパターンで記述した値を割り当て、その割り当てに対して期待する結果を記述します。

### データパターンの考え方
データパターンでは因子と各因子の水準の値を記述する必要があります。
#### 因子の決め方
後述の水準ほどはっきりとした決め方はない印象ですが、しいて言うならテストで確認する内容に必要な入力を因子として洗い出すことになります。テスト設計書の記述を分かりやすくするために確認するエラーを「入力の欠損」「入力値の異常」などの項目に分けることがある（後述）ので、それに合わせて因子と水準を決めることになります。

#### 水準の決め方
水準の決め方には同値分割・境界値分析があります。
* 同値分割
入力値に対する処理が同じになるように入力値をグループ分けし、グループ内で代表的な入力値を選択
* 境界値分析
入力値に対する処理が変化する境界の値をテストケースとして選択
「内部のDB処理で検索条件に等号を含むか否か」など、境界で仕様とは異なる動作をする場合があるので、境界値分析は有効になります。

状況に応じて使い分けましょう。
（インターンだと境界値分析でテスト設計を組みました）

### テストパターンの考え方
#### 因子間の組み合わせ
テストパターンは２因子間網羅をするとよいとされています。
（２因子間網羅：２つの因子間の状態の組み合わせを網羅した状態となっています）
テストパターンとして全ての因子の組み合わせをテストする全網羅組み合わせを行うことも考えられますが、それをすると、（水準数）^（因子数）というとんでもないテストの数になるので、現実的には２因子間を考えるのが現実的です。
これは、因子単体では問題が起こらないが、複数因子の組み合わせでは問題が起こるという場合の検出に有効だからだったりします。
３因子間網羅など網羅するパターンを増やすことも考えられますが、テスト数が膨大になるので、工数とソフトウェアの重要度に合わせて考えるとよさそうです。
２因子間網羅を満たす組み合わせを作成する手法には直行法やAll-Pairs法などがあるようですが、ここでは割愛します。

（インターンでは時間の都合上各因子一つずつを変更したものと、複数項目による問題がないかだけ確認する設計をすることになりました）

## テスト設計書の注意
前述の内容を多々含みます。

テストする項目は入力値の欠損・異常など複数の項目に分類することができます。そのため、各項目ごとにデータパターンとテストパターンを分けて記述するようにしましょう。これは、１つテストパターンに多くの項目を記述することにより表が膨れ上がり、わかりにくくなることを防止するためです。

## この記事が触れていない内容について
以下は備忘録的に私が今後学ぶ必要がある内容がある内容について記述しておきます。
### テストの種類について
テストは複数の軸によって以下に示すように分類できます。
* 単体テスト・結合テスト・システムテスト
* 開発者テスト・受け入れテスト
* ホワイトボックステスト・ブラックボックステスト
* リグレッションテスト
* モンキーテスト・探索的テスト
など

### テスト自動化について
テストを自動化していない場合、製品を改良した後にテストをやり直すのがかなり面倒になります。また、リファクタリングで動作が変わらないことを保証するという点でもテストを固定することが有効になります。これに役立つのがテストの自動化ツールになります。Playwrightなどの自動化ツールの記述方法は覚えておいた方がよさそうです。（最も、Playwrightだとボタン操作を記録してテストコードを生成する機能とかあるので、あまり書かなくてもよいかもしれませんが）

## 終わりに
以上で「インターンから学ぶ『テスト』」は終了です。また、学習する機会がありましたら追記していきます。
Python 3 エンジニア認定基礎試験の資格勉強方法

一般社団法人Pythonエンジニア育成推進協会のPython 3 エンジニア認定基礎試験に2023年1月に合格したので、勉強方法を共有します。

# 試験概要
概要としては以下2つがわかりやすくまとまっている。

https://www.pythonic-exam.com/exam/basic

https://www.wata-ridley.com/entry/certified-test-python3


# 勉強方法
試験概要にて記載している公式サイトにて試験範囲や学習方法等ひと通り記載してあるのでおすすめ。


## 教科書
試験公式サイトの出題範囲のところに本の版数やPythonのバージョンが記載されているので確認したほうがよい。本とWEBともに内容は同じなので好みの方で学習できる。
* Python公式のチュートリアル
* オライリー・ジャパンの「Pythonチュートリアル」

https://docs.python.org/ja/3/tutorial/

https://www.amazon.co.jp/dp/4873119359

## 問題集
PRIME STUDYやDIVERにて模擬試験というかたちだが、無料で学習できる。
※どちらも会員登録は必要

https://study.prime-strategy.co.jp/

https://diver.diveintocode.jp/python_basic/lp
【kotlin】超簡単なMVVMを実装してみた、②異なるレイアウト(Fragment)との連携



# 実装内容
・Activity(親View)の下半分にFragment(子View)を重ねる。
・ACTIVITYボタン(紫文字)が押された際に双方ViewのTextViewに1を足し、表示する。
・FRAGEMENTボタン(赤文字)が押された際に双方ViewのTextViewに10を足し、表示する。
![Screenshot_20230908_200445.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784089/5bb9e1f6-1873-a37e-4e6c-5ddefc80db9e.png)

下記のURLと動作は同じです
https://qiita.com/Na0yaKub0/items/76854a1dfc79dc978c3e

**[コード]**
**・ViewModelの設定**

```kotlin:
class MainViewModel : ViewModel(){

    private val _cnt: MutableLiveData<Int> by lazy { MutableLiveData<Int>(0)}
    val cnt: LiveData<Int> = _cnt

    // Activity側のボタンが押された時の処理
    fun onClickActivityButton() {
        _cnt.value = _cnt.value?.plus(1)
    }

    // Fragment側のボタンが押された時の処理
    fun onClickFragmentButton() {
        _cnt.value = _cnt.value?.plus(10)
    }
}

```

**・Fragment(子View)設定**
```kotlin:
class MainFragment : Fragment() {

    private lateinit var binding: FragmentMainBinding
    private lateinit var viewModel: MainViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // viewBinding初期化
        binding = FragmentMainBinding.inflate(inflater, container, false)
        // 親のviewからViewModel初期化
        activity?.let {
            viewModel = ViewModelProvider(it)[MainViewModel::class.java]
        }

        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.fragmentButton.setOnClickListener {
            viewModel.onClickFragmentButton()
        }

        //  LiveDataを読み込み反映
        viewModel.cnt.observe(viewLifecycleOwner, Observer  {
            binding.fragmentTextView.text = it.toString()
        })

    }
}
```

**・Activity(親View)設定**
```kotlin:
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // viewBinding初期化
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
        // Fragment生成
        val transition = supportFragmentManager.beginTransaction()
        transition.add(R.id.fragmentLayout, MainFragment())
        transition.commit()
        // ViewModel初期化
        viewModel = ViewModelProvider(this)[MainViewModel::class.java]

        binding.activityButton.setOnClickListener {
            viewModel.onClickActivityButton()
        }

        //  LiveDataを読み込み反映
        viewModel.cnt.observe(this, Observer {
            binding.activityTextView.text = it.toString()
        })
    }
}
```
reactでpdf比較

reactでpdfを比較
```react
import React, { useEffect, useRef } from 'react';
import WebViewer from "@pdftron/webviewer";
import { Subject } from "rxjs";

function PDFComparison() {
  const viewerRef = useRef(null);
  const documentLoaded$ = new Subject();
  let wvInstance = null;

  useEffect(() => {
    const initWebViewer = async () => {
      const instance = await WebViewer({
        path: '../lib',
        fullAPI: true,
      }, viewerRef.current);

      wvInstance = instance;

      const { documentViewer, Annotations } = instance.Core;

      instance.UI.openElements(['notesPanel']);

      documentViewer.addEventListener('annotationsLoaded', () => {
        console.log('annotations loaded');
      });

      const { UI, Core } = instance;
      const { Color } = Annotations;

      UI.addEventListener(UI.Events.MULTI_VIEWER_READY, () => {
        const [documentViewer1, documentViewer2] = Core.getDocumentViewers();

        const startCompare = async () => {
          const shouldCompare = documentViewer1.getDocument() && documentViewer2.getDocument();

          if (shouldCompare) { // Check if both documents loaded before comparing
            const beforeColor = new Color(21, 205, 131, 0.4);
            const afterColor = new Color(255, 73, 73, 0.4);
            const options = { beforeColor, afterColor };
            await documentViewer1.startSemanticDiff(documentViewer2, options);
          }
        };

        documentViewer1.addEventListener('documentLoaded', startCompare);
        documentViewer2.addEventListener('documentLoaded', startCompare);
        documentViewer1.loadDocument('http://localhost:4200/files/fluffy.pdf');
        documentViewer2.loadDocument('http://localhost:4200/files/scooby.pdf');
      });

      UI.enableFeatures([UI.Feature.MultiViewerMode]);
    };

    initWebViewer();
  }, []);

  return (
    <div>
      <div ref={viewerRef}></div>
    </div>
  );
}

export default PDFComparison;

```
PDFComparison.ts

```React
import React from 'react';
import PDFComparison from './PDFComparison'; // PDFComparisonコンポーネントのファイルパスに適切なものを指定

function App() {
  return (
    <div className="App">
      <PDFComparison />
    </div>
  );
}

export default App;
```



App.tsx
node.jsの切り替え

うっかりnode.jsを最新版にすると、古いプロジェクト（Vue CLI）で、モジュールの互換性でエラーになることが多々あるので、nvmを使って簡単にバージョン管理しちゃいましょう。
**コマンドプロンプトは管理者権限で実行します。**

```dos:インストールされているバージョン一覧
nvm list
    18.17.0
  * 12.13.0 (Currently using 64-bit executable)
```
```dos:バージョン切り替え
nvm use 18.17.0
  Now using node v18.17.0 (64-bit)
```
```dos:バージョンを指定してインストール
  nvm install 12.13.0
```

20250411 追記）
新しいnodejs(22系)をwindowsのインストーラーから入れたら上記ができなくなりました🙃
22系をアンインストール、18系をインストール、nvm unistall で12系を削除して再度install
みたいな作業で復元しました。
バージョンアップは上記の通りnvm installが良いかもね！
【プラクティス紹介】1分でさらっと分かる「Readyの定義」

## プラクティス名（別名）
Readyの定義 （DoR、Definition of Ready、Entry Criteria、準備完了の定義、READY-read）

## プラクティスの目的・狙い
* PBIがスプリント投入できる状態かどうかを判断する基準を明確にする
* PBIをスプリント投入できる状態にするための準備作業を明確にする

## どんな時に使うか
* PBIをスプリントに投入したが、いざ取り掛かると準備不足で次スプリントに回す、といった事態が頻発する時

## 実施手順
1. PBIをスプリントに投入可とする前提条件をチームで話し合って箇条書きにする
1. スプリントプランニングでPBI選択する際、「Readyの定義」を満たしてることを確認する
1. 近々投入予定のPBIは「Readyの定義」を満たせるように準備を進めておく

:::note info
「Readyの定義」の記載例
* POがユーザストーリーの詳細をDEVに説明できる状態であること
* そのストーリーに価値があることが確認できていること
* ストーリーの記述が概ねINVEST原則に沿っていること
* ストーリーポイントの見積もりが最新化されていること
* 1スプリントに収まるサイズに細分化されていること
* ストーリーの受け入れ条件（AC）が明確化されていること
* テストやデモが実施可能であること
* 技術的に実現できることが検証済みであること
* 実装に必要な情報がドキュメント化されていること
* その機能やサービスの利用者が明確になっていること
* その機能に関係するステークホルダーがスプリントレビューに参加可能であること
* システム影響調査が済んでいること
* 連携が必要な他チームとの調整が済んでいること
* 今回のスプリントゴールと関係があること
:::

## アレンジ例
* PBL上で「Readyの定義」を満たしているものは行の色を変えるなど判別しやすくする
* SBL作成時に「Readyの定義」から導き出される準備作業をタスクに含める

## アンチパターン
* 「Readyの定義」が多すぎて、それを満たすための準備作業の方がメインになってしまっている
* 厳密に運用しすぎて、逆にフロー効率を悪くしてしまう

## 参考情報
言わずと知れたryuzeeさんのブログです。いつも助けられております。（感謝）

https://www.ryuzee.com/contents/blog/4264


## こぼれ話（私的コメント）
ryuzeeさんの別の記事で「生煮えのPBIを食べる（＝スプリント投入する）と、消化不良（＝作り切れない）でおなかを壊す」という表現があり、分かりやすい例えだな、と思いました。

この記事を書くにあたり、「Readyの定義」の具体例を探しましたが全然出回ってなくて、このプラクティス自体、あまり採用されていないのかも、と思ってしまいました。個人的には「完成の定義」並みに有用なプラクティスだと思っているんですけどね。どうなんでしょう。

こうして記載例に書かれている項目を眺めていると、PO/SM/DEVそれぞれに準備すべきダンドリがあることが見えてきます。ただ記載例に挙げた項目を全て採用すると少し多すぎる気もするので本当に必要なものだけを取捨選択した方がよいと思います。また現場ごとに満たすべき条件は色々と変わってきそうです。

アンチパターンにも書きましたが、やりすぎると「勝てる試合しかしない」みたいなチームになってしまいそうなのでほどほどが良いかと。

-----
　[アジャイルプラクティス一覧へ戻る](https://qiita.com/kakashi_h5/items/20584998c5ca4594b9ea)
【kotlin】超簡単なMVVMを実装してみた、①ViewModelの実装

# MVVMとは?
Androidアーキテクチャの一つ。
ActivityやFragmentで行っていた処理を以下の三つの役割に分ける。

・Model(データに関する処理を行う)
・View(画面に関する処理、クリック等のイベントを拾ってViewとModelに送る処理を行う)
・ViewModel(ViewとModel間で、情報を加工・伝達する処理を行う)

# 実装内容
EditTextに文字を入力してボタンを押したら、下部のTextViewに表示させる(超簡単)。
![Screenshot_20230908_183356.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784089/45dc5a78-0194-4545-68d7-eb03e36f3221.png)

下記のURLと同じ動作です。
https://qiita.com/Na0yaKub0/items/d688c440dfa9c3a49a7f

# 実装
**・ViewModelの設定**

```kotlin:
class MainViewModel : ViewModel(){

    private val _textViewStr: MutableLiveData<String> by lazy { MutableLiveData<String>("")}
    val textViewStr: LiveData<String> = _textViewStr

    //　ボタンをクリックしたときの処理
    fun onClickButton(text: String) {
        _textViewStr.value = text
    }
}

```

**・View設定**
```kotlin:
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // viewBinding初期化
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
        // viewModel初期化
        viewModel = ViewModelProvider(this)[MainViewModel::class.java]

        binding.button.setOnClickListener {
            viewModel.onClickButton(binding.editTextText.text.toString())
        }

        //  LiveDataを読み込み反映
        viewModel.textViewStr.observe(this, Observer {
            binding.textView.text = it
        })
    }
}

```
PythonでWord文書にテキストや画像の透かしを入れる

Word文書には、半透明のグラフィックやテキストをドキュメントの背景に追加することができる透かし（ウォーターマーク）があります。これにより、文書の独自性を保護し、未承認のコピーまたは使用を防ぐことができます。セキュリティの役割だけでなく、透かしは文書の作成者の情報を表示したり、追加の文書情報を表示したり、単に文書の装飾に使用することもできます。この記事では、[Spire.Doc for Python](https://www.e-iceblue.com/Introduce/doc-for-python.html)を使用してPythonプログラムで**Word文書にテキストと画像の透かしを簡単に追加する方法**について説明します。

- **[Word文書にテキスト透かしを追加する](#word文書にテキスト透かしを追加する)**
- **[Word文書に画像透かしを追加する](#word文書に画像透かしを追加する)**

### Spire.Doc for Pythonの導入
Word文書を操作するためには、まずSpire.Doc for Pythonをプロジェクトに導入する必要があります。それは[Spire.Doc for Pythonの公式ウェブサイト](https://www.e-iceblue.com/Download/Spire-Doc-Python.html)からダウンロードするか、直接pipでインストールすることができます。以下はコードの例です：
```
pip install Spire.Doc
```
## Word文書にテキスト透かしを追加する
Spire.Doc for Pythonの**TextWatermark**クラスを使用してテキスト透かしを設定できます。設定した後、**Document.Watermark**プロパティを使用してWord文書に追加することができます。以下は操作の例です：
ドキュメントオブジェクトを作成します。

**Document.LoadFromFile()** メソッドを使用してWord文書のサンプルをロードします。
**TextWatermark**クラスのインスタンスを作成します。
**TextWatermark**クラスのメソッドを使用してテキスト透かしのテキスト、フォントサイズ、色、レイアウトを設定します。
**Document.Watermark**プロパティを使用してテキスト透かしをWord文書に追加します。
**Document.SaveToFile()** メソッドを使用して結果の文書を保存します。

**Python**
```python
from spire.doc import *
from spire.doc.common import *

# ドキュメントオブジェクトを作成します
document = Document()

# Word文書のロード
document.LoadFromFile("例.docx")

# TextWatermarkオブジェクトを作成します
txtWatermark = TextWatermark()

# テキスト透かしのフォーマットを設定します
txtWatermark.Text = "コピーしないでください"
txtWatermark.FontSize = 65
txtWatermark.Color = Color.get_Red()
txtWatermark.Layout = WatermarkLayout.Diagonal

# テキスト透かしをドキュメントに追加します
document.Watermark = txtWatermark

# 結果の文書を保存します
document.SaveToFile("output/テキスト透かし.docx", FileFormat.Docx)
document.Close()
```

## Word文書に画像透かしを追加する
画像透かしは、**PictureWatermark**クラスを使用して設定することができます。以下は操作の例です：

**Document**オブジェとを作成します。
**Document.LoadFromFile()** メソッドを使用してWord文書のサンプルをロードします。
**PictureWatermark**クラスのインスタンスを作成します。
**PictureWatermark.SetPicture()** メソッドを使用して画像を画像透かしとしてロードし、画像透かしのスケーリングとウォッシュアウトの属性を設定します。
**Document.Watermark**プロパティを使用して画像透かしをWord文書に追加します。
**Document.SaveToFile()**メソッドを使用して結果の文書を保存します。

**Python**
```python
from spire.doc import *
from spire.doc.common import *

# ドキュメントオブジェクトを作成します
document = Document()

# Word文書のロード
document.LoadFromFile("例.docx")

# PictureWatermarkオブジェクトを作成します
picture = PictureWatermark()

# 画像透かしのフォーマットを設定します
picture.SetPicture("dive.png")
picture.Scaling = 100
picture.IsWashout = False

# 画像透かしをドキュメントに追加します
document.Watermark = picture

# 結果の文書を保存します
document.SaveToFile("output/画像水印.docx", FileFormat.Docx)
document.Close()
```

以上が、Spire.Doc for Pythonを使用してWord文書にテキストや画像の透かしを追加する方法の概要です。Word文書の操作に関する他の情報については、[Spire.Doc for Pythonのチュートリアル](https://www.e-iceblue.com/Tutorials/Python/Spire.Doc-for-Python/Program-Guide/Spire.Doc-for-Python-Program-Guide-Content.html)を参照してください。ディスカッションやフィードバックについては、[Spire.Docフォーラム](https://www.e-iceblue.com/forum/spire-doc-f6.html)にアクセスしてください。
ブロックチェーンデベロッパーとスキル要素

私自身、ここ数年ブロックチェーンに関連するアプリの検証やコントリビュータを行ってきました。
ビットコインCoreやイーサリアム系EVM関連、スマートコントラクト開発、ウォレット各種（ハードウェアウォレットファームウェアを含む）など。

ブロックチェーンデベロッパーとスキル要素を体系的に情報を得られるサイトを見つけましたのでここに書き留めておきたいと思います。

## 参考サイト

https://roadmap.sh/

## ブロックチェーンデベロッパー（Blockchain Developer）

https://roadmap.sh/pdfs/roadmaps/blockchain.pdf

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514304/cb7ce621-1528-faee-8f3a-ac3e9e56c0bd.png)
プロジェクト ファイル 'Assembly-CSharp.csproj' はサポートされていない形式ですの問題対策

# 問題

vscodeのc# dev kitがインストールした後、以下のエラーが出ました。

```
プロジェクト ファイル 'Assembly-CSharp.csproj' はサポートされていない形式です (従来の .NET Framework プロジェクトなど)。C# Dev Kit で動作するには、新しい SDK スタイルに変換する必要があります。
```

# 対策

### 古いバージョンのunity
今のプロジェクトがまだunity2018を使っています、unityのvisual studioのパッケージをインストールできません。
vscodeのdotnet.preferCSharpExtensionをtrueに設定する
![スクリーンショット 2023-10-11 17.06.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771147/b119accc-3c3b-1f01-fc79-06a3fc32b03d.png)


#### 古い対策
Assembly-CSharp.csprojを開いて、`<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>`の下に`<TargetFramework>net7.0</TargetFramework>`を追加したことで解決しました。

こんな感じ
```
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
<TargetFramework>net7.0</TargetFramework>
```


### unity2021
unity2021以後なら、Packge Managerにで`Visual Studio Editor`を2.0.20にアップデートする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771147/768e8ad6-9645-6bb6-a412-7e4fa6cad8f6.png)
New RelicのログをJSONとCSVにサクッとExportしてみた

:::note info
最新のアップデートの詳細はこちら。[New Relic アップデート(2023年8月)
](https://newrelic.com/jp/blog/nerdlog/new-relic-update-202308 "New Relic アップデート(2023年8月)")
:::

# はじめに #
ログを含めたNew Relicプラットフォームに集められたデータは、UIを用いるだけで十二分に従来のログ分析や運用をカバーすることができますが、[履歴データのエクスポート](https://docs.newrelic.com/jp/docs/apis/nerdgraph/examples/nerdgraph-historical-data-export/)や[ストリーミングデータエクスポート](https://docs.newrelic.com/jp/docs/apis/nerdgraph/examples/nerdgraph-streaming-export/)の方法を用いて任意のシステムに定期的に引き渡すというオーソドックスな方法を取ることも可能です。一方で、運用を行っている際に、ログを一時的に手元に取得して確認作業を行いたいということもあるかと思います。(はい、**現場**ではそういう時もありますよね、本当に。。)

## ログをJSONやCSVで手元にダウンロードする機能がでたぞ!! ##
な、なんと!! [ログをダウンロードする機能](https://docs.newrelic.com/whats-new/2023/08/whats-new-08-10-export-logs)がリリースされました。

[Logs UI](https://docs.newrelic.com/jp/docs/logs/get-started/get-started-log-management/)上にある**Export**というメニューから実施することでログをダウンロードできるとのこと。
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3534647/69fc6037-fae4-c1ad-b8cc-f8af89f278c7.jpeg'>

## まてまて、どういった時に役立ちそうか？ ##
純粋にログを解析するとうことであれば、New RelicのLog UIを用いることで、十二分に要望を満たすことはできるし、そもそも**APMやRUMのUIを参照すること**で、ログの解析自体不要というケースも多いのではないかなと思います。
 
なので、

 - 障害時に特定サーバやアプリケーションのログを保全しておく(あって欲しくはないですが・・・)
 - 特定のログを保存しておくことで、システムの変更を行なった後の変更内容を比較する(障害とは全く関係なく)

といった使い方ができそうです。

# さっそくやってみる #
Logs UIにアクセスし、Exportメニューをクリックすると最大で2,000行のログまでダウンロードできるとのこと。まぁ、手動で得たログを2,000行以上目視するということは避けたいですよね。なので、個人的には無問題。Logs UI上で、必要なログだけを抽出できる様にフィルタ設定を行うことで、必要なログラインだけをダウンロードできるようです。

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3534647/06cf4823-9165-99b5-2040-810d4a5f069c.gif'>

JSONフォーマットで以下の様にログをダウンロードすることができました!
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3534647/5a0101d8-880d-0905-c032-272938001d0f.jpeg'>

ちなみに、CSVフォーマットでログをダウンロードすると、以下の様にログを取得することができました。
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3534647/9a4cfdcc-3323-9524-d211-f2982345c541.jpeg'>


# まとめ #
とても簡単にログを手元に出力することができることが確認できました。この機能を活用して、迅速にログの調査を進めることをお手伝いできれば幸いです。もし、今回の機能のNew Relicに興味をもったけど、試してみる環境がないという方は、ぜひ、[無料アカウント](https://newrelic.com/jp/sign-up-japan)を取得して試してみてください。New Relicを使って良かったと言ってもらえると嬉しいです。

:::note info
[New Relic株式会社のQiita Organization](https://qiita.com/organizations/newrelic)では、
新機能を含む活用方法を公開していますので、ぜひフォローをお願いします。
:::

:::note info
無料アカウントの詳細は[こちら](https://docs.newrelic.com/jp/docs/accounts/accounts-billing/account-setup/create-your-new-relic-account/)です。
:::
【kintone/PowerShell】PowerShellでkintoneApiとやり取りしたい！

# 背景
副業でkintoneを使った業務支援を行っている中で、社内システムで管理している各種マスタをkintoneと同期して欲しい(kintone上で業務データを生成する上で社内システムのマスタを使えるようにしたい)というご要望をいただきました。

マスタはWebアプリとWindowsフォームアプリの2種類あって、そこからデータを吸い上げるためにPowerAutomateを間に挟んでcsvでデータ化して、そのcsvデータをkintoneにリクエストするという構成にしました。
（ワンチャンうまく行かなかった場合の撤退コストを考慮し、サーバーなどは用意せず、クライアントPCで動かせる方式で構築したかった）

PowerAutomateの「Webサービスを呼び出します」で実装しろよって話なんですが、うまく疎通できなかったため(スピード勝負だったので深追いもせず)、実装はPowerShellに寄せることにしました。

# やりたいこと
- 検索、追加、更新、削除を実装する
- 10000件問題を回避する
- 複数レコードを一括更新できるようにする(APIコール数制限、オーバーヘッド低減)

# いざ実装
レコード一括取得処理はこんな感じです。
```kintoneApi.ps1
class KintoneApi {

  # kintoneのベースURL
  [string] $URL = 'https://your-domain.cybozu.com';

  # レコード一括取得API(検索条件指定あり)
  [array] GetKintoneRecords($app, $fields, $headers, $customQuery){

    $URI = "/k/v1/records.json"
    $Uri = $this.URL + $URI
    
    # 検索結果の一番大きなレコード番号を設定する変数
    # 繰り返し検索する際の起点として利用する
    $lastRecordId = 0;
    
    # 検索結果を格納する配列
    $records = @();
    $Report = @();
    # 1度の検索上限数
    $getLimitSize = 500;

    try {
      Log "Start GetKintoneRecords."
      while($true) {
        $query = 'レコード番号 > ' + $lastRecordId + ' order by レコード番号 asc limit ' + $getLimitSize;
      
        # 検索条件が指定されている場合は設定する(andで結合)
        if (-not ([string]::IsNullOrEmpty($customQuery))){
          $query = $customQuery + ' and ' + $query
        }

        $body = @{
          app = $app
          query = $query
          fields = $fields
          totalCount = 'true'
        }
    
        $Report = Invoke-RestMethod -Method Get -Uri $Uri -Body $body -Headers $headers
      
        for ($i=0; $i -lt $Report.records.Length; $i++){    
          $records += $Report.records[$i]
          $lastRecordId = $Report.records[$i].レコード番号.value # レコード番号の昇順で検索しているので、最後のレコード番号を次の検索の起点にセットする
        }
        
        # getLimitSize以下になるまで検索を繰り返す
        if ($Report.records.Length -lt $getLimitSize) {
          break
        }
        
      }

    } catch {
      Log ($_.Exception)
      Log (ConvertErrorMessage($_.Exception))
    } finally {
      Log 'End GetKintoneRecords'
    }
    
    return $records;
  }

}

```
呼び出しはこんな具合に。
```sample.ps1
$KintoneApi = New-Object KintoneApi
$records = $KintoneApi.GetKintoneRecords($ID, $fields, $headers, $null)
for ($i=0; $i -lt $records.Length; $i++){
  $val1 = $records[$i].フィールドコード1.value
}
```

上記以外にも1件検索、追加、更新、削除を実装しております。
https://github.com/koguren/powershellKintoneAPI.git

ご興味ある方＆ここの書き方こうするともっといいよ！とコメントいただける方いらっしゃればよろしくお願いいたします！

# その他
いざお客さんマシンで動かそうと思いきやpowershell実行にあたりExecutionPolicyの設定にハマりました(何事も勉強ですね！)。冷や汗ものでした。
Power Apps で、SharePoint リストの添付ファイルのアップロード有無、添付ファイルの数でアクションを変更する


# はじめに

何かの申請、申込みを行う業務において、必要書類 (添付ファイル) を添えるケースがあると思います。このような業務を Power Apps と SharePoint リストを利用して効率化する場合、既定で存在する添付ファイル列を利用する方法があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/87dfa8e3-07ff-add2-f132-e4edc6b687f5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/9f1bcac0-d1a4-55a9-089f-5a5af1d4003d.png)


こちらの添付ファイル列、複数のファイルをアップロードできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/96272991-967f-cd78-2e52-324713bb3acc.png)

今回は、Power Apps から SharePoint リストの添付ファイル列を利用する際、ある条件を満たした際に添付ファイルのアップロードを必須にする、添付ファイルの数がアプリ管理者が指定する数に達していない際に登録出来ないようにする方法について紹介いたします。

# ある条件を満たした際に添付ファイルのアップロードを必須にする

まず、Power Apps でフォームコントロールで入力を必須にするためには、データカードの`[Required]`プロパティを `false` から `true` に変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/3586b45a-57b4-3c7f-2e94-81335bc0871f.png)

ただし、こちらを `true` に変更すると常に入力が必須となります。そのため、入力項目で選んだ値によって入力を必須にしたいような場合は、条件式を書く必要があります。

例えば、LinkedIn プロフィールの欄 (DataCardValue9) が空白の際、履歴書、職務経歴書の入力 (添付) を必須にしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/14ebdaa2-66fe-21ab-5014-b31e648085f1.png)

```
If(
    IsBlank(DataCardValue9.Text),
    true,
    false
)
```

上記にくわえ、以下のようなボタンを通じてデータの登録を行う場合、ボタンの`[DisplayMode]`プロパティやエラーメッセージ用のラベルの`[Visible]`プロパティを臨機応変に変更する方法もあります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/8e31f5ff-71c9-ba6b-ff04-f2425c72bd6b.png)

ボタンの`[DisplayMode]`プロパティの式は以下のような感じです。添付ファイルの項目含め、フォームコントロールの入力必須項目において、未入力の箇所がある場合にボタンを押せなくしています。

```
If(
    !Form1.Valid,
    DisplayMode.Disabled,
    DisplayMode.Edit
)
```

:::note
`Form1.Valid`で判定しております。こちらだけで、フォームコントロールの入力必須項目において、未入力の箇所がないか判定できるため便利です。
:::

エラーメッセージ用のラベルの`[Visible]`プロパティも同じような感じで設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/43200cb9-5163-9325-c202-dcc478dc7ebe.png)

# 添付ファイルの数がアプリ管理者が指定する数に達していない際に登録出来ないようにする

今回は、職務経歴書と履歴書の 二つのファイルをアップロードしてもらいたいため、添付ファイルが一つしかない場合にもアップロード出来ないようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/d9e44501-fc7f-dedd-6e26-5c64ba66f53b.png)

まず、ボタンの`[DisplayMode]`プロパティは以下のような感じです。

```
If(
    Form1.Valid And CountRows(DataCardValue10.Attachments)>1,
    DisplayMode.Edit,
     DisplayMode.Disabled
)
```

エラーメッセージ側の`[Visible]`プロパティの設定は以下のような感じです。ボタン側の`[DisplayMode]`プロパティをベースに設定しています。

```
If(
    Button1.DisplayMode = DisplayMode.Edit,
    false,
    true
)
```

ちゃんと二つアップロードするとボタンが押せるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/7821f77f-60b4-6a8c-6c73-ba4df0f76b26.png)

データの送信と合わせて、必要に応じて Power Automate を利用して通知等も実施ください。


# まとめ

今回は、Power Apps で、SharePoint リストの添付ファイルのアップロード有無、添付ファイルの数でアクションを変更する方法について紹介しました。SharePoint リストベースで Power Apps を作成する際は、既定の添付ファイル列を利用することが多いため、参考にんされば幸いです。
Macでpyenvを使う

```zsh
brew update
brew install pyenv

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
source ~/.zshrc
```

以下のようなエラーが発生したら、

```zsh
ModuleNotFoundError: No module named '_lzma'
WARNING: The Python lzma extension was not compiled. Missing the lzma lib?
```

以下をやってもう一度試せばOK。

```
brew install xz
```
MacにEclipse MosquittoをインストールしてPub/Subを試す

MacにEclipse MosquittoをインストールしてPub/Subを試す。

## インストール/アンインストール

Homebrewで以下のように簡単にインストール/アンインストール出来る。

```zsh
brew install mosquitto
```

```zsh
brew uninstall mosquitto
```

## サーバの開始/停止

サーバの開始と停止も簡単。

```zsh
brew services start mosquitto
```

```zsh
brew services stop mosquitto
```

## websocket対応

websocketを使う場合は、

```zsh
code /usr/local/etc/mosquitto/mosquitto.conf
```

の最後に

```
listener 1883
listener 9001
protocol websockets
allow_anonymous true
```

のように追加しサービスを再起動すると、

```zsh
brew services restart mosquitto
```

以下のように呼び出すことが出来る。

```javascript
"ws://localhost:9001"
```

のように呼び出せる。
Dockerのコンテナを起動させると、Could not find a JavaScript runtimeになる

Railsの勉強をしていて、Dokcerもこの機会に触りたい！と思いインストールとかしてみた。

## 環境

Apple M1 Mac
Os: 13.5.1

Docker: 24.0.5
ruby: 3.2.2
rails: 7.0.7

## 経緯

基本的な環境構築は済ませた。

Bootstrap5を適応させたくて、

Gemfileに下記を追記してDockerのビルドは問題なく終わった。

```
gem 'bootstrap', '~> 5.3.1'
```

で、コンテナ起動するとエラーが発生。

```console
Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)
```

javascriptの実行環境がない？

まずは`mini_racer`いれればOKというサイトがでてきたので
Gemfileに下記を追記して、ビルド。

```
gem 'mini_racer'
```

そうすると、ビルドの結果がエラー。

```
61.26 An error occurred while installing libv8-node (18.16.0.0), and Bundler cannot
61.26 continue.
61.26
61.26 In Gemfile:
61.26   mini_racer was resolved to 0.8.0, which depends on
61.26     libv8-node
```

他にも`therubyracer`をインストールしろとか出るけど、やってみても同じように、
ビルドでエラーが起きる。

もう少し調べてみると参考サイト②にありました。
DockerイメージにNode.jsインストールしろ、とのこと。
Dockerfileに下記を追加。

```
apk add nodejs
```

ビルド、コンテナ起動して問題なし。
あとの設定は参考サイトの①のページを参考にしました。

### 参考サイト

＊ ①
[Rails7構築 -その2- importmapでbootstrap5の導入](https://qiita.com/devzooiiooz/items/262f71e737f94738debf)

＊ ②
[ExecJS:RuntimeUnavailable: Could not find a Javascript runtime Docker app](https://stackoverflow.com/questions/53883969/execjsruntimeunavailable-could-not-find-a-javascript-runtime-docker-app)
ネイティブJSでサウンドノベル風テキストアニメーション

サウンドノベルっぽいテキストアニメーションをJSで実現したい。

どういう動きかというとこんな感じ↓

https://store.steampowered.com/app/2067780/_/?l=japanese

ライブラリはいくつかあるのだけれども、やりたいことをすべて叶えてくれるものはなかった…ので、書きました。

## やりたいこと
1. 指定したテキストが1文字ずつ表示される
1. 表示途中でクリックすると全文表示される
1. 表示完了後にクリックすると次のテキストの表示を開始する
1. 複数のJSから上記の共通処理を呼び出す

## 完成形
元はviteで書いていたコードを単純jsっぽく直したので整合性取れていないところがあるかもしれませんが…こんな感じになりました。

```js: TypeWriter.js
/*
  TypeWriter

  呼び出し元で1つインスタンスを生成して使用
 */
export const TypeWriter = class {
  constructor(query) {
    this.charNum = 0
    this.textWriteEnd = false
    this.el = document.querySelector(query)
  }

  print(text) {
    this.textWriteEnd = false
    this.charNum = 0
    this.el.textContent = ''
    const self = this
    self._print(text.split(''))
  }

  _print(chars) {
    const self = this
    const timer = setTimeout(() => { self._print(chars) }, 50)

    if (this.charNum < chars.length) {
      this.el.textContent += chars[this.charNum]
      this.charNum++
      if (this.charNum === chars.length) {
        this.textWriteEnd = true
      }
    } else {
      clearTimeout(timer)
      this.textWriteEnd = true
    }
  }

  printAll(text) {
    this.charNum = text.split('').length + 1
    this.el.textContent = text
  }
}
```

```js:sample.js
import { TypeWriter } from '/js/typewriter.js'

let page = 0
let tw
let clickable = false

const textList = [
  { txt: 'テキスト1' },
  { txt: 'テキスト2' },
]

window.onload = () => {
　　　　tw = new TypeWriter('#id') // テキスト描画したい要素
  setTimeout(() => {
    tw.print(textList[page].txt)
    clickable = true
  }, 500)
}

// クリックイベント
const goNext = () => {
  if (!clickable) return

  if (tw.textWriteEnd) {
    page++

    if (page < textList.length) {
      tw.print(textList[page].txt)
    } else {
      // URL遷移
    }
  } else {
    tw.printAll(textList[page].txt)
  }
}
```

## おすすめライブラリ
もっとシンプルで良いのなら、iTyped.jsがおすすめです。

https://ityped.surge.sh/

今回は「途中クリックで全文表示」という要件が出た時点で使えなくなりました(泣)

## 参考にさせていただいたサイト
https://mizusibuki.com/javascript-novelgame/

https://www.tcdigital.jp/dev_blog/programming/javascript%E3%81%A7adv%E9%A2%A8%E6%96%87%E5%AD%97%E8%A1%A8%E7%A4%BA/


## あとがき
jsはなんとなくでずっといじっていて、今回初めてclassを使いました。
多分美しくないコードだと思います。
ご指摘やアドバイスは歓迎いたします。
[Linux 初期設定] mailコマンドインストール

Linux 初期設定シリーズ

変更内容：mailコマンドインストール
確認OS：Red Hat Enterprise Linux release 9.2 (Plow)
対象ファイル：/etc/aliases
反映：newaliases コマンドを実行する

０．Postfixインストール

```test.sh
sudo dnf -y install postfix
sudo systemctl start postfix
sudo systemctl enable postfix
sudo systemctl status postfix
```

１．mailコマンドインストール
※注意、OSのバージョンによってツールが違う

・AlmaLinux 8

```test.sh
sudo dnf install mailx
```

・AlmaLinux 9

```test.sh
sudo dnf install s-nail
```

・CentOS 7

```test.sh
sudo dnf install sendmail
```

２．設定のバックアップ

```test.sh
sudo cp -an /etc/aliases{,.$(date +%Y%m%d)}
sudo ls -alF /etc/aliases*
```

３．root宛メールを転送する設定
名称：<名前←正式名称を調べて修正する>
転送先：<メールアドレス>

```test.sh
sudo sed -i -e 's/#root:\t\tmarc/root:\t\t<名前←正式名称を調べて修正する>/g' /etc/aliases
sudo sed -i -e '$ a <名前←正式名称を調べて修正する>:\t<メールアドレス>' /etc/aliases
```

４．設定の確認

```test.sh
sudo diff /etc/aliases{,.$(date +%Y%m%d)}
```

５．転送設定反映

```test.sh
sudo newaliases
```

６．テストメールを root 宛に送信する

```test.sh
echo test from `hostname -s` | mail root
```
カラムを追加しても反映されない時の対処法

今回の躓いてた原因を残しておく
XXXXX_sorcery_core.rbの中身は以下の通り
```
class SorceryCore < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.string :email,            null: false, index: { unique: true }
      t.string :crypted_password
      t.string :salt
    end
  end
end
```
この状態で１回目のrails db:migrateを行った
その後first_name,last_nameカラムがひつようになったため
XXXXX_sorcery_core.rbを以下のように書き変えた
```
class SorceryCore < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.string :email,            null: false, index: { unique: true }
      t.string :crypted_password
      t.string :salt
      t.string :first_name,        null: false
      t.string :last_name,         null: false
    end
  end
end

```
ここで２回目のrails db:migrateを行うも反映されない
原因は一度マイグレーションを実行したファイルは
もう一度rails db:migrateを実行しても変更がされないらしい
そこで
```
$ rails db:migrate:reset
```
を実行してから再度
```
$ rails db:migrate
```
を実行するとカラムの追加ができた

初学者で知識がないというのは承知の上だが、だとしても初見殺しが多すぎないか？
ITエンジニアのパフォーマンスを爆上げするサプリメントとは？

### 動機
普段、我々は開発効率を向上させるため、方法論やツールなどを駆使していると思います。
ですが、大元は人間。
人間自体のパフォーマンスを上げなければ、全体のパフォーマンスは向上しません。
そこで今回は、その点をChatGPTに聞いてみました。

### ChatGPTの回答

プログラマーやその他の知的労働を行う人々にとって、集中力を向上させたり、脳の健康をサポートしたりするサプリメントがいくつか存在します。
以下は、プログラマーや知的労働者に役立つとされるサプリメントの一部です：


| サプリメント | 効果 |
| --- | --- |
| カフェイン | 一時的な集中力や警覚性の向上が期待される。ただし、過剰摂取は不眠や不安を引き起こすことがある。 |
| L-テアニン |  緑茶に含まれるアミノ酸で、リラックス効果が報告されています。カフェインと一緒に摂取することで、集中力の向上と同時にリラックス感を得られると言われています。 |
| オメガ-3脂肪酸 |  特にDHAは、脳の健康と機能のサポートに役立つと考えられています。 |
| ビタミンB群 |  神経系の健康やエネルギー代謝のサポートに役立つ。 |
| ジンコビロバ |  記憶や集中力をサポートするとされるハーブ。血流の改善作用も報告されています。 |
| アシル-L-カルニチン |  このアミノ酸は、脳のエネルギー代謝のサポートに役立つとされています。 |
| バッカ |  記憶や集中力の向上をサポートする伝統的なハーブ。 |
| ロディオラ・ロゼア |  疲労の軽減やストレス対応のサポートに役立つとされるアダプトゲンハーブ。 |
| ノオペプト |  記憶や学習能力の向上をサポートするとされるサプリメント。 |
| モディオダリル |  注意力の向上や疲労感の軽減をサポートするとされる。 |

これらのサプリメントを摂取する前には、必ず医師や専門家に相談することが推奨されます。
特に、既存の疾患や他の薬との相互作用に注意が必要です。また、サプリメントの摂取は一部の対策であり、適切な睡眠、バランスの取れた食事、定期的な休憩など、健全な生活習慣の維持が基本的に重要です。

---

- 「バッカ」とあるが、正しい名称は「パッカ」だと思われる。
AWS アカウント、ユーザー管理 メモ

## 記事の目的
AWS学習時にアカウントやIAMのところでつまずいたので、理解のためにまとめた:writing_hand_tone2:

## :black_medium_small_square: アカウントについて
AWSのサービスを利用したい！と思ったらまず作成するもの。

**▼▼ 作成方法はこちら ▼▼**

https://aws.amazon.com/jp/register-flow/

#### :part_alternation_mark: ルートユーザー
アカウントを作成すると、自動的にルートユーザーが作成されるユーザー。
作成したアカウントで利用できる全サービス、請求にアクセスすることができるユーザーで、権限が強いため、ルートユーザーは普段の作業では使用せず後で記載する`IAMユーザー`を使用する事を推奨している。

#### :part_alternation_mark: [アカウントエイリアス](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/console_account-alias.html#AboutAccountAlias)
AWSアカウントIDの代わりに使用できる名前。
作成するアカウントエイリアスは、指定されたネットワークパーティション内のすべてのAmazon Web Services製品で一意となる必要があり、`aws`、`aws-cn`、`aws-us-gov`などは使用できない。

## :black_medium_small_square: [IAM](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/introduction.html)について
AWSリソースへのアクセスを管理するためのサービス。
IAMを使用することで、アクセス許可や

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/intro-structure.html

#### :part_alternation_mark: ロールの切り替え
ロールを切り替えるには、下記の手順を踏む。
1. 下記画像のように、画面右上のユーザー名をクリックすると`ロールの切り替え`ボタンがあるので、クリックする。
（画像は、１度ロールの切り替えをしてIAMロールに切り替えてある状態なので、まだロール切り替えをしたことが無い方は見た目が違うが、クリックするボタンは同じ）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/785134/cff316e2-3bfb-b4f5-56a8-5763d660ac51.png" width="300" />

2. `切り替えたいロールのアカウントID`と`ロール名`を入力（表示名と色は任意）し、`ロール切り替え`ボタンをクリック！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/785134/8e351f1e-b935-a6a6-e3ae-6a6f7d18700f.png" width="700" />


#### :part_alternation_mark: [クロスアカウントアクセス](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html)
IAMロールを使用する事で、アカウントAのリソースをアカウントBに共有できる。
これをクロスアカウントアクセスと言い、設定することでアカウントごとにIAMユーザを作成する必要がなくなる。
さらに、アカウントAのリソースを使用してたい時、わざわざ今ログインしているアカウントBからサインアウトしてアカウントAへサインインするという手間もなくなる。

## :black_medium_small_square: [AWS Organizations](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_introduction.html?org_product_rc_usergude)
複数のAWSアカウントを`組織`として一元管理できるアカウント管理サービスで、請求の一括管理をすることもできる。
作成した組織の管理者は、既存のアカウントを招待したり、組織内に新規作成することが可能。

組織には、1つの管理アカウントとメンバーアカウントがある。
組織を作成すると、自動的に`Root`が作成され、ポリシーなどを適用することができる。
作成した組織の最上位に`Root`があり、その下に`Organizational unit (OU)`という単位で組織単位がぶら下がっている、階層構造でアカウントが整理されている。
そして、各アカウントは、Rootに直接または階層内のOUのいずれかに配置することができる。


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/785134/196bb334-6849-64a7-d92f-3c0d7af2a8e5.png" width="650" />



**▼▼概要▼▼**

https://docs.aws.amazon.com/organizations/latest/userguide/orgs_getting-started_concepts.html

組織内にメンバーアカウントを作成するには、下記の記事を参考にする。

**▼▼組織にメンバーアカウントを作成する▼▼**

https://docs.aws.amazon.com/ja_jp/organizations/latest/userguide/orgs_manage_accounts_create.html


## :black_medium_small_square: 合わせて読みたい
**▼▼AWS Organizations を使用した組織単位のベストプラクティス▼▼**

https://aws.amazon.com/jp/blogs/mt/best-practices-for-organizational-units-with-aws-organizations/?org_product_rc_OUBlog
【非推奨】GoogleフォームをカスタマイズしてWebサイトに組み込む

Webサイトにカスタムのフォームを用意してあげたいけど、バックエンドを開発する予算と余裕がないよ、という場面で、絶対推奨できるものではないけれどもなんとかやりくりする方法です。
Googleフォームをカスタマイズして埋め込みます。

## 実現したいこと
- Webページにフォームを設置する
- 回答を収集する
- 回答を受け取ったらメール通知する

## 使用するもの
- Googleアカウント（無料版でOK）
- Googleフォーム

## 制作手順
### Googleフォームの作成
普通に要件に沿ってGoogleフォームを作成します。
https://www.google.com/intl/ja_jp/forms/about/

### 作成したフォームの情報を取得
1. actionに指定されたURL
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490854/34cad793-d9fe-45e2-c29b-17b0d73000ef.png)

2. 各input項目のname値
作成した項目はすべてhiddenのinputタグができるので、そのnameを控えておきます。

```
<input type=“hidden” name=“entry.xxxxxxxxx” value=“名前”>
<input type=“hidden” name=“entry.xxxxxxxxx” value=“選択肢2”>
```

### Webサイトにフォームを組み込む
好きなデザインでフォームを組み込みます。


### JSでフォーム送信
```js:Googleフォーム送信
const paramList = new URLSearchParams()

// textの場合
paramList.append('entry.xxxxxxxxxx', 'inputから取得した値')

// checkboxの場合
const item = document.querySelector('#inputId')
if (item.checked) {
  paramList.append('entry.xxxxxxxxx', item.value)
}

fetch('actionに指定されていたURL', {
method: 'POST',
mode: 'no-cors',
headers: {
  'Content-Type': 'application/x-www-form-urlencoded',
},
body: paramList.toString(),
})
.then(res => {
  // 送信後にやりたい処理
})
```

## 注意
fetchのmodeに`no-cors`を指定してあげないとエラーになります。

`then`でレスポンスを受け取っているものの、この方法ではAPIのレスポンスを取得することはできません。
`res.ok`の値は、送信成功時もバリデーションエラー時も`false`です。
バリデーションエラーになった場合、コンソールには400エラーが表示されますが、fetchでcatchすることやresから検知することはできませんでした。
このため、Googleフォーム側にバリデーションを持たせず、Webページ側でのみバリデーションをかけるのが良いかと思います。

上記の理由から、このやり方は普通に非推奨です。

## 参考にしたサイト
 [Googleフォームを静的サイトに埋め込みカスタマイズ【非同期通信Ajax】｜しょーごログ](https://shogo-log.com/google-form-ajax/)
[Google FormをHTML/CSSでデザインしたフォームで運用する方法](https://zenn.dev/yurukei20/articles/9741118bfb5ee0)

## 追記
こんなやり方よりも、sendGridを使ってAPI連携させる方が格段に良いということを知りました。
近々テストしてみるので触ってみたらそちらもまとめます。
Oracle Database 23aiで追加されたMLE JavaScriptの基本的な使い方紹介

Oracle Database 23aiではMultilingual Engine(以下MLE)のJavaScriptに関する機能が大幅に強化されています。
23aiでは一度実装したコードをスキーマ・オブジェクトとして保存し、任意のタイミングで呼び出したり、他のコードへimportできるようになっています。

[以前投稿したこちらの記事](https://qiita.com/ssfujita/items/685d635c3d1ba4e98115)ではいきなりMLEの応用的な新機能を紹介してしまいましたが、改めて基本要素を本記事にまとめておこうと思います。

なお以下は23aiマニュアル(Free - Developer Release版)の参考資料です。
- [Creating JavaScript Modules in the Database](https://docs.oracle.com/en/database/oracle/oracle-database/23/mlejs/mle-js-modules-and-environments.html#GUID-0E40C6C1-3458-40EB-A81C-DC11885C2D24)
- [Preparing JavaScript code for MLE Module Calls](https://docs.oracle.com/en/database/oracle/oracle-database/23/mlejs/mle-js-modules-and-environments.html#GUID-9B9CE0FE-E2F9-4E72-A443-A841DE121B99)
- [Overview of Importing MLE JavaScript Modules](https://docs.oracle.com/en/database/oracle/oracle-database/23/mlejs/overview-importing-mle-js-modules.html#GUID-B10ABCEF-7E1C-4575-A326-325F1FE3D17D)

## 事前準備

MLE JavaScriptを利用するには対象のDBユーザに対して以下の権限を付与する必要があります。

```sql
-- JavaScriptをOracle Database上で実行するための権限
GRANT EXECUTE ON JAVASCRIPT TO <ユーザ名>;
-- MLE ModuleやMLE Environmentを作成するための権限
GRANT CREATE MLE TO <ユーザ名>;
-- MLE Moduleの呼び出しに使うPL/SQLプロシージャの作成権限
GRANT CREATE PROCEDURE TO <ユーザ名>;
-- JavaScript実行後デバッグ機能の利用に必要な権限
GRANT COLLECT DEBUG INFO ON <module> TO <ユーザ名>;
```

## MLE JavaScript実装の基本

MLE JavaScriptをオブジェクトとして保存し、再利用できるようにするには、以下3つのオブジェクトを作成する必要があります。
+ MLE Module：
    - メインのJavaScriptのコードを格納
+ MLE Environment：
    - MLE Moduleを実行する際に必要となる他MLE Moduleのimportや、Strictモードなどのパラメータを指定
+ MLE Module Call：
    - MLE Moduleを呼び出すためのプロシージャ

今回は例として、入力された値の階乗を計算する処理をMLE JavaScriptで実装してみます。
まずはメインとなる階乗の計算をするMLE Moduleが以下になります。

```sql
CREATE MLE MODULE IF NOT EXISTS factorial_mod LANGUAGE JAVASCRIPT AS

export function factorial(num) {
  if ( num < 0 ) {
    return -1;
  } else if ( num == 0 ) {
    return 1;
  } else {
    return ( num * factorial( num - 1 ) );
  }
}
/
```

次に、MLE Module「factorial_mod」を他のMLE Moduleでimportして使えるよう、MLE Environmentを作成します。

```sql
-- IMPORTS('<別のMLE Moduleでimport時に指定する別名>', MODULE <import対象のMLE Module名>)
CREATE MLE ENV my_factorial_env IMPORTS('FACTORIAL_MOD' MODULE FACTORIAL_MOD)
/
```

さらに factorial_mod をimportするMLE Moduleを作成します。

```sql
CREATE OR REPLACE MLE MODULE mod_imp_fact LANGUAGE JAVASCRIPT AS

import * as h from "FACTORIAL_MOD"

export function printAnswer(num){
    let ans = h.factorial(num);
    console.log(`The factorial of ${num} is: ${ans}`);
}
/
```

JavaScriptパートのimportでは、MLE Environment「my_factorial_env」で設定したimport時の別名を指定しています。
今回はMLE Module名と同名になっています。

最後にMLE Module「mod_imp_fact」を実行するためのMLE Module Call(プロシージャ)を作成します。

```sql
CREATE OR REPLACE PROCEDURE mod_imp_fact_proc(num NUMBER)
AS MLE MODULE mod_imp_fact
ENV my_factorial_env
SIGNATURE 'printAnswer(number)';
/
```

PROCEDURE句に実行時に利用するプロシージャ名を、ENV句には今回利用するMLE Environmentを指定します。
AS MLE Module句には実行するMLE Module名を指定します。
またSIGNATURE句には呼び出すJavaScriptの関数を指定します。

では作成したMLE Module Callを実行してみます。

```sql
SQL> set serveroutput on
SQL> EXEC mod_imp_fact_proc(3);
The factorial of 3 is: 6

PL/SQLプロシージャが正常に完了しました。
```

以上がMLE JavaScriptの基本的な使い方になります。
Unityで作った仮想空間上を足踏み等で散歩していくPGM

<h2>Unityで作った仮想空間上を足踏み等で散歩していくPGM</h2>
pythonのPGMからUnityで作った仮想空間上を足踏み等で散歩していくPGMを作りました。

<hr>
githubURL:https://github.com/NanjoMiyako2/WalkingInUnitySpace

<hr>
使い方

設定方法
まずUnity上で仮想空間を作成し、github上のカメラにCameraSousa.csのC#ファイルをアタッチします。
次に、pythonのpytestKoukaiYou2.pyのファイルの「C:\\hogehoge\\white.png"」のパスを適切な
ものに変更し、pytestKoukaiYou2.pyのファイルの252,275行目の座標をコマンドプロンプトの座標(スクリーンショットの②)、
323行目をUnityゲームプログラムの座標(スクリーンショットの①)に変更します。

実行方法)
実行のやり方は前の3d空間散歩PGM(https://qiita.com/shizuoka_miyako_19911118/items/90724d53f64064ab120d)
のやり方と同様です。


1. コマンドラインからプログラムを呼び出しますその際、2つ目の引数で動いたと判定する差分のパーセントを指定します

2. 発話で以下のうち一つコマンドを言います
A: {移動 前/後ろ/右/左｝
B: {回転 右/左/上/下}
C: 終了

うまく聞き取れたら「OK」と発話します(聞き取れなかった場合は「もう一度」と発話)
4.その5秒後、動いている間だけ、1でのコマンドを実行し続けます
5.停止したときには2に戻ります

<hr>
つまづいたところ<br>
Unityでpyautoguiでpressメソッドが利かなかったため、writeメソッドを使用しました。

<hr>
参考にしたサイト<br>
<a href="https://www.popii33.com/how-to-quit-a-game-in-unity/">【コピペ可】Unityでゲームを終了する方法｜4パターン紹介‼│Unity＃学習</a><br>
<a href="https://teratail.com/questions/314989?sort=2">pyautoguiでゲーム画面を操作したいが、反応しないので、操作できるようにしたい</a><br>
<a href="https://tmytokai.github.io/open-ed/activity/unity-basic/text01/page04.html">4. Unityの座標系</a><br>
<a href="https://tech-blog.rakus.co.jp/entry/20220613/python">【PyAutoGUI】Pythonでマウスとキーボードを操作する - RAKUS Developers Blog | ラクス エンジニアブログ</a><br>
<a href="https://tech.pjin.jp/blog/2022/09/26/unity-move-camera">【初心者Unity】TPS視点のカメラ操作を雑に実装する方法 | TECH PROjin</a><br>
[Linux 初期設定] パッケージ自動更新

Linux 初期設定シリーズ

変更内容：パッケージ自動更新
確認OS：Red Hat Enterprise Linux release 9.2 (Plow)
対象ファイル：/etc/dnf/automatic.conf
反映：サービスの再起動

１．自動アップデートツールのインストール

```test.sh
sudo dnf install -y dnf-automatic dnf-utils
```

２．設定ファイルのバックアップ

```test.sh
sudo ls -alF /etc/dnf/automatic.conf*
sudo cp -an /etc/dnf/automatic.conf{,.$(date +%Y%m%d)}
sudo ls -alF /etc/dnf/automatic.conf*
```

３．パッケージの自動更新の有効化

```test.sh
sudo sed -i -e 's/^apply_updates = no/apply_updates = yes/' /etc/dnf/automatic.conf
```

４．設定の確認

```test.sh
sudo grep ^apply_updates /etc/dnf/automatic.conf
sudo diff /etc/dnf/automatic.conf{,.$(date +%Y%m%d)}
```

５．サービスの登録、サービスの開始および確認

```test.sh
sudo systemctl start dnf-automatic.timer
sudo systemctl enable dnf-automatic.timer
sudo systemctl status dnf-automatic.timer
```