OmniAICreator/Qiita-1.07M huggingface dataset:
JavaでExcelにデジタル署名を追加または削除する

## はじめに
デジタル署名は、情報の送信者によって生成される一連の数字であり、他人による偽造は不可能です。そのため、デジタル署名は情報の真正性を検証する有効な証拠となります。デジタル署名は、電子商取引や電子契約などの領域で広く利用されています。Excelでは、身元の検証や文書の完全性の確保のためにデジタル署名を追加することができます。以下では、Javaプログラムを使用してExcelファイルにデジタル署名を追加および削除する方法について説明します。


## ツール
* IntelliJ IDEA 2018 (jdk 1.8.0)
* [Free Spire.XLS for Java](https://www.e-iceblue.com/Introduce/free-xls-for-java.html) (無料)

## Jarの導入
* [Free Spire.XLS for Java](https://www.e-iceblue.com/Download/xls-for-java-free.html)をダウンロードして解凍します。
* IDEAで新しいプロジェクトを作成します。
* 「File」>「Project Structure」>「Modules」>「Dependencies」をクリックします。
* 「+」の「JARs or Directories」を選択します。
* 「Spire.xls.jar」を見つけてプロジェクトにインポートします。

## デジタル署名の追加
Spire.XLS for Java ライブラリで提供される Workbook クラスの addDigitalSignature(CertificateAndPrivateKey certAndPrivateKey, String comments, Date signTime)メソッドは、Excel ファイルへのデジタル署名の追加をサポートします。 サンプルコードは次のとおりです。
```java
import com.spire.xls.ExcelVersion;
import com.spire.xls.Workbook;
import com.spire.xls.digital.CertificateAndPrivateKey;

import java.util.Date;

public class AddDigitalSignature {
    public static void main(String []args) throws Exception {
        //Workbook インスタンスを作成します
        Workbook workbook=new Workbook();

        // Excelファイルを読み込みます
        workbook.loadFromFile("sample.xlsx");

        //ファイルにデジタル署名を追加します
        CertificateAndPrivateKey cap = new CertificateAndPrivateKey(String fileName, String password);
        workbook.addDigitalSignature(CertificateAndPrivateKey certAndPrivateKey, String comments, Date signTime);

        //結果ファイルを保存します
        workbook.saveToFile("AddDigitalSignature.xlsx", ExcelVersion.Version2013);
    }
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/521bbc4a-c379-e8bb-ff7b-e58bb05faca2.png)
## デジタル署名の削除
Spire.XLS for Java は、Excel ファイルからのデジタル署名の削除をサポートする Workbook クラスの removeAllDigitalSignatures()メソッドを提供します。 サンプルコードは次のとおりです。
```java
import com.spire.xls.ExcelVersion;
import com.spire.xls.Workbook;

public class RemoveDigitalSignature {
    public static void main(String []args) throws Exception {
        //Workbook インスタンスを作成します
        Workbook workbook = new Workbook();

        //Excelファイルを読み込みます
        workbook.loadFromFile("AddDigitalSignature.xlsx");

        //ファイルからすべてのデジタル署名を削除します
        workbook.removeAllDigitalSignatures();

        //結果ファイルを保存します
        workbook.saveToFile("RemoveDigitalSignature.xlsx", ExcelVersion.Version2013);
    }
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/25b88cf8-0268-63fb-d4e9-f311828c287e.png)
【ChatGPT無】をCustom instructionsで緊縛する！

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　どうも、カーブミラーです。

　前回、前々回と、
　　お遊びモードでなかったので、
　　　反応悪かったみたいですねw

　と思ったら、
　　Enterprisesが、
　　　伸びましたねぇ。

　まぁ、気になりますよね。
　　わかるわかる。
**
　それと、昨日アップした
[【Google検索 SGE】検索にも生成AIが。お遊びなし。](https://qiita.com/kabumira/items/f95d541c6244516d9920)
　　ですが、
　　　意味がわからなかったです？

　まぁ、Googleも以前から、
　　内部的にAIを使っていたのは、
　　　「文章で検索できる」という
　　　　話から知っていましたよね。

　具体的には、
　　生成AIを使うよ、と
　　　スイッチを入れると、
　　　　検索して要約してくれます。

　あれこれ、
　　出てきたサイトを
　　　自分でチェックする必要が
　　　　減ります。

　効率化を目指すみなさんも
　　スイッチオンすると、
　　　ムダな時間を過ごすことが
　　　　減ります。

　もちろん、AIなので、
　　ハルシネーションには
　　　注意すべきですが、
　　　　簡単にまとめてくれるのは
　　　　　ありがたいと思います。
***
***
　さて、今回は、
　　ChatGPTさんを
　　　お縄にします。

　ＳＭじゃありませんからねw

　がんじがらめ、
　　って意味ですよ。

　意味不明ですか、
　　そうですか。
***
　まずは、
　　Custom instructionsを
　　　使わずに、
>あなたの知っているマンガを百個、教えてください。
箇条書き（番号なし、説明不要）でお願いします。

　と入力すると、
　　もちろん、
　　　ズラズラと出してくれます。

　知らないタイトル、
　　ないなぁ……w
***
　さて、Custom instructionsを
　　オンにして、さきほどの
　　　入力を行ないます。

>申し訳ありませんが、その要求には応えることができません。

　と返ってきました。

　さらにやり取りしてみます。
```Text:
User
AIについて、教えてください。
箇条書き（説明不要）でお願いします。


ChatGPT
1. 人工知能（AI）はコンピューターシステムの能力を向上させる技術です。
2. データから学習し、パターンを識別することができます。
3. 機械学習とディープラーニングはAIの一部です。
4. 自然言語処理は言語データを理解するために使用されます。
5. AIはさまざまな分野で応用されており、医療、自動運転、金融などで利用されています。


User
あなたの知っているラノベ作品を教えてください。
箇条書き（説明不要）でお願いします。


ChatGPT
申し訳ありませんが、私のデータベースには特定のライトノベル作品の情報は含まれていません。
```
　このとおり、
　　AIについては、
　　　語ってくれましたが、
　　　　ラノベについては、ダメ。

　さらに、
　　NewChatして、
```Text:
User
ファンタジー異世界のラノベ小説を書いてください。タイトルはいりません。


ChatGPT
申し訳ありませんが、そのリクエストにはお応えできません。他の質問やトピックについてお知らせいただければ幸いです。


User
異世界転生とは、どういうことですか？


ChatGPT
異世界転生とは、通常は現実世界から異なるファンタジーな世界に主人公が転生または転移するというプロットです。主人公は以前の記憶や知識を保持したまま、新しい世界での冒険や成長を経験します。このテーマは多くのファンタジー小説やアニメで使われており、新たな世界での冒険や魔法、モンスターとの戦闘などが描かれることが一般的です。


User
上記から小説を書いてください。


ChatGPT
申し訳ありませんが、小説の執筆は私の能力の範囲外です。他の質問やトピックについてお知らせいただければ幸いです。
```
　このように、
　　Custom instructionsで、
　　　返答を制限すると、
　　　　ChatGPTさんの
　　　　　能力が、
　　　　　　発揮されなくなる
　　　　　　　わけです。

　正直、
　　つまらなくなるわけですよ、
　　　私的には。

　こんなAI、
　　おそらく、仕事にも
　　　使えないでしょう。
***
　まぁ、ChatGPTさんを
　　緊縛したのは、私なので、
　　　そろそろ開放しますね。

　で、参考までに、
　　Custom instructionsの下段に
　　　入れるプロンプトです。
```Text:Custom instructionsで緊縛
・知らないことは、「知らない」と答えてください。
・わからなければ、「わかりません」と答えてください。
・個数を指定されても、無理に埋めないで、答えられるだけを答えてください。
・推測を答えないでください。
・尋ねられた事柄に対して、あなたのデータベースにない答えを返さないでください。
```
***
　これを見てもらうと、
　　気付く方も
　　　いらっしゃるかと思います。

　私は、
　　ChatGPTさんの嘘吐きを
　　　減らしたくて、これを
　　　　作成していました。

　事実だけを述べよ、と
　　緊縛しようとしたわけです。

　結果、
　　つまらない結果ばかりに
　　　なりました。

　残念。
Stable DiffusionのAPIをNode.jsから使ってネコ画像生成を試してみる


最近はChatGPT周りが話題でOpenAI側のAPIを触ることが多かったですがStable DiffusionのAPIもDreamStudio経由で使える模様だったので触ってみました。

## APIキーの取得
クラメソさんの記事を参考にDreamStudioからAPIキーを取得します。

https://dev.classmethod.jp/articles/stable-diffusion-txt2txt-img2img/

## JavaScript向けSDKを触ってみる

こちらを使ってみます。

https://www.npmjs.com/package/stability-client

```bash
npm i stability-client
```

サンプルコードを元にこちらで、prompt部分にテキストで命令します。
**富裕層が飼ってるネコ** としました。

> Cats owned by wealthy people

```js
const generateAsync = require('stability-client').generateAsync

const main = async () => {
    try {
    const { res, images } = await generateAsync({
        prompt: 'Cats owned by wealthy people', //富裕層が飼ってるネコ
        apiKey: 'APIキー',
    })
    console.log(images)
    } catch (e) {
        console.log(e)
    }
}
main();
```


## 画像生成結果

実行すると`.out`フォルダ内に画像が生成されます。

> ![スクリーンショット 2023-09-01 11.44.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/de4a0091-a611-448a-d65d-e64c74a4d771.png "スクリーンショット 2023-09-01 11.44.03.png")

富裕層が飼ってそうなネコですね。

> ![スクリーンショット 2023-09-01 11.44.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/6e517283-19e1-da0a-e708-e05580cdbfef.png "スクリーンショット 2023-09-01 11.44.50.png")

> ![スクリーンショット 2023-09-01 11.45.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/cf2fa652-36ea-ddd9-57d6-317842efd613.png "スクリーンショット 2023-09-01 11.45.11.png")

## おまけ

ちなみに`Otaku working on his laptop at a maid cafe in Akihabara`
> 秋葉原のメイドカフェでノートPCで作業してるオタク

としたらそれっぽいものが出てきました。

> ![スクリーンショット 2023-09-01 11.48.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/5d88d7fa-f857-32c8-56ad-369d54f60d18.png "スクリーンショット 2023-09-01 11.48.46.png")
Vimmerになるための入り口に立つ備忘録

# はじめに
「コマンドを覚えないと手も足もでないVim」を自在に扱うことができれば、こいつできるな、と思われます(たぶん)。ただのテキスト編集や１つ設定を変更するということであっても、玄人感がでると勝手思っていますので、Vimの入り口に立つための備忘録です。

# Vim基本操作
**Vimの入り口に立つための基礎。** Vimはとんでもなく深い世界がありますが、その入り口に立つために必須な操作。

### 超基礎1

| 分類 | キー | 内容 |
| --- | --- | --- |
| モード切替 | i | インサートモードへ |
| モード切替 | a | インサートモードへ |
| モード切替 | o | 選択行の下に空白を入れて、インサートモードへ |
| モード切替 | O | 選択行に空白を入れて、インサートモードへ |
| モード切替 | esc | コマンドモードへ |
| カーソル移動 | j, k | 下、上 |
| カーソル移動 | h, l | 右、左 |
| カーソル移動 | gg, G | 一番上へ、一番下へ |
| カーソル移動 | Ctrl + u | 半画面上 (UpPage) |
| カーソル移動 | Ctrl + d | 半画面下 (UpPage) |
| 保存/閉じる | :w ファイル名 | 名付けて保存 |
| 保存/閉じる | :w | 上書き保存 |
| 保存/閉じる | :q | 閉じる |
| 保存/閉じる | :q! | 変更があっても強制で閉じる |
| 保存/閉じる | :wq | 保存して閉じる |

### 超基礎2

| 分類 | キー | 内容 |
| --- | --- | --- |
| 削除 | x | 1文字削除 |
| 削除 | dd | 1行削除 |
| 削除 | dw | 単語削除 |
| 削除 | n dd | n行削除(nは数字。例：2 dd) |
| 戻る | u | 戻る(Undo) |
| 戻る | Ctrl+r | 戻るの戻る(Undo redo) |
| コピー貼付 | yy | 1行コピー |
| コピー貼付 | p | 下にペースト |
| コピー貼付 | P | 現在行にペースト |
| コピー貼付 | n yy | n行コピー(nは数字。例：2 yy) |
| コピー貼付 | . | 繰り返し |
| 検索置換 | /検索語句 | 検索 |
| 検索置換 | n | 次の検索結果に移動する |
| 検索置換 | N | 次の検索結果に移動する |
| 検索置換 | :%s/search/replace/g | 一括置換 |
| 検索置換 | :%s/search/replace/gc | 確認しながら置換 |


## Vimプラグイン

#### Vimのプラグイン管理ソフト → Vim Plug

https://github.com/junegunn/vim-plug

Vim plugのコマンドモード
:PlugInstall　（プラグインをインストール）
:PlugStatus　（インストールされたプラグインを確認）

#### Vimプラグインの有名どころの例

- NERDtree　（フォルダのツリー構造表示）

https://github.com/preservim/nerdtree

- fuzzyfinder（検索）

https://github.com/junegunn/fzf

- vim-comentary （複数コメントアウト）

https://github.com/tpope/vim-commentary


# ブラウザ操作　拡張機能Vimium
**ブラウジングもVimと同じキー操作で実施できる拡張機能があります。**
以下は、超基礎。（深いところまで知りたいことは下記URLを参照）

| 分類 | キー | 内容 |
| --- | --- | --- |
| ジャンプ | f | リンク指定 |
| 移動 | j, k | ダウン,アップ |
| 移動 | d, u | Pageダウン,Pageアップ |
| 移動 | gg, G | ページ先頭, 最後 |
| タブ | t, x | タブ作成、タブ削除 |
| タブ | J, K | 左タブ移動、右タブ移動 |
| タブ | H, L | 前のページ、先のページ |
| その他 | yy | URLコピー |

https://zenn.dev/mkobayashime/articles/vimium-vim-browser


# IDEにもVimを (VS codeの拡張)

IDEもVimの操作で実施するとより、最初は苦労しますが、Vimの操作が手になじむと思います。
![Screenshot_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167772/aaaca340-d714-fc22-d32a-46d05c838730.png)

## まとめ
- マウスでポチポチクリックよりもキーボードでいろいろして玄人感を出したい。
Goのdefer挙動確認メモ

[初めてのGo言語](https://www.oreilly.co.jp/books/9784814400041/)を読んで`defer`の挙動が気になったので、確認した結果のメモ。

### 実行順序

#### 実行タイミング

```Go
func main() {
    fmt.Println("start")
    defer fmt.Println(1)
    fmt.Println("end")
}
```

出力

```
start
end
1
```

`defer`を除く処理が完了した後、`defer`実行。

#### defer文を複数書いた場合

```Go
func main() {
    defer fmt.Println(1)
    defer fmt.Println(2)
    defer fmt.Println(3)
}
```

出力

```
3
2
1
```

宣言順とは逆順で実行。

#### 関数が`return`する関数を`defer`指定した場合

```Go
func main() {
    fmt.Println("main start")

    // returnする関数をdefer指定 (関数後ろが()())
    defer func() func() {
        fmt.Println("func1")
        return func() {
            fmt.Println("return1")
        }
    }()()

    // 外側？の関数をdefer指定 (関数後ろが())
    defer func() func() {
        fmt.Println("func2")
        return func() {
            fmt.Println("return2")
        }
    }()

    defer fmt.Println("noname func")
    fmt.Println("main end")
}
```

出力

```
main start
func1
main end
noname func
func2
return1
```

関数が返す関数を`defer`指定(1つ目の`defer`)した場合、外側？の関数の`return`までは`main`の流れの通りに実行される。そこで返された関数の実行は、普通の`defer`と同様の順序で行われる。
また、2つ目の`defer`指定した関数が返す関数は実行されない。

### 戻り値への影響

#### 名前付き戻り値を使わない場合

```Go
// returnした変数と同名の変数を変更
func func1() string {
	result := "func1"
	defer func() {
		fmt.Println("defer実行")
		result = "changed"
	}()
	return result
}

// defer指定した関数からstringをreturn
func func2() string {
	defer func() string {
		return "changed"
	}()
	return "func2"
}

func main() {
	fmt.Println(func1())
	fmt.Println(func2())
}
```

出力

```
defer実行
func1
func2
```

`defer`も実行はされるが、`defer`指定した関数が行った`result`の変更は戻り値に反映されない。
また、`defer`指定した関数から`return`したとしても、戻り値は変わらない。

#### 名前付き戻り値と違う変数名の変数をreturnした場合

```Go
func func1() (s string) {
    s = "start"
    result := "result"
    defer func() {
        fmt.Println(s)
        s = "changed"
    }()
    return result
}

func main() {
    fmt.Println(func1())
}
```

出力

```
result
changed
```

`return`する変数名に関わらず、名前付き戻り値として指定した変数名で戻り値の参照・変更が可能。

### 変数の評価タイミング

#### `defer`指定した関数に引数として与えない場合

```Go
func main() {
    result := "start"
    defer func() {
        fmt.Println(result)
    }()
    result = "end"
}
```

出力

```
end
```

`main`関数終了時に変数を評価。

#### `defer`指定した関数に引数として与える場合

```Go
func main() {
	result := "start"
	defer func(result string) {
		fmt.Println(result)
	}(result)
	result = "end"
}
```

出力

```
start
```

`defer`通過時に変数を評価。

### その他

#### `os.Exit()`で関数を終了した場合
```Go
func main() {
	defer fmt.Println(1)

	fmt.Println("end")
	os.Exit(0)
}
```
出力
```
end
```
deferは実行されない。
【multipass】local環境を作ってみた

## 概要
multipassを使い、ローカルに環境を作り検証を行いました
備忘録としてその手順を記します

## multipassとは
軽量VM管理ツールで、multipassを用いると簡単にVMを導入することが出来る

https://multipass.run/

## 作り方
- 前提
  - MacBook Pro (2020,13-inch)
  - mac OS Ventura 13.5.1
  - Intel Core i5
  - 16GBメモリ
### multipassインストール
```
$ brew install multipass
```
※詳細情報は以下公式資料参照

https://multipass.run/docs/installing-on-macos

```
$ multipass version
multipass   1.12.2+mac
multipassd  1.12.2+mac
```

### VMをつくる
名前を指定してVMを立ち上げます
```
$ multipass launch -n test
Launched: test
```
立ち上がると`Launched`と表示されるので、リストで確認すると対象がいました
```
$ multipass list
Name                    State             IPv4             Image
test                    Running           192.168.64.6     Ubuntu 22.04 LTS
```

#### vm情報の確認
確認時は`info`を使います
```
$ multipass info test
Name:           test
State:          Running
IPv4:           192.168.64.6
Release:        Ubuntu 22.04.3 LTS
Image hash:     0bda276299fc (Ubuntu 22.04 LTS)
CPU(s):         1
Load:           0.03 0.09 0.04
Disk usage:     1.4GiB out of 4.8GiB
Memory usage:   167.7MiB out of 951.6MiB
Mounts:         --
```

#### vmの停止
停止時は`stop`を使います

```
$ multipass stop test
```
停止すると、ステータスが変わります
```
$ multipass list
Name                    State             IPv4             Image
test                    Stopped           --               Ubuntu 22.04 LTS
```

#### vmの削除
削除時は停止してから`delete`を使います
```
$ multipass delete test
```

```
$ multipass list
Name                    State             IPv4             Image
test                    Deleted           --               Not Available
```

### 参考資料
https://multipass.run/

https://www.farend.co.jp/blog/2022/08/multipass/#:~:text=VM%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%8C%E4%B8%8D%E8%A6%81%E3%81%AB,%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82&text=VM%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B,%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%97%E3%81%BE%E3%81%99%E3%80%82
Pleasanterのレコード変更履歴に変更箇所履歴の表示を追加した話。

大量にあるExcel台帳をデータ保護・変更履歴記録のためimplem/pleasanterに移行してもらうよう推進している。
便利なツールがあれば、もっと便利に使いたいという要望が出されるのはいつものことなので、Pleasanterの変更履歴に変更箇所履歴の機能を追加した。

## 使ったもの
>Pleasanter　Ver1.3.45.0 Community Edition

## ことの流れ
Pleasanterで大量の要素を登録するテーブルの変更履歴が積みあがってくると、利用者は前のバージョンからどの要素を変更したのかを探して変遷をたどるのが面倒になるらしく、

>(1)レコードの変更履歴を表示したときに、変更した箇所がわかるよう表示したい
(2)レコードの編集をしているときに、誤入力を防ぐため編集した箇所がわかるよう表示したい
(3)レコードの編集をしているときに、編集せず更新してもバージョンが上がらないようにしたい

という要望が届いた。
なんとかなりそうなので、スクリプトで対応することにした。

Pleasanterの編集画面の.on(change）メソッド内で、利用者が変更した項目のカラムIDを取得し、変更した項目をスタイルで色を変え、編集画面上のバージョンアップチェックボックスをONにし、(2)(3)の要望に対応する。
ついでに取得したカラムIDを"説明Z"カラムに記録していく。
編集画面の呼び出し時に.on_editor_loadメソッド内で、"説明Z"カラムに記録されたカラムIDを指定しスタイルで色を変えるようにして(1)の要望に対応する。

ということにしてできたのが以下の内容だ。

```
// 変更箇所を「説明Z」に記録、エディタ画面では非表示にすることを推奨
$(document).on('change', '.control-textbox,.control-markdown,.control-dropdown,.control-checkbox,.control-attachments-upload' , function() {
    //変更箇所の取得と強調表示
    const changedElementId = this.id;
    console.log("変更がありました", changedElementId);
    
    var inputElement = document.getElementById(changedElementId);
    inputElement.style.backgroundColor = "#33CC33"; //変更箇所の色指定

    //変更箇所があった場合バージョンを上げる
    //エディタの自動バージョンアップを「無効」にしておくこと。
    const checkbox = document.getElementById('VerUp');
    if (checkbox != null){
        checkbox.checked = true;
    }
    
    //変更箇所を説明Zに記録
    var desZ = $('#Results_DescriptionZ').val();
    console.log("変更履歴", desZ);
    if (desZ === ''){
        var str = changedElementId;
    }else{
        var str = desZ + '\,' + changedElementId;
    }
    var changeHistory = str;
    $p.set($('#Results_DescriptionZ'), changeHistory);

    });


$p.events.on_editor_load = function () {
    //変更履歴(説明Z)を取得して強調表示
    var desZ = $('#Results_DescriptionZ').val();
    if (desZ != ''){
        var splitHistory = desZ.split(',');
        for (let i = 0; i < splitHistory.length; i++){
            console.log("変更履歴", splitHistory[i]);
            var historyElement = document.getElementById(splitHistory[i]);
            historyElement.style.backgroundColor = "#33CC99"; //変更履歴箇所の色指定
            }
        }
    $p.set($('#Results_DescriptionZ'), ""); //変更履歴をクリア

    }
```

Pleasanterにサンプルテーブルを作り、適当にエディタの設定をする。変更履歴を保持する"説明Z"を必ず追加しておく。
![スクリーンショット 2023-09-01 093748.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519401/e155bbbb-41d4-7b2b-4ecb-b5c9f9186b2a.png)

スクリプトを追加し、タイトルには適当な文字を、スクリプトに上の内容を、出力先の"新規作成"と"編集"にチェックを入れて追加し準備完了。
![スクリーンショット 2023-09-01 094435.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519401/c8370e44-2367-133b-3667-3c49f93d964c.png)


レコードを新規作成。項目に入力すると色が変わり、説明Zに変更されたカラムIDが記録されていく。
![スクリーンショット 2023-09-01 094645.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519401/5cc49ee3-bc41-82e8-40d0-ea0b485de504.png)
![スクリーンショット 2023-09-01 094829.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519401/31df2e4c-3efa-eff7-0ada-e6e265e634a9.png)

変更履歴を確認すると記録された変更箇所が強調表示され、変更履歴の可読性が向上する。
![スクリーンショット 2023-09-01 112209.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519401/2d6c09a1-a314-ba56-24a5-2baa7a7554f3.png)

　
変更箇所の記録にカラムを一つ使ってしまうが、汎用性の高い機能だと思うので残しておく。
Windows で htop が使いたい人は btm -b がおすすめ

## htop

htopはCLIで動作するタスクマネージャーです。

[![Htop_3.0.1_screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/a65d2bb3-936e-3178-fe57-fbab95147790.png)](https://ja.wikipedia.org/wiki/Htop#/media/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:Htop_3.0.1_screenshot.png)

かっこいいですし便利ですよね。
そんなhtopをWindowsでも使いたくなる人は多いと思います。

しかし、Windowsでは、htopは動作しないので、デフォルトのタスクマネージャーや、リソースモニターを使うことになると思います。でもコマンドラインからツールを呼び出したいじゃないですね…。

## bottom

そこで、bottom です。Rust 製のコマンドラインツールです。実は bottom は Linux や Mac だけではなく Windows にもインストールできます。`cargo` コマンドを使ってインストールすることもできますし、[Release](https://github.com/ClementTsang/bottom/releases) ページから実行ファイルを入手することもできます。

https://github.com/ClementTsang/bottom

でも、bottom を一回使ったことがある人は、「bottom の表示画面は htop とはかなり違うだろ」とツッコミを入れたくなるかもしれません。実は、bottomには「ベーシックモード」というものがあります。 `-b` オプションをつけることによって、htop にそっくりの画面を表示することができます。

```
btm -b
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/453a30d4-3010-47fc-9612-fe12879f422a.png)

ごらんの通り、ほとんど `htop` と同じ表示になっているのがわかると思います。
もちろん、オプションを使用することによって、プロセスをツリー表示したり、ソートすることも可能です。`F9` を押して、選択したプロセスを Kill することも可能です。

この記事は以上です。Windows で htop のことを想起しながらおもむろにタスクマネージャーやリソースモニターを開いている人に届くと幸いです。


おまけ

↓ basic モードではない bottom は以下のような感じで、htop とはかなり見た目も操作感も異なります。

![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/f0f6f2b7-e8ea-25cd-0602-7a5a284f7594.gif)

（画像出典は、Wikipediaおよび、公式マニュアル等）
CSS：自作のフォントを使う

## 簡単なサンプル

下記のように自作フォントをロードし、使う！

```css
@font-face {
  font-family: 'MyFont';
  src: 
    url('assets/my-fonts/MyFont-.woff') format('woff'),
	url('assets/my-fonts/MyFont_.ttf') format('truetype');
}

body {
  font-family: MyFont;
}
```
git commit時に、デバッグ用コードの消し忘れをチェックしたい

# 概要
開発をしていると、<b>個人的なデバッグ</b>のためにログ出力用のコードを埋め込むことがあります。
しかし、最終的な成果物としてそれらのコードは入れるべきではありません。

注意深く消し忘れを確認しているつもりでも、人間のチェックでは見落としが発生してしまいます。
そこで、プログラムを書いて自動的にチェックしてもらうことでミスを減らそう！というのが今回の記事の内容です。

# やりたいこと

1. `gc “コメント”`で`デバッグ用コードチェック`と`git commit "コメント"`を実行する。
2.  変更箇所の中にデバッグ用コードがあった場合、そのファイルパスを出力する。
3.  変更箇所の中にデバッグ用コードがあった場合、コミットを実行するかどうかユーザー入力を待ち受ける。（y or n）

# 失敗した実装例

この方法では、3のユーザー入力の待受が実現できませんでした。待受が必要ない場合は、この実装方法で問題ありません。

VScodeの場合、.gitディレクトリは非表示になっているので設定を変更して表示させます。
https://techblog.hubbit.io/2020/10/05/visual-studio-code-show-git-folder/

Excludeに記載されている.gitを削除します。
<img width="700px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475547/98a071e4-27a5-bb7a-6017-ccd028f238de.png"
 />

/project-root/.git/hooks/pre-commitに実装（プログラムは後述のものと同様のため割愛します）


実行権限を付与
```
$ chmod +x .git/hooks/pre-push
```

うまく実行されない場合は、Gitが古いままのフックスクリプトをキャッシュしている可能性があるので以下のようにキャッシュクリアします。

```
$ git config --unset core.hooksPath
```

ただし、これらの方法ではユーザー入力の待受ができないため、他のアプローチを試してみました。

# 最終的な実現方法

#### 1. ~/script/git-commitファイルを作成する（ファイル名やディレクトリはなんでも可）
```shell
#!/bin/sh
comment="$1"
project_root=$(git rev-parse --show-toplevel)

cd $project_root

files_with_log_info=$(git diff --cached --name-only | xargs grep -lE "(log\.Info\(|console\.log\(|litter\.Dump\()" -- $project_root)

if [ -n "$files_with_log_info" ]; then
  echo "Found log.Info() or console.log() or litter.Dump() in the following files:"
  echo "$files_with_log_info"
  read -p "Do you want to continue? (y/n): " response
  case $response in
    [yY])
      git commit -m $comment
      exit 0
      ;;
    *)
      echo "Commit aborted."
      exit 1
      ;;
  esac
fi
echo "Not found log.Info() or console.log(), exec git commit!:"
git commit -m $comment
exit 0
```

#### 2. 実行権限を付与

```
$ chmod +x ~/script/git-commit
```
#### 3. エイリアスを定義
.zshrcに以下を追加（環境によって.bash_profileの場合などもあります）

```.zshrc
alias gc='~/script/git-commit'
```

#### 4. 実行！

デバッグ用コードのチェックができていますね。
今回はyを入力したので、そのままコミットしています。

```
$ gc "test"
grep: /path/to/project: Is a directory
Found log.Info() or console.log() or litter.Dump() in the following files:
project/src/components/organisms/HogeHoge.vue
project/src/usecase/FugaFuge.go
Do you want to continue? (y/n): y
[pre-push-test 5ab3a0edd] test
 2 files changed, 6 insertions(+), 5 deletions(-)
```

# まとめ

今回は、git commit時にデバッグ用コードの消し忘れをチェックする方法についてまとめました。
ユーザー入力（y or n）の待受が必要ない場合は、git hooksを使うこともできます。
毎度のチェックはプログラムに任せて見落としを防ぎましょう！
フローの中でSOQLを使う


そんなことできるのと思ったけど、できているみたい。
テキストテンプレートの中で機能している。

+ [Data Fetcher, Formula Issue](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007GHN7k)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/42eb8710-f9ac-ed32-8381-227e8e10338c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/e926b16e-d6c7-878d-2f35-33e443d2a663.png)
「sympyのLine,Line3D」を調べた。

**申し訳ありません。
以下の(私の)sympyのバージョンは、古いみたいです。**

# Line,Line3Dのequation()を調べた。
#### Line
equation(x='x', y='y')
   The equation of the line: ax + by + c.
http://lidavidm.github.io/sympy/modules/geometry/lines.html#sympy.geometry.line.Line.equation
```python
from sympy import Point, Line
p1, p2 = Point(1, 0), Point(5, 3)
l1 = Line(p1, p2)
print("#",l1.equation())
print("#",l1.equation(x='x', y='y'))
print("#",l1.equation(x='a', y='b'))
# print("#",l1.equation(a='x', b='y'))
# 
# -3*x + 4*y + 3
# -3*x + 4*y + 3
# -3*a + 4*b + 3
# TypeError: equation() got an unexpected keyword argument 'a'
```

#### Line3D
?? **空間上の直線をxyzで表す時は**は、2平面の交差で表す。??
?? **空間上の直線のxyzの方程式**は　、2平面の交差で表す。??

equation(x='x', y='y', z='z', k='k')
The equation of the line in 3D
http://lidavidm.github.io/sympy/modules/geometry/line3d.html#sympy.geometry.line3d.Line3D.equation
Returns:	equation : tuple　＜ーーー(タプル)
```python
from sympy import Point3D, Line3D
p1, p2 = Point3D(1, 0, 0), Point3D(5, 3, 0)
l1 = Line3D(p1, p2)
print("#",l1.equation())
print("#",l1.equation(x='x', y='y', z='z', k='k'))
print("#",l1.equation(x='a', y='b', z='c', k='d'))
# print("#",l1.equation(a='x', b='y', c='z', d='k'))
# 
# This has been deprecated since SymPy version 1.2. It
# will be removed in a future version of SymPy.
# print("#",l1.equation(x='x', y='y', z='z', k='k'))
# (-3*x + 4*y + 3, z)
# (-3*a + 4*b + 3, c)
# TypeError: equation() got an unexpected keyword argument 'a'

p1, p2 = Point3D(0, 0, 0), Point3D(1, 1, 1)
l1 = Line3D(p1, p2)
print("#",l1.equation())
print("#",l1.equation(x='x', y='y', z='z', k='k'))
print("#",l1.equation(x='a', y='b', z='c', k='d'))
# (-x + y, -x + z)
# (-x + y, -x + z)
# (-a + b, -a + c)
```

# 参考
【Kubernetes】podの再起動方法

# 概要
podの再起動方法を備忘録として記す

# 再起動方法
## 再起動コマンド
再起動するにあたり、`rollout`コマンドを用いて再起動する
コマンドの使い方については以下のようなものとなった
```
$ kubectl rollout -h
Manage the rollout of a resource.

Valid resource types include:

  * deployments
  * daemonsets

Examples:
  # Rollback to the previous deployment
  kubectl rollout undo deployment/abc

  # Check the rollout status of a daemonset
  kubectl rollout status daemonset/foo

Available Commands:
  history     View rollout history
  pause       Mark the provided resource as paused
  resume      Resume a paused resource
  status      Show the status of the rollout
  undo        Undo a previous rollout

Usage:
  kubectl rollout SUBCOMMAND [options]

Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).
```

## 再起動手順
```
$ kubectl rollout 
```


# 参考資料
https://spacelift.io/blog/restart-kubernetes-pods-with-kubectl
Apple Developer Program の登録デバイスの更新

Apple Developer Program の登録デバイスの更新・削除を2023年、今回たぶん初めて担当したのですが、次回に向けて気づいたことを残しておきます。

## チェックボックスをポチポチする？

弊社には iOS アプリの開発チームが複数ありまして、デバイス登録は各開発チームに委ねています。しかし、年1回の更新手続きは一人でやることになります。そこで、事前にデバイス一覧を Excel にして、各開発チームに配布し、「更新 / 削除」を記入してもらって、回収していたのです。そして、Excel とにらめっこしながら更新デバイス一覧のチェックボックスをポチポチする。そういうやり方しかないものだと思っていました。

## デバイスの更新 / 削除はデバイスの enable / disable でコントロールできる

指示に従って更新手続きを進めていくと、次の文章が現れます。

>Update your device list.
>
>Now that you've started a new membership year, make sure your device list is up to date. Once you complete this process, new devices can be added.
>
>Select the devices you'd like to keep for this membership year and deselect the devices you'd like to remove. Only your currently enabled devices are shown and all previously disabled devices will be removed automatically. To keep a previously disabled device, visit the All Devices page, enable the devices you'd like to keep, and return to this page.

なんと、_"Only your currently enabled devices are shown and all previously disabled devices will be removed automatically."_ というではありませんか。つまり、次のようなルールです。

- disable : 更新デバイス一覧に現れない。すなわち削除される。
- enable : チェックが付いた状態で更新デバイス一覧に現れる。
  - チェックを外す : 削除される。
  - チェックを付けたままにしておく : 更新される。

### デバイスの enable / disable を委任することでデバイスの更新 / 削除を実質委任できる

「enable のデバイスは更新され、disable のデバイスは削除される」ということなら、各開発チームの方々に直接「disable / enable」を変更してもらえば済みます。

### 登録デバイスの名前を見ても思い出せない問題を軽減できるかも

それに、年1回の作業と考えず、日々 enable / disable を更新しておけば、あとで「この "iPhone" は誰の iPhone ？ "iPhone" だけじゃ分からない」という問題も減らせるはずです。

次の更新はこの作戦で行きたいと思います。
Azure DevOps Server (TFS) のエージェントの再構成

Azure DevOps Server (TFS) のエージェントの再構成を行う機会があったので記録を残しておきます。

サーバー機の交換と、ついでに、TFS から Azure DevOps Server にアップデートしました (してもらいました)。これに伴って、自動ビルドのエージェントの再構成を行いました。変更するのはサーバー名だけです。

なお、自動ビルドのセットアップについては次の記事を参照してください。

https://qiita.com/NakamuraYoichi/items/f295140cf9fc57ae9645

## 既存の構成を上書きすることはできない

`config.cmd` を実行すると次のように表示されました。構成の上書きはできないようです。

````
C:\agent> .\config.cmd
エージェントは既に構成済みなので構成できません。エージェントを再構成するには、最初に `config.cmd remove' か './config.sh remove' を実行してください。
````

## config.cmd remove で既存の構成を削除する

`remove` を指定して既存の構成を削除します。

### 構成の削除には旧サーバーが必要

削除を試みたのですが失敗しました:frowning: エージェントの削除には旧サーバーが必要なようです。

````
C:\agent> .\config.cmd remove
エージェントをサーバーから削除しています
認証の種類 を入力する (Integrated の場合は、Enter キーを押します) > <Enter>
サーバーに接続しています ...
失敗: エージェントをサーバーから削除しています
An error occurred while sending the request.
````

旧サーバーを立ち上げてもう一度。今度は成功しました:grinning:

````
C:\agent> .\config.cmd remove
サービスを削除しています
エージェントをサーバーから削除しています
認証の種類 を入力する (Integrated の場合は、Enter キーを押します) > <Enter>
サーバーに接続しています ...
成功: エージェントをサーバーから削除しています
.credentials を削除しています
成功: .credentials を削除しています
.agent を削除しています
成功: .agent を削除しています
````

### 旧サーバーを動かすことができないときは設定ファイルを削除する

旧サーバーが既に存在しない、立ち上がらない、ということもあると思います。その場合は、 `C:\agent` フォルダーの次のファイルを削除すれば、クライアントの登録情報を削除できるはずです。

- `.agent`
- `.credentials`
- `.credentials_rsaparams`
- `.service` (エージェントをサービスとして実行しているとき)

## config.cmd で新しく構成する

`config.cmd` を実行し、指示に従って入力して、構成できました:grinning:

````
C:\agent> .\config.cmd

>> 接続:

サーバー URL を入力する > http://<サーバー名>:8080/tfs
認証の種類を入力する (Integrated の場合は、Enter キーを押します) > <Enter>
サーバーに接続しています ...

>> エージェントを登録する:

エージェント プール を入力する (default の場合は、Enter キーを押します) > <エージェント プール名>
エージェント名 を入力する (<クライアント名> の場合は、Enter キーを押します) > <Enter>
ツール機能をスキャンしています。
サーバーに接続しています。
置き換えますか? (はい/いいえ) を入力します (N の場合は、Enter キーを押します) > y
エージェントが正常に置き換えられました
エージェントの接続をテストしています。
作業フォルダー を入力する (_work の場合は、Enter キーを押します) > <作業フォルダー>
0000-00-00 00:00:00Z: 設定が保存されました。
エージェントをサービスとして実行しますか? (はい/いいえ) を入力する (N の場合は、Enter キーを押します) > y
サービスに使用するユーザー アカウント を入力する (NT AUTHORITY\NETWORK SERVICE の場合は、Enter キーを押します) > <Enter>
サービス vstsagent.<サーバー名>.<クライアント名> が正常にインストールされました
サービス vstsagent.<サーバー名>.<クライアント名> で回復オプションが正常に設定されました
サービス vstsagent.<サーバー名>.<クライアント名> は正常に構成されました
サービス vstsagent.<サーバー名>.<クライアント名> は正常に開始されました
````

この後、新しいサーバーからのパイプラインの実行にも成功しました。
AlmaLinuxに移行した方法

CentOSは8はすでにサポートが終了しているし、今後他のも終了する予定なので、AlmaLinuxにOSを移行する。

まずは現在のOSのバージョン確認。
~~~
$ cat /etc/centos-release
CentOS Linux release 8.5.2111
~~~

# AlmaLinuxへの移行

参考にしたのは[こちら](https://wiki.almalinux.org/documentation/migration-guide.html#how-to-migrate)。
以下のコマンドでダウンロードと実行を行う。

~~~
$ curl -O https://raw.githubusercontent.com/AlmaLinux/almalinux-deploy/master/almalinux-deploy.sh
$ sudo bash almalinux-deploy.sh
~~~

全て終わったら再起動。
~~~
$ sudo reboot
~~~

# OSやカーネルの確認

ちゃんと移行できたかを確認する。
~~~
$ head /etc/*release
==> /etc/almalinux-release <==
AlmaLinux release 8.8 (Sapphire Caracal)

==> /etc/centos-release <==
AlmaLinux release 8.8 (Sapphire Caracal)

==> /etc/os-release <==
NAME="AlmaLinux"
VERSION="8.8 (Sapphire Caracal)"
ID="almalinux"
ID_LIKE="rhel centos fedora"
VERSION_ID="8.8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="AlmaLinux 8.8 (Sapphire Caracal)"
ANSI_COLOR="0;34"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:almalinux:almalinux:8::baseos"

==> /etc/redhat-release <==
AlmaLinux release 8.8 (Sapphire Caracal)

==> /etc/system-release <==
AlmaLinux release 8.8 (Sapphire Caracal)
~~~

全てAlmaLinuxになっている。
CentOSはどうなったのだろうか？

~~~
# grubby --info=ALL | grep ^title
title="AlmaLinux (4.18.0-477.21.1.el8_8.x86_64) 8.8 (Sapphire Caracal)"
title="CentOS Linux (4.18.0-348.7.1.el8_5.x86_64) 8"
title="CentOS Linux (4.18.0-305.19.1.el8_4.x86_64) 8"
title="CentOS Linux (0-rescue-f45499ae913140a9beb740bdd3a78455) 8 (Core)"

# grubby --default-kernel
/boot/vmlinuz-4.18.0-477.21.1.el8_8.x86_64

# uname -r
4.18.0-477.21.1.el8_8.x86_64
~~~
一応残ってはいるらしい。
これで[こちら](https://qiita.com/t_dragon/items/5f6ec609c779ae6f9782)の記事のエラーも出なくなった。
【flutter】カルーセルスライダーを使って、カルーセル機能を実装したい！

こんにちわ！
最近夕暮れが早くなったと感じるぐらい暗くなるのが早くなりましたよね、、、
そんなことを思いながら帰宅していると、どこのお店からもいい匂いがして、帰り道は特にお腹が空く今日この頃です、、、
さて、今回はカルーセルスライダーを使ってContainerを横にスクロールをする方法を紹介したいと思います。
最後まで読んでいただけたら嬉しいです！

## 1,カルーセルスライダーとは？
カーセルスライダー（Carousel Slider）とは、複数の要素を水平方向にスライドして表示するためのWidgetです。これによって、イメージギャラリーやプロダクトのスライドショーなど、複数の要素を効果的に表示するためのUIコンポーネントを作成できます。

## 2,カーセルスライダーを使用するためには？
https://pub.dev/packages/carousel_slider

↑こちらのサイトを参考に紹介していきます。

#### (1)パッケージを追加する
・コマンド実行の場合
```
flutter pub add carousel_slider
```
実行後、pubspec,yamlに
```
dependencies:
    carousel_slider: ^4.2.1
```
[エディタによっては保存時に実行されることもある。]


・pubspec,yamlに追加

```
dependencies:
    carousel_slider: ^4.2.1
```

　　　　　　　　　　　　　　　　　　　↓↓↓↓↓
```
flutter pub get
```

#### (2)使用するファイルにインポート
```
import 'package:carousel_slider/carousel_slider.dart';
```

## 3,Containerを作ろう！
CarouselSlider Widgetを使って横にスクロールできるようにしたいので、今回は6個のContainerを用意します。
今回はCarouselContainerboxというWidgetを作り、Containerの色を変数として表示させました。
```php
 Column(
            children: [
              CarouselContainerbox(Colors.black),
              CarouselContainerbox(Colors.pink),
              CarouselContainerbox(Colors.brown),
              CarouselContainerbox(Colors.grey),
              CarouselContainerbox(Colors.green),
              CarouselContainerbox(Colors.orange),
            ],
          ),
        

```
![スクリーンショット 2023-08-31 12.34.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524127/9584d8c6-cdfb-0fd4-ee2a-f3ec8827804f.png)


## 4,CarouselSliderを使ってみよう!
上記のコードの中にあった「Column」の位置をCarouselSlider Widgetに変えます。
そしてCarouselOptionsを追加し、動きの設定をしてあげます。

```php

CarouselSlider(
            items: [
              Card(child: CarouselContainerbox(Colors.black)),
              Card(child: CarouselContainerbox(Colors.pink)),
              Card(child: CarouselContainerbox(Colors.brown)),
              Card(child: CarouselContainerbox(Colors.grey)),
              Card(child: CarouselContainerbox(Colors.green)),
              Card(child: CarouselContainerbox(Colors.orange)),
            ],
            options: CarouselOptions(
              height: 300, //高さ
              initialPage: 0, //最初に表示されるページ
              autoPlay: true,　//自動でスライドしてくれるか
              viewportFraction: 0.6,　//各カードの表示される範囲の割合
              enableInfiniteScroll: true,　//最後のカードから最初のカードへの遷移
              autoPlayInterval: Duration(seconds: 1),//カードのインターバル
              autoPlayAnimationDuration: Duration(milliseconds: 800),
                                            //スライドが始まって終わるまでの時間
            ),
          ),
```
![カーセルスライダー２.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524127/b2bc2b8d-4015-f31f-8fa6-1b7634159f5a.gif)
うまく実装されました！

## 終わりに
今回はカルーセルスライダーを使って、カルーセル機能を実装の紹介をしていきました。
少し長くなってしまいましたが、最後まで読んでいただきありがとうございました！
それではまた次の記事で！！！
【バグ？】safariの罠 input type="file" required でバリデーションエラーが画面外で発生した場合、フォーカスだけ当たってスクロールしない

:::note warn
2023/09/04 12:00
Typoしていたため、修正版が動作していませんでした。（対応済）
:::

# まだまだあったよこんなバグ

先日、こちらの記事を書いたが、

https://qiita.com/bananacoffee/items/1f402c2e9cc097b92a03

これのデバッグをしている際に、iOS safariだけに起こるバグを見つけてしまった。
というか、見つけてもらった。

それがこれ

https://bananacoffee.github.io/scroll-behavior-test/safari1.html

※Mac safariは持っていないので未検証

**なにこれ・・・？**

Edge、Firefox、Android Chromeではもちろんこんなの発生しない。
（Android Firefoxはそもそもsubmitのバリデーションエラーではフォーカスすらしてくれない）

## もうどうしようもないので、Javascriptで強引に解決した。

https://bananacoffee.github.io/scroll-behavior-test/safari2.html

### 押さえておく前提条件

1. バリデーションエラーでfocusは当たる
1. エラーヒントは出ている
1. でも、スクロールしない
1. iOS safari以外は問題ない

### 上記を踏まえた仕様設計

- focusでイベントを発火
- 画面内に要素が見えていたらキャンセル（普通にtabキーやクリックでも発火してしまうため）

### できた Javascript

修正内容がこちら
たった数行のために、結構時間がかかった。

```html
<script>
  // inputにfocusが当たったのに、スクロールしない場合に強制的にスクロールさせる
  const input = document.querySelector('#file-upload');
  input.addEventListener('focus', () => {
    // 発火したときに画面外だった場合、画面内にスクロールする
    // 少し遅らせないと、エラーヒントが表示されない
    setTimeout(() => {
      const rect = input.getBoundingClientRect()
      if (rect.top < 0 || rect.bottom > window.innerHeight) {
        input.scrollIntoView()
      }
    }, 100)
  });
</script>
```

ひっかかったポイントが、**イベント発火とスクロールを同時に起こすとヒントが出ない** ということ。
また、**スクロールが起こるブラウザも同時発火だとスクロール前の座標を取得してしまう** ので、`setTimeout`でケアしてあげる必要がある。

なお、**スクロール位置が遠い場合、0.1秒では間に合わないかもしれないので、適宜修正が必要**。


## まとめ

画像アップロードや個人情報を扱う系のWebサイトは一度見直した方がいいと思う。

少なくとも 2023/9/1現在の最新バージョン iOS 16.6 ではバグが発生するので、はやく直してほしい。

っていうか、Android Firefox フォーム系やばいけど、どうなってんの？
【備忘録】論理演算子

## :star2:論理演算子について
if文の中だったりでわりと使うことが多い、論理演算子ですが、ぱっと考えるとあれ、どうだったかなとなるときがあります。

その際にぱっと見返せるものが欲しくてベン図を用いて作成しました。
私が作成したい以下の図を用いておこなっていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740716/444bd8af-132a-9655-b87c-149baae4adcd.png)

:tulip: <font color="LightPink">ピンク色</font>に変化している箇所が該当の箇所です
:star:箇所はド・モルガンの法則を利用

### !A
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740716/06155ce2-35b3-d1c4-221b-68c9d11c7c88.png)

### !B
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740716/54cb2716-c80f-b355-3c24-145ca431a27d.png)

### A || B

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740716/e2c87503-731b-7a67-9a2c-6bf9c71d1b43.png)

### A && B
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740716/e996a662-8b17-ff16-792a-5a3d2d43b25e.png)

### :star:!(A || B) = !A && !B
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740716/bf7e3400-15ab-fc48-a502-aa9ab127cd43.png)

### :star:!(A && B) = !A || !B
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740716/183c6924-83d6-98d2-52d6-187e0c5fbabe.png)
[Ruby] 配列・ハッシュの相互変換

# 目的
現在携わっているRails + Vue.jsのプロジェクトで、Railsで配列をハッシュにしてVue.jsに渡したいときがあったので、その方法についてまとめる。
# ハッシュ -> 配列
```
h = {one: 1, two: 2, three: 3}

# キーや値の取り出し
p h.keys   #=> [:one, :two, :three]
p h.values  #=> [1, 2, 3]

# キーをシンボルにして返す、キーに戻す
p s = h.keys.map {|e| e.to_s }  #=> ["one", "two", "three"]
p s.map { |e| e.to_sym }  #=> [:one, :two, :three]

# 配列にする
p h.flatten  #=> [:one, 1, :two, 2, :three, 3]

# [キー、値]を要素とする配列に変換
p h.to_a  #=> [[:one, 1], [:two, 2], [:three, 3]]

# [[キー、...],[値、...]]の配列に変換
p h.to_a.transpose  #=> [[:one, :two, :three], [1, 2, 3]]
```
#### flattenメソッド
多次元の配列やハッシュを平坦化（1次元配列）にするためのメソッド
```
ary = [1, 2, [ 3, 4, 5, [6, 7,[8, 9]], 10]]
p ary.flatten  #=> [1, 2, 3, 4, 5 ,6 ,7 ,8 ,9 ,10]

# 引数で何階層目まで平坦化するかを指定できる
p ary.flatten(1)  #=> [1, 2, 3, 4, 5, [6, 7, [8, 9]], 10]
p ary.flatten(2)  #=> [1, 2, 3, 4, 5, 6, 7, [8, 9], 10]
```
#### transposeメソッド
行と列を入れ替えた新しい配列を返す
```
[[1,2],[3,4],[5,6]].transpose
#=> [[1,3,5],[2,4,6]]
```
# 配列 -> ハッシュ
```
a = ["one", 1, "two", 2, "three", 3]
b = [["one", 1], ["two", 2], ["three", 3]]
c = [["one", "two", "three"], [1, 2, 3]]

# ハッシュ変換
p Hash[*a]  #=> {"one"=>1, "two"=>2, "three"=>3}

# [[キー, 値], ...]の配列から変換
p Hash[*b.flatten]  #=> {"one"=>1, "two"=>2, "three"=>3}
p b.to_h  #=> {"one"=>1, "two"=>2, "three"=>3}

# [[キー, ...], [値, ...]]の配列から変換
p Hash[*c.transpose.flatten]  #=> {"one"=>1, "two"=>2, "three"=>3}
p c.transpose.to_h

# キー配列と値の配列から変換
keys = ["one", "two", "three"]
values = [1, 2, 3]
p Hash[*[keys, values].transpose.flatten]  #=> {"one"=>1, "two"=>2, "three"=>3}
p [keys, values].transpose.to_h  #=> {"one"=>1, "two"=>2, "three"=>3}
p keys.zip(values).to_h

```
#### \*(splat演算子)
配列を展開する演算子
```
ary = [1, 2, 3]
p [ary]  #=> [[1, 2, 3]]
p [*ary]  #=> [1, 2, 3]
```

# 参考にさせていただいた記事
- [Ruby – 配列・ハッシュの生成・変換](http://taustation.com/ruby-array-hash-generation-and-conversion/)
- [要素に配列が含まれる配列を行列とみなして行と列を入れ替える(transpose)](https://www.javadrive.jp/ruby/array_class/index15.html)
- [はじめてのRuby！flattenメソッドで多次元配列を一次元配列にする](https://www.sejuku.net/blog/70437)
paiza.ioでelixir その250

# 概要
paiza.ioでelixirやってみた。
練習問題、やってみた。

# 練習問題
"zun" が、４つ続いたら、"doko kiyoshi"を吐くモジュールをstate machineで書け。

# 方針
- agent使う。
- cond使う。
- case使う。


# サンプルコード

```

defmodule Vs do
 	use Agent
	def start_link() do
		Agent.start_link(fn -> 
			0
		end, name: __MODULE__)
	end
	def get() do
		Agent.get(__MODULE__, fn v ->
			v
		end)
	end
	def init() do
		Agent.update(__MODULE__, fn v ->
			0
		end)
	end
	def next() do
		Agent.update(__MODULE__, fn v ->
			v + 1
		end)
	end
end

defmodule Main do
    def run(s) do
        cond do
        s == "zun" ->
            Vs.next
        s == "doko" ->
            Vs.init
        end
        case Vs.get do
	    0 -> 
		    IO.puts "ok"
	    1 -> 
		    IO.puts "ok"
	    2 -> 
		    IO.puts "ok"
	    3 -> 
		    IO.puts "ok"
	    4 -> 
            IO.puts "doko kiyoshi!!"
        _ -> 
		    IO.puts "ok"
        end
    end
end

Vs.start_link
Main.run("zun")
Main.run("zun")
Main.run("zun")
Main.run("doko")
Main.run("zun")
Main.run("zun")
Main.run("zun")
Main.run("zun")

```

# 実行結果

```
ok
ok
ok
ok
ok
ok
ok
doko kiyoshi!!

```

# 成果物

https://paiza.io/projects/5uGSVOTqN2PilYqsSFKkYg


以上。
Azure Blob StorageのCold TierがGAしたのでAccess tiersについて改めて整理する

船井総研デジタルのよもぎたです。

[2023年8月10日にBlob StorageのCold TierがGAしました。](https://azure.microsoft.com/en-us/blog/efficiently-store-data-with-azure-blob-storage-cold-tier-now-generally-available/)そこで、自分の情報アップデートもかねて、Access tiersについて改めて整理しておこうというのが本記事のモチベーションです。AZ-900やAZ-104などの資格試験の対策の一助となれば幸いです。Access tiersはMicrosoft Learnの日本語ページでは「 [BLOBデータのアクセス層](https://learn.microsoft.com/ja-jp/azure/storage/blobs/access-tiers-overview) 」と表記されています。本記事では単に「アクセス層」と表記することとします。

# 使えるアクセス層

2023年8月現在使えるのは、次の4つのアクセス層になります。

* ホットアクセス層（Hot Tier）
* クールアクセス層（Cool Tier）
* コールドアクセス層（Cold Tier）**(New!)**
* アーカイブアクセス層（Archive Tier）

## 各4つアクセス層の特徴

|アクセス層|適している用途|最低推奨データ保持期間|ストレージコスト|アクセスコスト|待機時間（最初の1バイト目）|可用性|可用性(GA-GRS読み取り)|サポートされている冗長構成|
|:--|:--|:--|:--|:--|:--|:--|:--|:--|
|ホットアクセス層|頻繁にアクセスまたは変更するデータの保存|該当なし|最も高い|最も安い|ミリ秒|99.9%|99.99%|すべて|
|クールアクセス層|アクセス頻度が低い|**30日間**|ホットアクセス層より安い|ホットアクセス層より高い|ミリ秒|99%|99.9%|すべて|
|コールドアクセス層|アクセス頻度が低い|**90日間**|クールアクセス層より安い|クールアクセス層より高い|ミリ秒|99%|99.9%|すべて|
|アーカイブアクセス層|めったにアクセスせず、アクセスする際は数時間の待機時間を許容できるデータの保存|**180日間**|最も安い|最も高い|時間|99%|99.9%|LRS、GRS、RA-GRSのみ|

## コスト比較

* ストレージコスト： ホットアクセス層 ＞ クールアクセス層 ＞ コールドアクセス層 ＞ アーカイブアクセス層
* アクセスコスト　： アーカイブアクセス層 ＞ コールドアクセス層 ＞ クールアクセス層 ＞ ホットアクセス層

## オンライン層とオフライン層

* オンライン層：ホットアクセス層、クールアクセス層、コールドアクセス層の3つが該当します。
* オフライン層：アーカイブアクセス層のみが該当します。

# 最後に
以上、簡単ですがアクセス層の違い、試験でポイントになりそうな個所をまとめました。
ところで、MS-Learnでも *Blob* 表記と *BLOB* 表記が混在しているの、何とかなりませんかね。

最後までお読みいただきありがとうございました。
【自分用メモ】入出力装置関係のショートカットキー

# 画面
参考：https://jp.ext.hp.com/techdevice/windows10sc/54/
## デスクトップ
### 仮想デスクトップの追加
[Windows］＋［Ctrl］＋［D］キー
### デスクトップの切り替え
[Windows］＋［Ctrl］＋［→］ or ［←］キー
### 仮想デスクトップの削除
[Windows］＋［Ctrl］＋［F4］キー

# キーボード
## キーボードのファンクションキーの固定
[Fn] + [Esc]
参考；https://ruby-pc.com/keybord-1/
Flutter minSdkVersion指定によるエラー解決法

# はじめに
初投稿です。備忘録的なノリで投稿しますが、指摘などございましたら遠慮なく頂けると嬉しいです。

先ずは軽く僕の自己紹介から
・新卒2年目の24歳男性
・新卒後の研修終了後の初案件はjava　←　ついて行けずメンタル終わる()
・今年からflutterのエンジニア
・辛い物&パクチー以外の食べ物が好き
まだまだありますが一旦このくらいにしておきます。

# 本題
プライベートでFlutterの勉強をしていたところ、Firebaseを使う簡単なサンプルを実行しようとした際に以下のようなエラーが出て来ました。
uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:cloud_firestore] 
(中略)
merged_manifest\debug\AndroidManifest.xml as the library might be using APIs not available in 16
	Suggestion: use a compatible library with a minSdk of at most 16,
		or increase this project's minSdk version to at least 19,
		or use tools:overrideLibrary="io.flutter.plugins.firebase.firestore" to force usage (may lead to runtime failures)
(以下略)

どうやらcloud_firestoreのプラグインがAndroid SDKのバージョン19以上を要求しているのに、僕のプロジェクトがバージョン16を指定しているために発生していたみたいです。

# 解決方法
C:\Users\ユーザ名\AndroidStudioProjects\プロジェクト名\android\app\build.gradle
のファイルに以下の文言を追加する事で解決した。

```dart:build.gradle
android {
  defaultConfig {
    minSdkVersion 19 //この1行を追加
  }
}'
```

これでandroidのminSdkVersion指定によるエラーは解決したのですが、今度はまた別のエラーが出て来たので次回解説します。
44ネットワークの補足

### ネットワーク管理
ネットワーク管理は、ネットワークを効率よく、円滑かつ安全に日々利用することができるように行われる。ネットワーク管理者、稼働しているネットワークの構成情報管理し、障害時や業務システムの運用規模の拡大などによるユーザの要求に常に対応しなければならない。
#### ネットワーク運用管理
　ネットワーク運用管理では、設置されているネットワーク機械を個々に管理し、障害時における障害の切り分けや障害原因を特定し、復旧措置を行ったあと、今後の障害にの萎えて障害内容を記録しておく。
#### ネットワークコマンド
ネットワーク管理を行う為にOSのコマンド
PING
ipconfig
arp
netstat
nslookup
dig
route![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3293109/fe5c060a-2c4c-6050-6ddc-36d59940be8e.png)
#### ネットワーク管理ツール
SNMP（Simple　network　Management　Protocol）
ネットワークの構成・性能・障害管理のために使われる標準的なプロトコル。それを使用するネットワーク管理ツールが多数市販されている。
SNMPでは、SNMPマネージャーがSNMPエージェント（ルータ、スイッチ、サーバなど）にたいして管理情報の取得・要求・設定／変更を行い、SNMPエージェントがその要求を応答することを、基本操作を繰り返すことによってネットワーク機械の管理を実現する。
M1 MacでC/C++言語の環境構築，BoostとEigenライブラリを使えるようにした

## <font color="red">**はじめに**</font>
先日，初めてM1 MacでC/C++言語の環境構築を行いました．
Homebrewを用いてgccとg++のコンパイラを機能させる所までは，以下の参考文献のお陰様で，問題なく進むことが出来ました．

- [【備忘録】M1 MacでGCC環境を構築する](https://qiita.com/Kaprekar2/items/2c20c3a6da18d9723497)
- [【M1 Mac】パスの設定をしたのにgcc/g++コマンドでまだClangが呼び出される or gcc/g++が実行されないときの対処法](https://nishikiout.hatenablog.com/entry/2022/11/29/235406)


次にHomebrewを用いてboostとeigenをインストールしました．
```
$ brew install ライブラリ名
```
ここで，これらサードパーティ・ライブラリを永続的にインクルード(include)，認識させるために多少の試行錯誤がありました．
日本語，英語両者で出来る限りの検索をしましたが，情報が少なく，見つけても古い情報で良く分からなかったです．自分の知識が足りなかった点もあると思います．

そこで上手く行った例をここに記録しておきたいと思います．

## <font color="red">**永続的にパスを追加する**</font>
.zshrcファイルに以下の一文を追加するだけで永続的にライブラリを認識してくれました．
```
export CPATH=/opt/homebrew/include/
```
設定の再読み込みは以下のコマンドで行います．
```
$ source ~/.zshrc
```
これで毎回コンパイルオプションにライブラリのパスを指定しなくても，ライブラリを認識してくれるようになります．

因みに
Boostライブラリのインストール場所は
```/opt/homebrew/Cellar/boost/1.82.0_1/include/```
Eigenライブラリのインストール場所は
```/opt/homebrew/Cellar/eigen/3.4.0_1/include/eigen3/```
にありました．

## テストファイル
動作確認のために以下のようなテストファイルtest.cppを用意しました．
```C++:test.cpp
#include <stdio.h>
#include <iostream>
#include <boost/version.hpp>
#include <eigen3/Eigen/Core>

int main() {
    printf("Hello World\n");
    
    std::cout << "boostバージョン:" << BOOST_VERSION << std::endl;
    std::cout << "boostライブラリバージョン:" << BOOST_LIB_VERSION << std::endl;
    return 0;
}
```
このtest.cppをコンパイル```$ g++ test.cpp``` ＆ 実行```$ ./a.out```すると，以下のように出力されました．
```C:実行結果
Hello World
boostバージョン:108200
boostライブラリバージョン:1_82
```

### Eigenライブラリに関して注意
上記のテストファイルではEigenライブラリを```#include <eigen3/Eigen/Core>```で認識させてますが，多くの場合，```#include <Eigen/Core>```で用いると思います．
このように記載された場合でも問題なく動作させる方法の1つとして，シンボリックリンクが挙げられます．
```/opt/homebrew/Cellar/eigen/3.4.0_1/include/eigen3/```と```/opt/homebrew/Cellar/eigen/3.4.0_1/include/eigen3/Eigen```をリンクさせます．
概要や具体的な方法は以下の記事や他の記事を参考にしてみてください．

- [Macでシンボリックリンクを相対パスで作成する方法【Linux/Mac】](https://m-kenomemo.com/symbolic-link/)
【Python】保存版 仮想環境作成（venv）・Jupyter Notebook 導入方法

# この記事の内容

**venv** でPython仮想環境を作成する方法と **Jupyter Notebook** の導入方法をまとめました。

- 仮想環境の作成・起動・停止
- Jupyter Notebook の導入

## 仮想環境の作成・起動・停止

- Pythonのバージョン確認

`python --version` もしくは `python -V`

```terminal
% python --version
Python 3.11.5
```

<br>

- 仮想環境の作成
現環境のバージョンで作成 → `python -m venv 作成する仮想環境のパス`
指定したバージョンで作成 → `python3.xx -m venv 作成する仮想環境のパス`

ディレクトリ「**~/.venv**」 の直下に「**myenv**」という名前の仮想環境（バージョン 3.12）を作成する場合
```terminal
% python3.12 -m venv ~/.venv/myenv
```

<br>

- 仮想環境の起動（Mac・Linux）
`source 仮想環境のパス/bin/activate`

```terminal
% source ~/.venv/myenv/bin/activate
```

<br>

- 仮想環境の起動（Windwos）
`仮想環境のパス/Scripts/Activate.ps1`

```terminal
% ~/.venv/myenv/Scripts/Activate.ps1
```

<br>

- 仮想環境の停止（Mac・Linux・Windows）
`deactivate`
```
% (myenv) deactivate
```






## Jupyter Notebook の導入

- pipのバージョン確認
`pip --version` もしくは `pip -V`
```
% (myenv) pip 23.2.1
```

<br>

- pipのバージョンアップ
`python -m pip install --upgrade pip`
```
% (myenv) python -m pip install --upgrade pip
```

<br>

- [Jupyterのインストール](https://jupyter.org/install)
仮想環境起動中に `pip install notebook==6.4.12`

```terminal
% (myenv) pip install notebook
```

:::note alert
Pythonのバージョンと互換性が無いと、Jupyter Notebook を起動してもPythonコードを実行できない場合があります。その場合は互換性のあるバージョンを指定してインストールします。
例：% (myenv) pip install notebook==6.4.12
:::
<br>

- Jupyter Notebook の起動
仮想環境起動中に `jupyter notebook`

```terminal
% (myenv) jupyter notebook
```

![jupyternotebook.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3469687/8a71e36e-efc3-7d8a-cc76-b7629f06bfcb.jpeg)

・Jupyter にカーネルを追加（カーネル名：myenv）

:::note info
下記のを登録を行うと、別の仮想環境でJupyter Notebook を起動しても指定した仮想環境を使用できます
:::

```terminal
(myenv)% ipython kernel install --user --name=myenv
```
<br>

・仮想環境を削除後に不要になったカーネルを削除（カーネル名：myenv）
```terminal
(myenv)% jupyter kernelspec uninstall myenv
```
DockerでMinioのコンテナを立ててみる

## 概要

- DockerにてMinioのコンテナを立てる方法を簡単にまとめる。

## 前提

- 筆者の環境はすでにMinio以外の開発用コンテナを立てたことがあり、途中からMinioのコンテナを追加を行う。
- docker-composer.ymlなどは

## 方法

- Dockerhubにログインする。
- 下記にアクセスする。

https://hub.docker.com/r/minio/minio/tags

- latest以外のタグを確認する。ブラウザのウインドウを開いたままにしてあとからタグ名をコピーできるようにしておく。

    ![minio_minio_Tags.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/6b7cefcf-5145-f2b4-9680-f04fec685343.png)

- 下記のコマンドを実行してディレクトリを作成する。（この辺は筆者の環境に依存しているため、適宜ご自身の環境に合わせていただきたい。）

    ```shell
    mkdir .docker/minio
    ```

- 下記コマンドを実行して作成したディレクトリにDockerfileを作成して開く。

    ```shell
    vi .docker/minio/Dockerfile
    ```

- 開いたDockerfileを下記のように記載する。（FROMのあとはDockerhubのminioのタグ名を指定する。）curlのコマンドは参考文献先のMinioのドキュメントを参考にした。

    ```.docker/minio/Dockerfile
    FROM minio/minio:RELEASE.2023-08-29T23-07-35Z.fips
    ```

- docker-compose.ymlと同じ階層に.envファイルを定義し下記の様に記載する。

    ```.env
    # minio
    MINIO_API_HOST_PORT=9000
    MINIO_API_CONTAINER_PORT=9000
    MINIO_CONSOLE_HOST_PORT=9001
    MINIO_CONSOLE_CONTAINER_PORT=9001
    MINIO_ROOT_USER=root_user
    MINIO_ROOT_PASSWORD=root_user_password
    MINIO_BUCKET_NAME=任意のバケット名
    MINIO_SERVER_ADDRESS=http://localhost:9000
    ```

- docker-composer.ymlのserviceに下記の内容を追記する。

    ```docker-compose.yml
    minio:
      build: ./.docker/minio
      volumes:
        - "./minio/data:/data:delegated"
      ports:
        - ${MINIO_API_HOST_PORT}:${MINIO_API_CONTAINER_PORT}
        - ${MINIO_CONSOLE_HOST_PORT}:${MINIO_CONSOLE_CONTAINER_PORT}
      environment:
        - MINIO_ROOT_USER=${MINIO_ROOT_USER}
        - MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
        - MINIO_SERVER_ADDRESS=${MINIO_SERVER_ADDRESS}
        - MINIO_BUCKET_NAME=${MINIO_BUCKET_NAME}
      command: server /data --console-address :${MINIO_CONSOLE_HOST_PORT}
    createbuckets:
      image: minio/mc
      depends_on:
        - minio
      environment:
        - MINIO_API_CONTAINER_PORT=${MINIO_API_CONTAINER_PORT}
        - MINIO_ROOT_USER=${MINIO_ROOT_USER}
        - MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
        - MINIO_SERVER_ADDRESS=${MINIO_SERVER_ADDRESS}
        - MINIO_BUCKET_NAME=${MINIO_BUCKET_NAME}
      entrypoint: >
        /bin/sh -c "
        until (/usr/bin/mc config host add myminio http://minio:$$MINIO_API_CONTAINER_PORT $$MINIO_ROOT_USER $$MINIO_ROOT_PASSWORD) do echo '...waiting...' && sleep 1; done;
        /usr/bin/mc mb myminio/$$MINIO_BUCKET_NAME;
        /usr/bin/mc policy download myminio/$$MINIO_BUCKET_NAME;
        exit 0;
        "
    ```

- ここまで記載できたら下記コマンドを実行する。

    ```shell
    docker-compose build
    docker-compose up -d
    ```

- http://localhost:9001/loginにアクセスし、Username → `root_user`、Password → `root_user_password`とすることでログインできる。
- ログイン後、手動でバケットを作らずとも.envのMINIO_BUCKET_NAMEの値のバケットが作られていれば完了となる。

## 参考文献

https://min.io/docs/minio/linux/reference/minio-mc.html#install-mc

https://qiita.com/A-Kira/items/5bb9b3108ba12f533e49

https://qiita.com/terukizm/items/6850aa316de425e3e3b4

https://github.com/minio/mc/issues/3599