OmniAICreator/Qiita-1.07M huggingface dataset:
【React】State(useState)の使い方

##   はじめに
こんにちは！プログラミング初学者です。
現在学習中のReactで重要な概念の**State**についてまとめてみました。

##  Stateとは
コンポーネント内で管理されるローカルなデータの状態を表します。
コンポーネントが持つ動的な情報や状態を保持するために使用されます。
**State**が変更されると、React は自動的にコンポーネントを再レンダリングして、新しい状態を反映します。
**State**は主にコンポーネント内で使用され、コンポーネントの見た目や動作を制御するために利用されます。

Webアプリを作る場合、様々な状態(state)を画面は持っています。
-  エラーがあるかどうか
-  ボタンを押せるか
-  ユーザーがモーダルウィンドウを開いたか閉じたかどうか
-  ログインしているかどうか、またはログインフォームが表示されているかどうか

このような状態は全て**State**で管理し、イベント実行時等に更新処理を行うことでアプリケーションを実行していきます。

##  useState
React Hooksと総称される機能郡の中の一つのこと。
<dl>
    <dt>宣言</dt>
        <dd>React関数コンポーネント内で状態を管理するために使用されます。
useStateを使用して状態を宣言すると、React コンポーネント内で変更可能な状態を管理するための変数が作成されます。この変数には、現在の状態の値が含まれます。</dd>
    <dt>初期化</dt>
<dd>useStateが返す第二の要素は、状態を更新するための関数です。この関数を呼び出すことで、状態の値を変更することができます。</dd>
    <dt>更新</dt>
<dd>状態の更新は非同期的であり、React は自動的にコンポーネントを再レンダリングして、更新された状態を画面に反映します。</dd>
</dl>

###  **useState**の基本的な使用例
```javascript
import React, { useState } from 'react';

function ExampleComponent() {
  // 状態の宣言と初期化
  const [count, setCount] = useState(0);

  // ボタンがクリックされたときのハンドラー関数
  const handleClick = () => {
    // 状態の更新
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}

export default ExampleComponent;
```


↓この場合、`count`が状態を持った変数、`setCount`がそれを更新する関数となります。
```javascript
const [count, setCount] = useState(0);
```
名称は自由につけることができますが、暗黙のルールで変数が`count`であれば更新関数名は`setCount`のようにします。

##  おわりに
useStateについて理解しきれていなかったので、調べながらまとめてみましたが、改めてコードの意味を理解することができ良い学習になりました。
ABC344備忘録【C~E】

## はじめに
[ABC344](https://atcoder.jp/contests/abc344)です。基本的に書いたコードをほとんどそのまま張り付けていますが、考えたことなども書いていますので是非見て行ってください。

## C - A+B+C
### 問題
https://atcoder.jp/contests/abc344/tasks/abc344_c

### 考えたこと
注目するべき制約は、
``` math
\begin{align}
1 \leq N, M, L \leq 100 ,　 1 \leq Q \leq 2 \times 10^5
\end{align}
``` 
です。これにより、$A,B,C$を3重ループしても計算量は$10^6$程度なので問題ありません。
ただし、リストYでの x in Y の計算量は$O(len(Y))$ となり、リストに結果を格納してしまうと厳しいです。そこで、setなどに結果を格納することでこの問題を解くことができます。

### ACコード
```Python:C.py
n = int(input())
A = list(map(int, input().split()))
m = int(input())
B = list(map(int, input().split()))
l = int(input())
C = list(map(int, input().split()))
q = int(input())
X = list(map(int, input().split()))

sum_ = set()
for a in A:
    for b in B:
        for c in C:
            sum_.add(a + b + c)

for i in range(q):
    if X[i] in sum_:
        print("Yes")
    else:
        print("No")
```


## D - String Bags
### 問題
https://atcoder.jp/contests/abc344/tasks/abc344_d

### 考えたこと
$dp$です。各要素$dp[i][j]$を袋$i$までで$j$個の文字列まで一致させるための最小金額として考えるとうまくいきます。

実装時は2次元リストを思い浮かべて、どのように遷移していくかを考えていったため、画像を張り付けておきます。
図１はDP遷移式がどのように適用されていくのかを表しています。図２は入力例１の処理の流れを表しており、赤枠が答えとなります。

<img width=10%><img width=80% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631672/2d6b5254-169d-25e0-5fb0-0dda82be7537.png">

![dp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631672/b84fd261-b85d-f2a9-6f26-b1aeed5e61b4.png)



### ACコード
``` Python:D.py
t = input()
n = int(input())
len_t = len(t)
# 最小値を求めるので、float("inf")で初期化
dp = [[float("inf") for _ in range(len_t + 1)] for _ in range(n + 1)]

dp[0][0] = 0
for i in range(n):
    _, *S = input().split()
    for j in range(len_t + 1):
        # minを取らないと、遷移先を上書きしてしまう
        dp[i + 1][j] = min(dp[i + 1][j], dp[i][j])
        for s in S:
            if j + len(s) > len_t or t[j : j + len(s)] != s:
                continue
            dp[i + 1][j + len(s)] = min(dp[i + 1][j + len(s)], dp[i][j] + 1)

print(dp[-1][-1] if dp[-1][-1] != float("inf") else -1)
```

## E - Insert or Erase
### 問題
https://atcoder.jp/contests/abc344/tasks/abc344_e

### 考えたこと
最初はグラフが適用できそうだと思い実装を進めていましたが、無向グラフは挿入部分で、有向グラフは削除部分で躓いてうまく実装できませんでした。

最終的には、公式解説と同じように前後の数字を持っておくように実装を進めることができました。辞書形式で格納していったので実装を楽にするため、先頭に-float("inf")、最後尾にfloat("inf")を導入しました。

図３は入力例１の2143を辞書形式で表したものです。

![辞書で表現.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631672/04ec3db6-5bf5-e88b-8198-af77b4a1e032.png)

### ACコード
``` Python:E.py
n = int(input())
a = list(map(int, input().split()))
a = [-float("inf")] + a + [float("inf")]
n += 2  # 両端分を加算

# 実装を楽にするため、要素が2つのリストを持つように初期化
d = {a[i]: [-1, -1] for i in range(n)}
for i in range(n - 1):
    d[a[i]][1] = a[i + 1]
    d[a[i + 1]][0] = a[i]

q = int(input())
for _ in range(q):
    query = list(map(int, input().split()))
    if query[0] == 1:
        _, x, y = query
        d[y] = [x, d[x][1]]
        d[d[x][1]][0] = y
        d[x][1] = y
    else:
        _, x = query
        d[d[x][0]][1] = d[x][1]
        d[d[x][1]][0] = d[x][0]
        del d[x]

ans = [d[-float("inf")][1]]
while True:
    if d[ans[-1]][1] == float("inf"):
        break
    ans.append(d[ans[-1]][1])

print(*ans)
```
RaspberryPiからGmailの送信サーバーを使う

### Googleアカウントのアプリパスワードを設定
[Googleアカウント][セキュリティ][Googleにログインする方法][２段階認証プロセス][アプリパスワード]
アプリ名「raspberrypi」パスワード「1234567890123456」
参考 https://support.google.com/mail/answer/185833?hl=ja
## Pythonプログラムで添付ファイルを送信
### EmailMessageを使用
```
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import smtplib
from email.message import EmailMessage

def main():
	args = sys.argv
	filepath = args[1]
	basename = os.path.basename(filepath)
	msg = EmailMessage()
	msg['From'] = 'sss@gmail.com'
	msg['To'] = 'ccc@gmail.com'
	msg['Subject'] = basename

	msg.add_alternative('本文1.', subtype='plain')
	msg.add_alternative('<h1>本文2.</h1>', subtype='html')
	with open(filepath, 'rb') as f:
		msg.add_attachment(
			f.read(),
			maintype='application',
			subtype='csv',
			filename=basename
		)

	with smtplib.SMTP('smtp.gmail.com', '587') as smtp:
		smtp.starttls()
		smtp.login('sss@gmail.com', '1234567890123456')
		smtp.send_message(msg)

if __name__ == '__main__':
	main()
```
参考
https://qiita.com/tarao1006/items/d257299e3d202fbf4460
https://qiita.com/curry__30/items/2e487168693b8248189a
### MIMETextおよびMIMEMultipartを使用（上記「EmailMessageを使用」を見ると非推奨）
参考 http://make.bcde.jp/python/gmail%E3%81%A7%E7%B0%A1%E5%8D%98%E3%81%AB%E3%83%A1%E3%83%BC%E3%83%AB%E9%80%81%E4%BF%A1/
## 単純なメール送信
### プログラムをインストール
```
$ sudo apt -y install ssmtp mailutils
```
### メール送信を設定
```
$ sudo vi /etc/ssmtp/ssmtp.conf
#root=postmaster
root=sss@gmail.com
#mailhub=mail
mailhub=smtp.gmail.com:587
#末尾に追加
AuthUser=sss@gmail.com
AuthPass=1234567890123456
UseSTARTTLS=YES
```
### メール送信を実行
```
$ date | mail -s test ccc@gmail.com
```
【Salesforce認定資格】Salesforce Certified AI Associateの受験結果

※本記事は2024年03月に受験した「Salesforce Certified AI Associate」の振り返りを記載しています。

## はじめに
TrailblazerDXで話題の中心になっていたことで感化され、AIに関する基本的な知識を試すために受験しました。

## 試験結果
結果は __「合格」__ でした。
試験に関しては時間は余裕があり、1回程度見直しを行いました。

| 受験料 | 試験時間 | 設問数 | 合格ライン | | 受験日 | 正答率 | 所要時間 |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| 10,000円 | 70分 | 40問 | 65% | | 2024/03/18 | 92.41% | 26分 |

内訳を見るとAIのデータに関する内容で数問の取りこぼしがあるため、復習が必要そうです。

| 試験内容 | 内訳 | 設問数 | | 正答率 |
| :-- | :-: | :-: | :-: | :-: |
| AIの基礎 | 17% | 6.8問 | | 85% |
| CRMでのAIの働き | 8% | 3.2問 | | 100% |
| AIの倫理上の考慮事項 | 39% | 15.6問 | | 100% |
| AIのデータ | 36% | 14.4問 | | 86% |

![Salesforce_Certified_AI_Associate_01_テスト結果詳細.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3285411/a3ddb941-70a3-d58f-d632-096aee4ee84a.png)

## 学習方法
学習時間は10時間程度で、AIに関する一般論からSalesforceの特有の考え方まで目を通して学習を進めました。
AIの一般論に関しては[CRDSの特集](https://www.jst.go.jp/crds/column/ai/index.html)と[総務省の特集](https://www.soumu.go.jp/johotsusintokei/whitepaper/ja/h28/html/nc142120.html)を中心にして、第3世代（第3.5世代）のAIと以前の世代のAIの成り立ちの違いを説明できるようにしておきました。
Salesforceの特有の考え方については下記のTrailmixが良い学習コンテンツになると思います。

https://trailhead.salesforce.com/users/strailhead/trailmixes/prepare-for-your-salesforce-ai-associate-credential

特に、 __信頼済みAIの原則__ についてまとめられた下記のSalesforce Blogについては集中して頭に入れるようにしました。

https://blog.salesforceairesearch.com/meet-salesforces-trusted-ai-principles/

## 学習の意識付け
AIに関する知識が多く問われるため、Salesforceの実機に触れて覚えるよりもドキュメントを読み込んで学習するような形になります。
暗記が苦手なため、意味合いは雰囲気やイメージを作って覚えるようにし、言葉はまとめて覚えるようにしました。
※信頼済みAIの原則は頭文字を取ると「ARTIE」となるので、「信頼済みAIの原則 = アーサー王」で覚えていました。
CH552P を使いたい

# はじめに

以前、↓こちらの記事で **CH552**マイコンを紹介した。そのときは、ピッチ変換基板に実装済みの **CH552P**を使用した。

https://qiita.com/nak435/items/da2b81e31852774f710d

**CH552**は、4種類のパッケージ形状がラインナップされており、用途により使い分けができる。

<img width="300" alt="ch552_package.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/4f681cfd-4fd6-cd28-ab40-147d9c105131.png" /> CH552 Datasheetから引用


|諸元 ＼ チップ	|CH552T	|CH552G	|CH552P	|CH552E|
|:-|-:|-:|-:|-:|
|パッケージ	|TSSOP-20	|SOP-16	|QFN-16	|MSOP-10|
|ボディサイズ ($mm$)<br>（リード線を含まず）|6.5×4.4	|10.0×3.9	|3.0×3.0	|3.0×3.0|
|面積 ($mm^2$)	|28.6	|39.0	|9.0	|9.0|
|ピン数(リード数)	|20	|16	|16	|10|
|リードピッチ	|0.65	|1.27	|0.5	|0.5|
|ピン数当たりの面積	|1.43	|2.44	|<b><i>0.56</i></b>	|0.9|

この中で、**CH552P**は、16ピンでありながらピン数当たりの面積が最小のパッケージである。

このチップを <i>素</i> で使いたいと思い、以下の基板を設計した。

# プリント基板

PCのUSB-Aポートに直接挿す形状とした。部品はすべて表面に実装。

表面に、**CH552P**、パスコン、DFUのプルアップ抵抗とパッド（ショートさせるとDFUモード）、および RGB-LEDを配置し、裏面には、電源系とシリアルポートのパッドを配置。

|サイズ| W 29.0mm x H 12.0mm|
|:-:|-|
|表|<img width="300" alt="ch552p_front.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/bd429d32-03f5-c49d-d6b3-1c0d4c30d3e2.png" />|
|裏|<img width="300" alt="ch552p_back.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/1ea1b055-ff6a-99e6-c82e-6dbf76838918.png" />|
|R1<br>C1 / C2<br>RGB<br>（nak435|10KΩ<br>0.1μF ×2<br>WS2812C-2020（P1.0に接続、オプション）<br>静電容量検出パッド、P1.1に接続）|


比較のために1円硬貨を並べてみた。それにしても、0.5ミリピッチのハンダ付は毎回シビレる。

<img width="300" alt="IMG_3102.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/95a63ef6-8c83-fd4a-56e0-e649cb5d8693.png" />


なお、**CH552P**は、アリエクにある [WCHオフィシャルショップ](https://ja.aliexpress.com/item/1005005401613509.html) にて、20個セットで 1,953円（送料無料）で購入した。1個当たり98円。


# 比べてみた

この手の基板として有名な [**Digispark ATtiny85**](https://www.google.com/search?q=Digispark+ATtiny85) と比べると、部品点数に圧倒的な差がある。今回は「VBUSのフューズと電源レギュレータを実装していない」とはいえ、**CH552**がネイティブにUSBをサポートしていることが主な要因。_さすが **USBマイコン**と唱うだけのメリットはある。_

<img width="280" alt="digispark.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/f54e4aa2-38b9-1329-793b-8e7de4f60675.png" />


# 用途

まずは、スリープブロッカー（マウスジグラー）のコードを書いて使うことにした。また、**CH552**が持つ静電容量検出機能を使って、指を近付けている間、RGB をランダムに光らせるようにしてみた。
（_静電容量検出の閾値の設定は微妙。これについては 別記事にする。_）

<img width="300" alt="IMG_3108-2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/b6dc099f-8b19-66b7-eda2-5929d98702b6.gif" />



# おわりに

この基板の素材は、一般的なFR-4で、厚みが 1.6ミリである。
一方、USB-Aは、USB規格にて 2.2ミリとなっていて、この基板は若干薄い。このため、接触不良を起こす場合があるので、そこの工夫が必要。

_チョコレートの空き箱を切って挟むとちょうどよい。もしくは、USBの4本のパッドにハンダを流し込み厚みを持たせるもよし。_

基板はパネライズして全部で100枚ほど作った。まだ大量に余っている（笑）。

<img width="160" alt="pa.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/231b0fae-dbad-2125-6648-df04964f0bb0.png" />



### 以上
IAM Identity Centerで作ったユーザーにAWS CLIからアクセスする方法

# 手順

- セッションを立ち上げる
``` sh
$ aws configure sso
```
aws access portal(IAM Identity Centerで作ったユーザーのログイン画面)に行けば、実行後の入力すべき値が確認可能。それに従って、入力していく。

- 認証が終われば、プロファイル名を登録しておく

```sh
CLI profile name [{プロファイル名}]:
```
出てきたプロファイル名を登録する。

```sh
export AWS_PROFILE={プロファイル名}
```
これだけ。あとはコマンド叩く。

# IAM Identity Centerの良さ

IAM Identity Centerで作ったIAMユーザーにcliからアクセスすると、そのタイミングでアクセスキーが発行される。「セッションが切れる or 一定の時間が経つ」とそのアクセスキーは自動で廃棄される。<br>
普通のIAMで作ったユーザーにアクセスするのと違い、超短期的なアクセスキーの運用により、セキュリティを高められる。
文字種を指定したパスワードの生成@Ubuntu

# はじめに

WSL（Ubuntu）を使ってサーバーのパスワードを生成しようと思い、以前に書いた「[文字種を指定したパスワードの生成](https://qiita.com/nkojima/items/3c5b83103b5e2274d6b1)」という記事に沿って`mkpasswd`コマンドを実行しようとしたところ、なんとUbuntuでは`mkpasswd`コマンドが使えないことが判明しました。

そこで`mkpasswd`コマンドの代替策を調べたので、その結果を記事としてまとめてみました。

# pwgenのインストール

* Ubuntuでは`mkpasswd`の代わりに`pwgen`というパッケージがあるため、これをインストールします。

```bash:
$ sudo apt install pwgen
```

# pwgenの使い方

* `pwgen [ OPTION ] [ pw_length ] [ num_pw ]`という構文になっており、引数を何も指定しない場合は英数字から成る8文字のパスワードが160個も生成されます。

```bash:
$ pwgen
teu3Osh8 Cu9thied aiph2Oey ve8aeL4E Kaifi6ei aib5Iv6s Tax0kooz feePhea7
ii4Iefae yo0Shuqu ieth0aiW taeP4eix Iex0phah quie4Coo Nijues2Y Erahdoh8
Aixipai7 Bieth9Ie fieW7foo rohqu8La Eishoox6 eezo2vuH OLu8Lie7 yiz1tohS
eeGee6Ai jie2Iegh aiZeep5d rahSh1ah sho4UPie UuP0sei3 heCei2ee Aot1kooc
Yi8jahd0 nahGhoe3 ioDa3ohv quu3Zaiw zik1Zeze laing4Oh Gola7eek eethu3Eu
ipha1Cut Ohsoo1su Moo0Ohng eim7Geiz Eesi9oof Ech8awe9 Thah1aer ut9Yeiph
loh1uT7I Ohmolud0 Cie3Ue7J MeeNg4po maeT4OhD Quad3ahs feecay8I ruaMoef9
Chei9foh the9IeFa zu0Quu9n eixahm3J Aexae3jo Geiquee9 ahFaer9t phaig8Zo
obe7ko7E kohRash5 vae3aeKa Oun2aexe tae2Ceoh Oseuh8ve Ajevo4de Jah9vo7U
Acoxaes6 Eireib5h eeyia4Oh eejoh1aM aebi3Zoh Ac8yees4 na6Angie Ooc1aagi
Phael6je lohG7Tha poo3Ig1v ieV1meif Veim5Tee een6Aiph ai4Queic Eev4xooh
MooCu8Ko aed5OoSo Meebie6j eima0aeR uag9Seu2 wie3OhZe eu9Ath8p eZ7zeero
noh1Chie aifew0Ah chohs2Ve AiraQu2y ahneiV1u Ce6thai9 iS3Shae5 MichaiT5
ahpahD5U thah1Kai anieTh2u ooNae7oh Ahj0uu7o Eingoh9d aech8Pho Thu6Vie1
re4ooHit jaaM4iex caeng8Ii shiaVoo0 cho5AiJi seya7ieR Iesh0aht ahm7Chie
eiyai1Ga kieJ0sie oshaLii9 Peemai3l Zongoox1 ou8Caang OhF2eing Nothae6E
Eix6bieD Hoo0Iero LooS9ohN aiqu1Woc zuC1ooW0 ein1Angi vaX1ahba cooXae4i
xaPh7EiZ choo6Iec haer5Wie OhSeeSh8 oe5SheiF ooXe5paa roo4Ebu6 poz4See7
kaiTi9uc eemeePh9 Poshi2fi johnah4U OoSh2EiX seedauK5 Pu8aengi oobae7Gu
nie1phoW ekie7Aic ahZ1Wihi Aere7rae EejeiS2f zuu0Kee2 gaila5Hu aeK4powu
```

* 12文字のパスワードを3つ生成したい時は、以下のコマンドを実行します。

```bash:
$ pwgen 12 3
eiJ5Shaekaib iTae4quaiphu hie3eos9aeGi
```


# pwgenのオプション

* オプションを指定することで、「パスワードに記号を含める」などの基本的な設定に加えて、「間違われやすい文字を除去する」という高度な設定も可能です。
* `-B`を使うとパスワードの勘違い（打ち間違い）を防げると思いますが、使える文字の数が減ってパスワードの強度がちょっと落ちてしまいそうな気もします。
  * 英数字に加えて記号も使っていれば、あとはパスワードが十分な長さであれば問題ないと思いますが...

|UNIXスタイル|GNUスタイル|意味|
|---|---|---|
|-0|--no-numerals|数値を含まないパスワードを生成する。|
|-1||1行に1つのパスワードを表示する。|
|-A|--no-capitalize|大文字を含まないパスワードを生成する。|
|-B|--ambiguous|「l」と「1」、「0」や「O」など、印刷時にユーザーが混乱する可能性のある文字を使わない。|
|-c|--capitalize|パスワードに大文字を少なくとも1文字含ませる。|
|-N|--num-passwords=num|num個のパスワードを生成する。|
|-n|--numerals|パスワードに数字を少なくとも1文字含ませる。|
|-r chars|--remove-chars=chars|指定された文字をパスワードに使わない。|
|-s|--secure|完全にランダムで覚えにくいパスワードを生成する。|
|-v|--no-vowels|母音や母音と間違われる可能性のある数字を含まない。※具体的に何を指しているのかは不明|
|-y|--symbols|パスワードに記号を少なくとも1文字含ませる。|

# 参考URL

* [文字種を指定したパスワードの生成](https://qiita.com/nkojima/items/3c5b83103b5e2274d6b1)
* [mkpasswdみたいなパスワード作成するコマンドをubuntuとかOSXにインストールする](https://cameong.hatenablog.com/entry/20120322/1332428213)
GitHubに大量の悪質リポジトリが発生中！！

GitHub上で、マルウェアを仕込んだリポジトリを本物のものと偽って広める手法が広まっており、サイバーセキュリティ企業が10万を超える感染したリポジトリを発見したとのことです。

&nbsp;

この攻撃は現在も続いていて、無知な開発者がこれらのリポジトリを使用すると、マルウェアに感染しパスワードなどの情報が漏洩する可能性があります。

&nbsp;


個人開発をする機会も増えてきて、GitHubなどからリポジトリを利用することも多いと思います。いつも使っているからこそ「GitHubなら大丈夫だろう。」と思うこともあるかもしれません。

&nbsp;

ですが、今そういった情報リテラシーの甘い人をターゲットにした悪質なリポジトリがかなりの数見つかっているそうなので、改めて気を引き締める必要がありそうです。

&nbsp;

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958142/2f1cd710-f93f-ec32-10d4-f08007902f0b.png)

&nbsp;

フォークされた不正なリポジトリはGitHubが消去しているそうですが、自動検出で見落とされることもあり、手動でアップ済みのリポジトリは消去されずに残るようです。

&nbsp;

さらに、何も知らないユーザーが無意識にマルウェアの含まれている悪質なリポジトリをフォークしてしまい、拡散させているケースも少なくないそうです。本当に恐ろしい。。

&nbsp;

## 用語解説

### GitHub
GitHubは、プログラムのソースコードをオンラインで共有・管理することのできるサービスです。利用者は国内だけでなく世界中のプログラマーによって使われています。

### リポジトリ
リポジトリは、GitHubの最も基本的な要素の一つで、プログラミングコード、ファイル、各ファイルのリビジョンの履歴を格納することのできる場所のことです。
リポジトリは、複数名のコラボレーターが参加できます。リポジトリの公開やプライベート設定など、使う人のニーズに合わせることが出来ます。

### フォーク
フォークとは、GitHub上でほかのユーザーが所有しているリポジトリを、自アカウントのリポジトリへコピーすることです。
フォークを使うことで、元となる親リポジトリに英起用を及ぼすことなく、自リポジトリでプログラム等を改変、編集することが出来ます。
Linuxのディストリビューションとは？？

## はじめに
Linuxを皆さんは聞いたことがあるでしょうか？
エンジニアの方なら一度は聞いたことがあるでしょう。
しかし、Linuxについて少し調べるとUbuntuやCentOSというものを使用しているのを見かけます。
最初にこれをみた時に、これらもOSなの？ディストリビューションて何？となったので簡単にまとめてみました。

## Linux
まずは、Linuxですね。一般的には、WindowsやMacOSと同様にOSの一つとして知られています。

## Linuxカーネルとは
調べるとカーネルって目にしますよね。これはなんでしょうか？
これは、OSの中心部分でハードウェアとソフトウェアの間を取り持つ役割があります。
実はLinuxとは、狭義ではこのLinuxカーネルのことを指しています。

## Linuxディストリビューションとは？
Linuxカーネルはあくまで中心部なのでそれ単体では動けません。
そこで、様々なソフトウェアやライブラリを組み合わせてOSとして動作するようにしたのがLinuxディストリビューションです。

つまり、Linuxディストリビューションには共通でLinuxカーネルが含まれており、目的によって周りのソフトウェアやライブラリを組み込んで生まれたのがUbuntuやCentOSということです。

## 最後に
Linuxカーネルやディストリビューションのイメージがなんとなくついたでしょうか？
世の中には様々なディストリビューションが存在しているので、ぜひ一度何がどんな目的で利用されるのか調べてみてください！！
Makefileを使って、コードを書かずとも各種のPDFトリミング作業 （Windows環境）

上位システムからPDFで伝票をもらうのですが、その全ページについて指定部分でトリミングを行い、再度PDFで保存したいときに。

Windows環境でのメモ。Python pillow でコードを書かずともMakefileのみで、やればできるもんです。

# 事前準備
以下のツールをインストールしておきます。

* ImageMagick - https://imagemagick.org/script/download.php
* xpdftools (pdf2pngが含まれる) - https://qiita.com/wutai00/items/28b8930a617034687909　
* pdftk - https://pdftk.en.softonic.com/

Makefileでは、以下のような定数を定義するとします。

```
PDF2PNG		= d:\opt\xpdftools\bin32\pdftopng.exe
IMGMGK		= d:\opt\magick\convert.exe
IMGMTG		= d:\opt\magick\montage.exe
PDFTK 		=  d:\opt\pdftk\bin\pdftk.exe
```

# やってみる
## PDFファイルを画像にする

> $(PDF2PNG)   -gray -r 600  source.pdf output.png

* -r 600 は出力させたい解像度。数字を大きくするほど繊細で大きな画像になります。

## 出力した画像から、欲しい範囲をトリミング

> $(IMGMGK) -crop 1000x520+320+610 -quality 80 input.png clip__.bmp

* x=320, y=610 を始点として、(1000x520)の範囲をトリミング

## 画像の周囲にマージン枠を付ける（キャンバスを拡大）

> $(IMGMGK) -gravity center -background white -extent 1400x700 input.bmp output.bmp

* gravityはセンタリングポジションを指定します。centerだと上下左右センターに配置されます。
* extent は、最終的に出力を希望するビットマップサイズです。

## 画像をPDFに戻す

> $(IMGMGK) -quality 80  source.bmp output.pdf

* pngファイルをソースにpdfを作ると、解像度関連で面倒なことになるので、bmpファイルを使うのが無難です。

## 作成した複数のPDFデータを連結
pdftkを呼びます。

> $(PDFTK) source*.pdf cat output merge.pdf

## これら全部を合体させると

以下のようなMakefileが出来上がります。

```makefile
TARGET_SRC 	=  $(wildcard input*.pdf)

all:
	make pdf2png
	make clip
	make clip2pdf
	make concatpdf

pdf2png: 
	$(PDF2PNG)   -gray -r 600  $(TARGET_SRC) input.png

clip:
	-del clip__*
	for %%I in (input*.png) do ( $(IMGMGK) -crop 1000x520+320+610 -quality 80 "%%~nI.png"  "clip__%%~nI.bmp" )

clip2pdf:
	for %%I in (clip__*.bmp) do ( $(IMGMGK) -gravity north -background white -extent 1400x700 -quality 90 "%%~nI.bmp" "%%~nI.pdf" )

concatpdf:
	$(PDFTK) clip__*.pdf cat output merge.pdf

```

# PDFで、1 枚の用紙に複数のページを印刷する（n-up）

古典的には psmulti, pdfjam のようなツールを使うのが定石ですが、Windowsではlibpaperを入れるのが面倒なので。以下の手順でやっちゃう。

* pdfを画像データに変換 (pdftopng) https://qiita.com/wutai00/items/28b8930a617034687909
* ImageMagickのmontage.exeを使い、画像を連結する https://imagemagick.org/Usage/montage

```makefile

nup:
	$(PDF2PNG) input.pdf clips.png
	$(IMGMTG) -tile 2x2 -geometry +100+100  clips*.png output.pdf 
```

縦に２ページ、横に２ページ分を割り付け、マージンは100px100pxで確保しています。


![Clipboard_04-02-2024_01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666068/bac8ce0f-a5e1-9021-58e1-618e1b88b4dd.jpeg)

# 複数ページのPDFを、1ページごと単一pdfファイルに解体する

> pdftk.exe input.pdf burst output out_%02d.pdf      

out_01.pdf, out_02.pdf, .... と連番で解体されます。

# あとがき

* コマンドラインでPDFデータをプリンタに送って印刷することもできる。　https://qiita.com/wutai00/items/22228a94524f432be276
npm -v すら実行できなかった際の対応

`npm -v` を実行すると以下のエラーが出た。
なんの操作をしてこのようになったのか記憶がない...

```bash
$ npm -v
ERROR: npm v10.2.5 is known not to run on Node.js v13.13.0.  This version of npm supports the following node versions: `^18.17.0 || >=20.5.0`. You can find the latest version at https://nodejs.org/.

ERROR:
/Users/IsamuUmetsu/.nodebrew/node/v13.13.0/lib/node_modules/npm/lib/utils/exit-handler.js:19
  const hasLoadedNpm = npm?.config.loaded
                           ^

SyntaxError: Unexpected token '.'
    at wrapSafe (internal/modules/cjs/loader.js:1039:16)
    at Module._compile (internal/modules/cjs/loader.js:1087:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
    at Module.load (internal/modules/cjs/loader.js:972:32)
    at Function.Module._load (internal/modules/cjs/loader.js:872:14)
    at Module.require (internal/modules/cjs/loader.js:1012:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at module.exports (/Users/IsamuUmetsu/.nodebrew/node/v13.13.0/lib/node_modules/npm/lib/cli-entry.js:15:23)
    at module.exports (/Users/IsamuUmetsu/.nodebrew/node/v13.13.0/lib/node_modules/npm/lib/es6/validate-engines.js:39:10)
    at module.exports (/Users/IsamuUmetsu/.nodebrew/node/v13.13.0/lib/node_modules/npm/lib/cli.js:4:31)
```

なぜか nvm がインストール済みで、 `nvm ls` で `v20.10.0` がインストール済みなので切り替えることに。
```bash
$ nvm ls
         v8.3.0
       v20.10.0
->       system
```

以下の流れで対応できたっぽい
```bash
$ nvm use v20.10.0
Your user’s .npmrc file (${HOME}/.npmrc)
has a `globalconfig` and/or a `prefix` setting, which are incompatible with nvm.
Run `nvm use --delete-prefix v20.10.0` to unset it.

$ node -v #正常に切り替えられたことを確認
v20.10.0

$ npm -v #できるようになった
10.2.3

$ nvm use --delete-prefix v20.10.0
Now using node v20.10.0 (npm v10.2.3)
```
Pythonで「文字クラスを使って色々な文字にマッチするパターンを記述する」の動作を確認してみた

# 概要

Pythonで「文字クラスを使って色々な文字にマッチするパターンを記述する」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/python/regex/index11.html

# 実装

以下のファイルを作成しました。
```sample.py
import re
pattern = re.compile(r'Sun')
print(bool(pattern.search('Today is Sunday')))
print(bool(pattern.search('The Sun rose')))
print(bool(pattern.search('Ham Sandwich')))

import re
pattern = re.compile(r'S..d')
print(bool(pattern.search('Today is Sunday')))
print(bool(pattern.search('The Sun rose')))
print(bool(pattern.search('Ham Sandwich')))

import re
pattern = re.compile(r'[sS]un')
print(bool(pattern.search('Today is Sunday')))
print(bool(pattern.search('The sun rose')))
print(bool(pattern.search('Ham Sandwich')))

import re
pattern = re.compile(r'199[^01234]')
print(bool(pattern.search('My birthday is 1998/03/12')))
print(bool(pattern.search('Graduated in 1994')))
print(bool(pattern.search('It opened in 1996')))

import re
pattern = re.compile(r'199[0-6]')
print(bool(pattern.search('My birthday is 1998/03/12')))
print(bool(pattern.search('Graduated in 1994')))
print(bool(pattern.search('It opened in 1996')))

import re
msg = '郵便番号は 456-7890 です'
pattern = re.compile(r'\d{3}-\d{4}')
result = pattern.search(msg)
if result :
    print(result.group(0))
else :
    print('Don\'t matched')

import re
msg = """こんにちは。
今日のミーティングですが予定通りの時間に行います。
何か変更があれば連絡してください。"""
pattern = re.compile(r'。\n.')
result = pattern.search(msg)
if result :
    print(result.group(0))
else :
    print('Don\'t matched')
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
True
True
False
True
False
True
True
True
False
True
False
True
False
True
True
456-7890
。
今
```

# まとめ

何かの役に立てばと。
Ansible Serverからターゲットサーバへのコピー

最初失敗かと思ったら
ファイルが大きいので時間がかかっていただけ。
焦ってはいけない。


```
[root@docker163 ansible]# cat mqcopy.yml
---
- hosts: mqservers
  tasks:
  - name: target server Copy from controller
    ansible.builtin.copy:
      src: /ansible/MQ.tar.gz
      dest: /tmp

```

インベントリファイルの中身

```
[root@docker163 ansible]# cat inventory.ini
[mqservers]
mq1
mq2
mq3
```


実行コマンド

```
ansible-playbook -i inventory.ini mqcopy.yml
```
Cloud 9で色々起動しちゃうシリーズ　jupyterlab

```bash
mkdir jupyter-lab
cd $_
```

```bash
python3 -m venv .venv
source .venv/bin/activate
```

```bash
pip install jupyterlab
```

```bash
jupyter lab --port 8080 --ServerApp.allow_remote_access True
```

プレビューさせても、Cloud 9のIDE内だとエラー表示になるので、新規タブで開きましょう。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/afa3ee6a-66f8-f118-0872-4c4562a98e76.png)

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/da53745d-6a36-270e-bef0-677470ae50cf.png)
JS&TS用に画期的なログ出力ライブラリを作ったので報告

# 何を作ったの？
今回自分が作ったライブラリはこちらになります。

https://www.npmjs.com/package/log4debug

このリンクだけだとまだ分からないと思うので説明していこうと思います。
## どういうライブラリ？
簡単に言うと従来のconsole.logを改造する様なライブラリです。
まず以下のコードを見てみてください
```typescript
import log4debug from "log4debug"

log4debug.set(log4debug.defaultTemplate)

console.log("This Package is JavaScript and TypeScript's Logger")
```
これ普通にログ出力されると思いますよね？
実はこれlog4debug.setをやることによって、console.logが改造されて以下のようにログが出力されるんです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2676619/3b5d2ea9-0c65-5652-f4d1-32e153759b2d.png)

## 使い方
大まかな使い方としては以下のようなものがあります。
```ts
import log4debug from "log4debug"

log4debug.set(log4debug.defaultTemplate)
log4debug.setClear(3000,"Clear Log",log4debug.defaultFrameTemplate)

console.log("HelloWorld")
console.clear()

// 出力結果
// [2024-1-4:1711017584119][LOG]: HelloWorld
// -------------
// | Clear Log |
// -------------

//   三秒後にログクリア

```
このように、このライブラリを使う事でconsole.clearとconsole.logの挙動を変えることができます。
**※ プラグインや詳しい仕組みについては次項で解説しています。**

console.logを変える場合にはlog4debug.setを使います。
引数には**プラグイン**を設定することができます。
プラグインは右から順番に読み込まれます。

console.clearを変える場合はlog4debug.setClearを使います。
引数には左から順番に
**ログをクリアするまでの秒数** - 即時クリアの場合はnull or 0でOK
**クリアする前に出力する文字** - 出力する必要がないならnullを代入
**上のやつに何のプラグインを適用するか** - 何も選択しなければ普通のconsole.log又はlog4debugで選択されたものが使われます。

## プラグイン
このライブラリにはプラグインという概念があります。
簡単に言うと、そのライブラリを使う事によって色々なフォーマットでログを出力することができます。
また、仕組み自体は簡単なので、沢山の人にプラグインを作っていただければ幸いです。

**※デフォルトでlog4debug.defaultTemplateとlog4debug.defaultFrameTemplateというプラグインが搭載されています。**

## プラグイン作成方法
まずプラグインは以下のような型を持つ関数にする必要があります。
```ts
type options = (content:string) => string
```
簡単に言うと**引数と戻り値が文字列型**って事ですね

これをもとに実際にプラグインを組むと、以下のようになります。
```ts
import log4debug from "log4debug"

function testPlugin(content:string):string {
    return `[TEST]${content}`
}

log4debug.set(testPlugin,log4debug.defaultTemplate)

console.log("This Package is JavaScript and TypeScript's Logger")
```

ログ出力するとログの最初に[TEST]が含まれていると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2676619/2dcc61f3-fbde-bb3d-8041-7bb45833dffc.png)
このように簡単にプラグインを作る事ができるので、良かったら作ってみてください。

## 解説
どうしてこのようなライブラリを作ることができたか説明していきます。

**コードすべてを説明するわけではないので、詳しく見たい方はGitHubでコードを公開していますので、そちらをご覧ください**

https://github.com/ROBOTofficial/log4debug

このコードの肝になっているのは以下の部分です。(一部抜粋)

```ts
type options = (content:string) => string
function set(...func:options[]) {
    let newConsole = console.log // console.logをnewConsoleに代入
    console.log = (...data: any[]) => { // console.logに新しい関数を代入
        let content = data.join(" ")
        if (func.length !== 0) for (let i = func.length-1; -1 < i; i--) content = func[i](content)
        newConsole(content)
    }
}
```
このコードの内容としてはconsole.logの関数を一度newConsoleという関数に写して、実際のconsole.logにはnewConsoleなどの関数を利用した新しい関数を入れるという感じです。

## 関連リンク
https://www.npmjs.com/package/log4debug

https://github.com/ROBOTofficial/log4debug

## 注意点
何かこの記事や自分のライブラリ等に改善点等ありましたら、コメント欄で優しくご指摘していただけるとさ
Redis・Pythonで検証用データを作る（セット型で大量の要素を登録する）

## はじめに

Redisの検証を行う際に、検証用のデータを作成する必要が生じまして、その方法を考えました。

文字型やリスト型などで、キーと値だけ定義できればよいならredis-benchmarkが使えるのですが、redis-benchmarkでは以下のようなことはできないようでした。

* セット型で1つのキーに複数の要素を持たせる
* キーに有効期限を設定する

他にも、ソート済みセット型やHyperLogLog型などを登録してみたいと思いましたが、いずれもredis-benchmarkではできないようでした。そもそも、redis-benchmarkはRedisのベンチマークツールです。

今回はSet型で1つのキーに複数の要素を持たせるようにしたかったので、Pythonのクライアントライブラリredis-pyを使ってみました。

1つのSet型に1000万・2000万という要素を持たせると、キーの削除には数秒かかり、その間はブロックが発生します。このブロックをわざと発生させるための方法を考えていて、Set型に1000万単位で要素を登録することを思いついて、その処理にクライアントライブラリを使おうと考えました。

Set型1つに1000万単位で要素を持たせる事自体は、実用的な使い方ではないですが、キー削除時のブロック処理・ノンブロック処理を検証するには都合の良いキー・値となります。

## Pythonのクライアントライブラリredis-pyのインストール

クライアントライブラリのインストールを行います。

```bash
$ pip install redis
```

## 参考・redis-cliでセット型のキーを登録する

以下のキーを登録するとします。

* セット型でmysetというキー
* 10個の要素
    * 1
    * 2
    * 3
    * 4
    * 5
    * 6
    * 7
    * 8
    * 9
    * 10

セット型のキーの登録には`SADD`コマンドを使います。

```:redis-cli
127.0.0.1:6379> SADD myset 1 2 3 4 5 6 7 8 9 10
(integer) 10
```

## Pythonで上記のキーを登録するには？

redis.commands.core.CoreCommandsの`sadd`コマンドを使います。

https://redis.readthedocs.io/en/stable/commands.html#redis.commands.core.CoreCommands.sadd

1つ目の引数にキー名を、2つ目以降は要素をカンマ区切りで列挙します。

```python
import redis

r = redis.Redis(host='localhost', port=6379)

r.sadd('mydata', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
```

:::note info
以後、`import ...`と`r = redis ...`は省略します。
:::

## 最初に考えた記述

`sadd`コマンドの挙動を確認した際に、値はカンマ区切りで列挙すれば登録できていたことから、当初はrange()で連番を作り、それをリスト型にした後、カンマ区切りで文字型にしたものを値として渡せばよいと思いました。

```python
l = list(range(1, 11))
s = ','.join(str(n) for n in l)    # print(s)で確認すると 1,2,3,4,5,6,7,8,9,10

r.sadd('mySet', s)
```

`r.sadd('mySet', 1,2,3,4,5,6,7,8,9,10)`になると思ったのですが、登録されたキーを確認したら、要素数は1でした。これは失敗です。

```:redis-cli
127.0.0.1:6379> SMEMBERS mySet
1) "1,2,3,4,5,6,7,8,9,10"
```

## うまくいった記述

リスト型でデータを作った後、アンパックしてsaddのvalueに渡すとうまくいきました。

```python
l = list(range(1, 11))    # print(l)で確認すると [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

r.sadd('mySet', *l)
```

確認すると、今度は意図したとおりに10個の要素が登録されていました。

```redis-cli
127.0.0.1:6379> SMEMBERS mySet
 1) "1"
 2) "2"
 3) "3"
 4) "4"
 5) "5"
 6) "6"
 7) "7"
 8) "8"
 9) "9"
10) "10"
```

## 要素数を1000万件にして実行

この後、`range()`の引数を`1, 10_000_001`にして`sadd`コマンドを実行、redis-cliで確認したところ、キーの要素数が1000万となったことを確認できました。

```:redis-cli
127.0.0.1:6379> SCARD myset
(integer) 10000000
```

`SMEMBER myset`でも確認しました。1000万件の要素を表示するのに140秒程かかりました。

```:redis-cli
127.0.0.1:6379> SMEMBERS mySet
       1) "6538995"
       2) "756997"
       3) "3976871"

【中略】

 9999998) "9994395"
 9999999) "4432247"
10000000) "5477660"
(140.21s)
```
データ検証に使えるExcel関数まとめ

### 概要
データの検証をしたいときに、活用しやすい関数をまとめてみました。
あるデータがちゃんと想定通りのデータになっているかを、目視だけでなく関数を利用することで効率よく効果的に確認ができます。
いろいろな関数が活用できますが、割と汎用的なものをまとめたので、覚えられると様々な場面で役に立つかと思います。

## 比較演算子
データ検証に限らずいろんな場面で必要になる基礎知識ですが、検証する上でデータの一致や比較は必須となるので記載しておきます。
演算子|名称|使用例|結果
|:-:|:-:|:-:|:-:|
|=|等しい	|"=5"|5と等しい
|<>|等しくない|"<>渋谷"|渋谷に等しくない
|>|より大きい|">5"|5より大きい
|<|より小さい|"<5"|5より小さい
|>=|以上|">=5"|5以上
|<=|以下|"<=5"|5以下

## COUNTIF関数
条件に指定した単語や数値、日付、比較条件などと一致するセルの数を数えてくれます。
例えば性別の項目がある表で男性の行がいくつあるか数えたい時は、下記のように記載します。
```
=COUNTIF(A1:A27,"男性")
```
範囲を指定して、条件に指定する（数を数えたい）文言を指定しています。
仮に男性だけで絞られたデータだった場合、全体の行数と関数の結果が一致するはずなので、これが一致しなければ何かおかしいと気づけます。
2つ目の引数は文言だけでなく、数値や日付なども指定できて比較演算子も扱えるので、年齢の項目で○○歳以上とか、登録日の日付が○月○日以前などといった条件も指定できます。

## SEARCH関数
指定された文字列を他の文字列から検索し、最初に見つかった位置を数値で表します。
SEARCH(検索文字列,対象,開始位置)
※開始位置は省略できます。
使い方の例として
```
=SEARCH("渋谷区",A2)
```
このように記入することでA2に住所データが入力されていた場合、渋谷区であるかどうかを検索して確かめることができます。
１つ前に紹介したCOUNTIF関数とやっていることが近いですが、文字列の中から何かの文字列を検索したいといったケースで、SEARCH関数のほうがシンプルで扱いやすいイメージです。
また、SEARCH関数は範囲指定ができないので１セルずつに１つ関数を記載したセルが必要です。

## LEFT関数（RIGHT関数、MID関数）
文字列の一部だけを取り出して、確認したいときに使えます。
LEFT関数は文字列の左側から指定した文字数だけ取り出します。
```
=LEFT(A2,3)
```
1つ目の引数で文字列、2つ目の引数で文字数（何文字目まで取るか）を指定しています。
例えば電話番号のような最初の1文字が必ず0になる想定の項目があったとき、1桁目だけを取ってフィルタを掛けたりすることで、ちゃんと0であるか確認することができます。

RIGHT関数は下記の記載で、LEFT関数とは逆に右から指定した文字数取ります。
```
＝RIGHT(文字列,文字数)
```
MID関数は若干変わりますが、2つ目と3つ目の引数で何文字目から何文字取るかを指定します。
```
=MID(文字列, 開始位置, 文字数)
```
URLアクションを利用した画像表示のやり方

今回、Tableauの自己学習を行い、自分の振り返りを兼ねて拙い文ですがまとめてみました。

**使用環境**
・Tableau Public（無料）

**使用データ**
・サンプル　-　スパーストア

今回使用環境の準備、サンプルデータの準備の方法に関しては省略させていただきます。


## やりたいこと
**ゴール：ダッシュボード上にネット画像のURLを記載してそのURLをClickしたら該当の画像を表示**
これが実装できると、
・今回は単なる画像のURLだが関連するネットの情報のリンクを残すことでダッシュボードの情報とネットの情報を並べて表示
などURLとダッシュボードを連携させることでダッシュボードの表現の幅を広げることが可能である。


**手順１:**
・下記画像の電球、ノートの画像をwebで画像の取得をする。今回の取得先としては下記のリンクからフリーのアイコン画像の取得を行う。
![スクリーンショット 2024-03-21 19.30.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2591484/073ae06e-bd20-e1ad-8933-d243468e3b75.png)

取得先：https://icooon-mono.com/

**手順2:**
・計算フィールドの作成から下記画像のように記載する。
![スクリーン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2591484/fee95ec6-0c02-aa96-98f6-24d654b19f4b.png)

then以降は上から電球、ノートの画像のURLになる。

次に、シートの方に製品名と上記作成したURLの方をドラックする。

![スクリーンショット 2024-03-21 20.31.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2591484/535c8c31-a284-78dc-d794-af6368ebe2fb.png)


**手順3:**
ダッシュボードの方に、手順2で作成したシートを移動させ、『ワークシート』→『アクション』の順にクリック。


**手順４:**
『アクションの追加』→『URLに移動』を順にクリック

![スクリーンショット 2024-03-21 20.35.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2591484/9e3bde49-89f8-0179-a4fd-117c04af0072.png)



**手順５:**
下記画像のように設定を実施する。
ソースシートの方は手順2で作成したシートを選択
アクションの実行対象は『選択』を選択。
（『カーソルを合わせる』を選択した場合は、カーソルを合わせるだけで該当のページに遷移）

『挿入』の方には手順2の計算フィールドから作成したものを選択URL
![スクリーンショット 2024-03-21 20.37.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2591484/4d61cb1a-d582-7151-4f5b-bd0886f41735.png)



こうすることで作成したダッシュボード上のURLをクリックすることで該当のリンクに遷移できます。

![スクリーンショット 2024-03-21 20.44.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2591484/51278d65-2397-a493-5fa4-275a0a30c2f2.png)


## あとがき
今回アクション機能を使い該当のURLをクリックすることで、該当のページを参照できるように設定しました。今回は画像を表示させる機能を追加しましたが、地図などと連携してその土地の地理情報を表示させるなどが考えられます。是非この機会に試してみてください。
kubernetesとは

## Kubernetes（クーバネティス）
Kubernetes（クーバネティス）とはコンテナ化されたアプリケーションを自動的に管理するオープンソースのツールです。これにより、複数のコンテナを効率的に管理し、高可用性とスケーラビリティを実現できます。

## Dockerとの関連性
Dockerはコンテナ化プラットフォームであり、Kubernetesはそのコンテナを効率的に管理するためのオーケストレーションツールです。Dockerを使ってアプリケーションやサービスをコンテナ化すると、Kubernetesを使用してそれらのコンテナをクラウド上で簡単にデプロイ、管理、スケーリングすることができます。

## Kubernetesの利点
自動化された管理: Kubernetesはアプリケーションのデプロイメント、スケーリング、および管理を自動化します。
高可用性とスケーラビリティ: Kubernetesはアプリケーションの高可用性を確保し、トラフィックに応じてスケーリングできます。
柔軟性とポータビリティ: Kubernetesはクラウド上で動作し、さまざまな環境でアプリケーションを実行できます。
## まとめ
Kubernetesはコンテナ化されたアプリケーションの自動化された管理を可能にするツールであり、Dockerと組み合わせることで開発と運用の効率性が向上します。Dockerでアプリケーションをコンテナ化し、Kubernetesでそれらのコンテナを簡単に管理して、スケーラビリティと信頼性を確保する。
複数のコンテナを一元的に管理するツールだと考えておけば問題ない！
#### 単語
高可用性（High Availability）:

これはシステムやサービスがずっと利用可能である状態を指します。つまり、システムが障害や停止したり、ダウンタイムが発生したりしないことを意味します。高可用性を実現するためには、冗長性を持たせたり、自動的に障害を検知して修復したりする仕組みが必要です。

スケーラビリティ（Scalability）:

スケーラビリティは、システムやサービスが負荷やユーザー数の増加に柔軟に対応できる能力を指します。つまり、システムがスムーズに増減することができ、高負荷時でも正常に動作し続けることができることを意味します。
オーケストレーションツール（Orchestration Tool）:

オーケストレーションツールは、複数のコンポーネントやサービスを自動的に管理し、効率的に動作させるためのツールです。例えば、複数のサーバーやコンテナーを自動的に起動・停止したり、負荷分散や障害対応を行ったりするためのツールです。

デプロイ（Deploy）:

デプロイとは、アプリケーションやソフトウェアを実際に動作させる準備を整えることを指します。つまり、開発したアプリケーションを実際の環境に配置して、利用可能にする作業です。
スケーリング（Scaling）:

スケーリングは、システムやサービスの処理能力やリソースを増減させることを指します。負荷が増加した場合には、システムを拡張して追加のリソースを割り当て、負荷が減少した場合にはリソースを減らすことで、システムの柔軟な運用を可能にします。
トラフィック（Traffic）:

トラフィックは、ネットワーク上を流れるデータや通信の量や流れを指します。ウェブサイトへのアクセスやネットワーク上のデータ転送など、さまざまな形で現れます。
ポータビリティ（Portability）:

ポータビリティは、システムやアプリケーションが異なる環境やプラットフォームで移動したり、利用されたりする能力を指します。つまり、ある環境で開発や動作したアプリケーションが、別の環境でも同じように動作することができることを意味します。

[参考サイト]
・https://qiita.com/tadashiro_ninomiya/items/6e6fea807b2a16732b5b
・https://www.dsk-cloud.com/blog/what-is-kubernetes
Zabbixでメンテナンス設定を適用する

## はじめに
Zabbixで監視をしているサーバーで、サービス停止を伴うメンテナンスを行うことがあります。その際にZabbixからアラート通知が飛んでしまうため、メンテンス中は設定を入れ、アラートを抑止する事ができます。  

## 各種項目の入力
左バーから「設定」→「メンテンス」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529173/d571e9fa-8cbb-20ac-2e18-ece42ec52b94.png)

右上「メンテンス期間の作成」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529173/6702d4ce-1f00-c611-7d6b-9a116c1d668f.png)

## 「メンテナンス」の入力
「メンテナンス」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529173/41fc8753-24cd-3330-ab4a-8a24495fc25f.png)

名前： メンテナンスの内容がわかる名前を入力
設定有効期間の開始日時： メンテナンス期間の開始時間を設定
設定有効期間の終了日時： メンテナンス期間の終了時間を設定

## 「監視対象のメンテナンス期間」の入力

「監視対象のメンテナンス期間」→「追加」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529173/0ea2337d-3459-a40b-6c4b-8dbf0ba46a5a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529173/e7fbc0d3-80fa-506d-bb78-c53c11bd1f27.png)

期間のタイプ： 1回だけなのか、定期的（毎日・毎週・毎月）に実施するかを選択
日時： メンテナンス開始日時を設定
メンテナンス期間：上記日時からどれだけの期間をメンテナンス期間とするのか

「追加」を選択。


## 「ホストとホストグループ」の入力
「ホストとホストグループ」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529173/ab4730d0-a83e-fde1-5ae7-36fe30df0c7f.png)

ホストグループorホスト：監視対象のホストを指定

「追加」を選択

メンテナンス期間の一覧画面に作成したメンテナンス期間が表示されていることを確認する。

## まとめ
上記方法でメンテンス中のアラートを抑止する事ができます。設定した時間が過ぎたら自動的に監視がスタートします。

また、zabbix APIというオープンソースの監視ツールの機能やデータをプログラム的に操作・取得するためのインターフェースがあるみたいです。これにより、ユーザはZabbixのGUIを使用せずに、直接データベースにアクセスしたり、設定の変更、新しいホストの登録などの操作を自動化できます。
GUIから手動だと手間や設定漏れのリスクがあるので、更に効率化できそうだと感じました。

メンテナンス作業が予定より早く終了した際には、削除を忘れずに。
【ポエム】Pythonのsortedcontainersって便利だね

C++でいうところのstd::setがPythonにも導入でき、かつAtCoderでも可用なことを最近知った。この記事は、自分自身のための備忘録のようなものであり、万人が参考にできるとは限らないのでご注意ください。

# SortedSetおよびSortedList

ローカルで使うにはpip導入後に```pip install sortedcontainer```を叩くこと。

以下のようなコードを書くと使える。自動補完の際は小文字のsortedsetやsortedlistをimportしないように気をつけよう。

SortedDictもあるらしいが、使い方がよくわからないので割愛。

```python
from sortedcontainers import SortedSet,SortedList

SL = SortedList([3,1,4,1,5])
SS = SortedSet([3,1,4,1,5])
```

要素の追加がadd、削除がdiscardで統一されていることに注意。

# 使用例
特徴としては、indexを指定したアクセスが早い。挿入も早い。削除もおそらく早い。
最大・最小値を知りたい時は特に便利。
ACコードへのリンクも記載してあるが、あまりリーダブルではないので注意。

## [ABC170 D - Not Divisible](https://atcoder.jp/contests/abc170/tasks/abd170_d)
集合を小さい順に見ていって、見たやつから消す、的なことが可能。
余談だが、ソートされていることが保証されているので、集合を小さい順に回すコードを書く際に精神的に良い。[ACコード](https://atcoder.jp/contests/abc170/submissions/51475674)

## [ABC137 D - Summer Vacation](https://atcoder.jp/contests/abc137/tasks/abc137_d)
優先度付きキューの代わりに使うと、「えーと最大値を求めるには$ -1 $をかけて……」みたいな手間が省ける。[ACコード](https://atcoder.jp/contests/abc137/submissions/51486781)

## [典型90問 001 - Yokan Party](https://atcoder.jp/contests/typical90/tasks/typical90_a)
~~1問目にしては妙に難しいことで有名。~~ 二分探索もらくらく。bisectを利用。余談だが、整数列を二分探索する時は、引数から$0.5$を引くと同値に当たるパターンがなくなって精神的に良い。[ACコード](https://atcoder.jp/contests/typical90/submissions/51485423)

## [ABC333 C - Repunit Trio](https://atcoder.jp/contests/abc333/tasks/abc333_c)
「N番目に小さいものを答えよ」系の問題で、Nが十分小さければ使えることがある。
（$\because$集合の長さが必要量をはみ出したら捨てられる）
この問題はPyPyの速さを信じて$116^3$回のループをぶん回した。なぜ116かは忘れた。[ACコード](https://atcoder.jp/contests/abc333/submissions/51471935)

## [ABC170 E - Smart Infants](https://atcoder.jp/contests/abc170/tasks/abc170_e)
$2\times 10^5$個の幼稚園の管理と、**最強園児**の管理のため、大量のSortedListを生やした例。制限時間が比較的長いが、それでも割と危うかった。[ACコード](https://atcoder.jp/contests/abc170/submissions/51473425)

## [ABC281 E - Least Elements](https://atcoder.jp/contests/abc281/tasks/abc281_e)
集合$A,B$に対し、$\forall a \in A,b \in B \  \lbrack a \le b \rbrack $を保ちつつ要素を出し入れする問題。比較的点数が高かったが、やってみたら通った。嬉しい。[ACコード](https://atcoder.jp/contests/abc281/submissions/51489398)

# 外部リンク

https://grantjenks.com/docs/sortedcontainers/

https://github.com/grantjenks/python-sortedcontainers
java.net.http.HttpClient にて、IOException: Too many open files エラーが発生する場合の対応

# 概要
`java.net.http.HttpClient`を利用してHTTP通信を行う実装を行った際、処理が集中すると `IOException: Too many open files` というエラーが発生してしまうことがあります。

それほど大した負荷でもないのに、この例外が発生してしまった場合、以下の2つに問題がある可能性が考えられます。

1. OSの設定
2. HttpClientのインスタンスの持ち方

それぞれ、どのように解消すれば良いか、以下に記述します。

# 1. OSの設定を見直す
Linux OSにおいて、ファイルディスクリプタの上限が低く抑えられている可能性があります。この上限値を増やす、または取り払うことで問題が解消されるかもしれません。
詳細は他記事に委ねます。

https://akishin.hatenablog.jp/entry/20130213/1360711554

# 2. HttpClientインスタンスをキャッシュする
HttpClientは、デフォルト実装を`HttpClient.newBuilder().build()`によって生成することが出来ますが、通信の度に生成するのではなく、シングルトンとして使い回す方法が適切な様です。

インスタンスを使い回して問題ないことはドキュメントに記載があります。

https://docs.oracle.com/javase/jp/11/docs/api/java.net.http/java/net/http/HttpClient.html

>HttpClientを使用して「リクエスト」を送信し、「レスポンス」を取得できます。 builderを介して HttpClientが作成されます。 ビルダーを使用して、クライアントごとに次のような状態を構成できます: 優先プロトコル・バージョン(HTTP/1.1またはHTTP/2)、リダイレクトの有無、プロキシ、認証プロバイダなどがあります。**一度ビルドされると、HttpClientは不変になり、複数のリクエストの送信に使用できます。**

ここで「不変になる」ということは、HttpClient自体がステートレスであり、通信の都度インスタンス生成する方針でも問題ないように見えます。

しかしながら、HttpClientのデフォルト実装を見てみると、コネクションをプールしている実装であることが分かります。

```java:jdk.internal.net.http.HttpClientImpl
private final ConnectionPool connections;
```

実際にローカルPCで動作検証したところ、ソケット利用数に明確な差が現れました（スレッド数は1）

* HttpClientインスタンスを使い回す場合、ソケット利用数が30程度で上限を迎える
* HttpClientインスタンスを都度生成する場合、ソケット利用数が250程度まで上昇

この挙動を確認する限り、やはりシングルトンとして使い回す方法が適切であると結論付けられます。
AWS｜同じメールアドレスで複数のIAMユーザーを作る方法

# AWS｜同じメールアドレスで複数のIAMユーザーを作る方法

```
user@hogehoge.com
```
これを

```
user+[好きな文字]@hogehoge.com
```
とするだけで、別のメールアドレスとして認識され、user+[好きな文字].hogehoge.comのメールは全てuser@hogehoge.comに届く。
renovateでライブラリ更新するときの良さげな設定と運用

npmパッケージなどは[renovate](https://docs.renovatebot.com/)により自動で更新PRを出すことができる。その良い設定と運用を考察。

# 前提
- npmパッケージ更新PRが複数あると、1つマージすると **ほぼ必ず** `pnpm-lock.yaml` などのロックファイルや `package.json` がconflictし、rebase/mergeやconflict解消が必要になる。
- github branch protectionでPRのブランチが最新であることをマージ条件として必須にしてある。
- ~~同じくbranch protectionでCODEOWNERSのレビュー必須にしており、renovateの `automerge` 設定は運用できないのでfalseにしてある。~~
  - package.jsonなど、renovateが変更するファイルパスをCODEOWNERSから除外すれば（それらを人間が変更してもレビュー不要になってしまうが）、自動マージでき、大幅に効率化できる
  - https://zenn.dev/kimuchan/articles/9152895c1761a9 

#   rebaseWhen
[rebaseWhen](https://docs.renovatebot.com/configuration-options/#rebasewhen)はデフォルトでautoだが、これはneverの方がよい。

```
  rebaseWhen: 'never',
```

後述のprConcurrentLimitが1でない場合はrenovate のPRが複数同時にできる。そのとき何か1つPRマージするたびに全renovate PRが自動でrebaseされる。CIリソースを無駄に使う上、1つずつしかマージできないので、renovate PRを10個処理するだけでも9+8+7+6+5+4+3+2+1回のrebaseとCIが走る。しかもrenovate PRが10個のまま滞留していると、renovateでないPRをマージしても常に10回rebaseされ続ける。実際に発生した問題としてこれが起因でgithub actions・vercel・chromaticの枠を浪費した。

また、renovateのバグか分からないが、自動commitと組み合わせると危険なときがある。あるPRで自前のGithub Actionによる自動commitとrenovateによるrebase commitを無限に繰り返し上書きし合う挙動をしたことがあり、これもCIリソースを浪費した。

公式は

> It is also recommended to avoid rebaseWhen=never as it can result in conflicted branches with outdated PR descriptions and/or status checks.
> Avoid setting rebaseWhen=never and then also setting prCreation=not-pending as this can prevent creation of PRs.

と非推奨にしているが、PRの状態が最新であることをマージ条件として必須に設定すれば事故は防げるし、PRを最新にrebaseしたかったらチェックボックスを押すだけなので手動でも問題ない。

![スクリーンショット 2024-03-21 14.49.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50442/b0b357d0-1518-7189-8333-d3cd8b427857.png)


# prConcurrentLimit
[prConcurrentLimit](https://docs.renovatebot.com/configuration-options/#prconcurrentlimit) はデフォルトで10だが、これを1にすると、1リポジトリに対して1つのPRだけ出て、マージすると次のPRが1つだけ出て、ということを繰り返すようになる。これはメリットとデメリットがあるが、1の方が良いように思われる。

```
  prConcurrentLimit: 1,
```

1つに絞るメリットとデメリットを考察すると以下のようになる。

- メリット
    - renovate PR同士で必ず発生するconflictがなくなり、rebaseしなくていい
    - conflict解消,rebaseによるCIやり直しで無駄にリソースを使用しない
    - 一度に大量のrenovate PRの通知が来ない
    - 処理する時間がないときにも大量のrenovate PRが滞留しない
- デメリット
    - 事前に対応工数を見積もろうと思ってもやりづらい 
        - PRが1つしかできないので、[Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/)に羅列されている分を見るしかないが、対象のライブラリのリリースノートやcode diffに行きづらいので差分が分かりづらいし、CIが成功するかどうか分からない
    - 1つしかPRがないことで油断して忘れているとずっと更新されないライブラリが出てくる

複数にする場合、例えば月に1回だけ複数のPRを出し、それを眺めていって工数を見積もり、その月内にそれを全部処理する運用になる。
1つにする場合、一定工数を取ってなるべくその範囲でPRを処理し続ける運用になる。
Swiftで数値で構成された配列の中から過半数を超える値を抽出するアルゴリズム


# 概要

[169. Majority Element](https://leetcode.com/problems/majority-element/description)を解いていると面白い解き方があったのでメモを残しておきます。

こちらは与えられた配列中の過半数を超える値を返却するような関数を書く、という問題です。

以下が[169. Majority Element](https://leetcode.com/problems/majority-element/description)で与えられる入力例と出力例です。

```Swift:Majority Element
Example 1:
Input: nums = [3,2,3]
Output: 3

Example 2:
Input: nums = [2,2,1,1,1,2,2]
Output: 2
```

Example 1では`3`が過半数を超える値であるため`3`を、Example 2では`2`が過半数を超える値であるため、`2`を返しています。

また、問題文中に**多数決要素は常に配列中に存在すると仮定してもよい**と記載があるので、過半数を超える値が存在しない状況は考えなくても良いことになります。

なお、ここでは以下のような制約が存在します。

```
n == nums.length
1 <= n <= 5 * 104
-109 <= nums[i] <= 109
```

# 詳細


## 自分の解法

```swift:Majority Element
class Solution {
    func majorityElement(_ nums: [Int]) -> Int {
        var counts = [Int:Int]()

        for n in nums{
            counts[n,default:0] += 1
        }
        
        var maxElement = 0
        var maxCount = 0

        for (element,count) in counts{
            if count > maxCount{
                maxCount = count
                maxElement = element
            }
        }

        return maxElement
    }
}
```

配列内に存在する値とその値が出現する回数をDictionaryで保存しておき、そのDictionary内で最もValueの値が大きい値を返す、というものです。
計算量,空間計算量共にO(N)です。

これ自体はよくある解法で、パッと思いつきやすい内容だと思います。

これで終わりかと思っていましたが、問題文の最後の方に書いてある文字に気が付きました。

```
Follow-up: Could you solve the problem in linear time and in O(1) space?
(この問題を線形時間と空間計算量をO(1)で解くことができますか？)
```

こう書いてあるということは、この問題には空間計算量をO(1)に落とせる解法があるのです。
それが次の解法です。

## Boyer-Moore Voting Algorithm

[Boyer-Moore Voting Algorithm](https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_majority_vote_algorithm)は、与えられた配列内で出現回数が過半数を超える要素（majority element）を効率的に見つけるためのアルゴリズムで、配列内の値を線形時間、そして追加のメモリ空間を使用することなく配列内の過半数を超える要素を見つけることができます。

ここで注意しなければならないのは、**与えられた配列内に過半数の要素が存在すること**が前提条件となっていることです。

今回に関してはその前提が満たされているため、このアルゴリズムが適用可能となっています。


```swift:Majority Element
class Solution {
    func majorityElement(_ nums: [Int]) -> Int {
        var majority = 0
        var count = 0
        for n in nums{
            if count == 0{
                majority = n
                count += 1
            }else if n == majority {
                count += 1
            }else{
                count -= 1
            }
        }
        return majority
    }
}

```

単純なcountの増減だけで過半数を判定できることに気付けなかったのが少し悔しくなりました。

こちらの解法の計算量はO(N)で、空間計算量はO(1)です。
特定の変数しか追加しないため、Dictionaryを使用する時よりもメモリの使用量が少なくなります。
install mosquitto ubuntu

install mosquitto ubuntu Mosquitto is an open-source message merchant that utilizes the Message Lining Telemetry Transport (MQTT) Convention. MQTT runs on top of the TCP/IP model and is the standard informing stage for the Web of Things (IoT). 

Since the MQQT convention is incredibly lightweight, its little code impression permits you to make applications for gadgets with insignificant assets like short battery duration, restricted network data transfer capacity, and untrustworthy web associations.:point_up: https://docs.vultr.com/install-mosquitto-mqtt-broker-on-ubuntu-20-04-server
とりあえずDockerコンテナでMySQLサーバーを立ち上げてクライアントで接続する方法

## やりたいこと
MySQL8を簡単に立ち上げて動作確認をできる方法を作りたい。

## 方法

- 以下のファイルを適当なディレクトリーに作成
- 変数と設定ファイルを変更（【変更対象】と明記した部分）
- `bash start_mysql.sh`で起動



```bash:start_mysql.sh
# 【変更対象】
# 各種変数を設定
dir_name=$RANDOM # 一時ディレクトリー用のディレクトリー名。MySQLの設定ファイルを入れる
conf_dir_path=/tmp/docker/mysql/${dir_name} # とりあえずtmpに作る
conf_file_path=${conf_dir_path}/mysql.cnf # 設定ファイルのパス
local_mnt_dir=/path/to/work_dir/20240320 # マウントするディレクトリー。コンテナ上からアクセスしたいファイルを置いたディレクトリー


# 【変更対象】
# 設定ファイルの準備（ここで必要な設定を読み込ませる。以下の設定ファイルは例なので必要な設定を追加する）
mkdir -p ${conf_dir_path}
cat > ${conf_file_path} <<EOF 
[mysqld]
character-set-server=utf8
local-infile=1 

[mysql]
local-infile=1 
EOF

# コンテナが残っていたら消す
docker rm -f some-mysql


# コンフィグを読み込み、ローカルディレクトリーをマウントし、dockerコンテナを起動する
docker run -v ${conf_dir_path}:/etc/mysql/conf.d -v ${local_mnt_dir}:/tmp/tmp_date --name some-mysql -e MYSQL_ROOT_PASSWORD=password -d mysql

# コンテナが起動しきるまで待つ。10秒は適当なので短くてもよいかもしれない
sleep_seconds=20
echo "waiting for mysql to start up (for ${sleep_seconds} seconds)"
sleep ${sleep_seconds}

# mysqlクライアントでログイン
docker exec -it some-mysql mysql -ppassword -h 127.0.0.1

# 終わったらコンテナを削除する。
docker rm -f some-mysql
Voltaを使用したNode.jsバージョン管理

## はじめに

Voltaを使用してみて、Node.jsのバージョン管理が楽になったので、
インストール方法と、コマンドを簡単に紹介します。

## Voltaとは
VoltaとはNode.jsのバージョン管理ツールです。
「高速」「信頼性」「ユニバーサル」が代表的な特徴として挙げられています。

[Volta](https://volta.sh/)

## Voltaの魅力
 * Windows, Mac両方の環境で使用可能
 * プロジェクトごとに自動でバージョンを変更可能
 * インストール、操作が簡単

## インストール
:::note warn
Node.jsや他のバージョン管理を利用している人はアンインストールが必要です。
:::

最新のインストーラをダウンロードする。
[https://docs.volta.sh/guide/getting-started](https://docs.volta.sh/guide/getting-started)

:::note warn
Windowsの場合設定画面から開発者モードをオンにする必要があります。
「設定」→「プライバシーとセキュリティ」→「開発者向け」
開発者モードをオンに設定
:::

ダウンロードしたVoltaのインストーラを起動してインストール。

ターミナルからVoltaがインストールされたことを確認します。

```ruby:コマンド
volta
```

## Node.jsのインストール

```ruby:安定版
volta install node
```

```ruby:バージョン指定
volta install node@20
```
## Node.jsのバージョンをプロジェクトに固定
プロジェクト固定する場合、プロジェクトのディレクトリで@の後ろを任意のバージョンを入力します。
package.jsonにVoltaに関する設定が記述され、Voltaを使用していれば自動でNode.jsのバージョンを切り替えてくれるようになります。

```ruby:Node.js のバージョンを固定
volta install node@20.11.10
```
## インストールしたバージョンの確認

```ruby:現在使用中の Node.js、npmのバージョン表示
volta list
```

```ruby:インストール済みの Node.js、npmのバージョンを全て表示
volta list all
```
## まとめ
Voltaのインストールと使用方法を簡単に記述しました。
実際に暫く使用してみて、OS依存も無くプロジェクトごとにNode.jsのバージョンを固定できるのは非常に便利と感じています。
興味がありましたら、ぜひ導入してみてください。
DockerのImageを消すのコマンド


# 背景
Dockerのゴミがたまっていた

## Dockerのimageとは

**```docker compose build```などで作られるcontainerを作るときの設計図**

imageの削除はcontainerを止めるのとは別の作業です


## imageの削除
全体の流れ
**イメージのリストを表示して、古いやつを```docker rmi```で消す**

1.　動いているcontainerがないか確認しよう
```docker container ls```を実行する

結果例
```
$ docker container ls
CONTAINER ID   IMAGE       COMMAND                  CREATED       STATUS      PORTS     NAMES
00092249572f   AAA-core   "/opt/nvidia/nvidia_…"   13 days ago   Up 5 days             AAA-core-1
```

もし今使っていないcontainerがあれば先に```docker compose stop <CONTAINER ID>```で止めるか、```docker compose down <CONTAINER ID>```で消しましょう


2.　imageを見てみよう
```docker images```を実行してイメージのリストを表示する

```
$ docker images
REPOSITORY                 TAG       IMAGE ID       CREATED         SIZE
gpu-hina-graduation-core   latest    fe5d083f8783   3 weeks ago     9.56GB
<none>                     <none>    d24265650b3c   3 weeks ago     9.56GB
ubuntu                     latest    3db8720ecbf5   5 weeks ago     77.9MB
gpu-core                   latest    5a2107c66f19   7 weeks ago     4.96GB
hello-world                latest    9c7a54a9a43c   10 months ago   13.3kB

```
3.　いらないimageの削除
```sudo docker rmi IMAGE ID```を実行する

特に```<none>```は既に同じものが作られていてゴミになっている可能性が高いので消そう！
SIZEがピッタリ一致しているものは同じものである可能性が高いよ

もし、コンフリクトしたり、使われていますというエラーが出た場合には無理して消さない方がよいかもです
```
Error response from daemon: conflict: unable to delete XXXXXXXX (must be forced) - image is being used by stopped container XXXXXXXX
```

## 終わり
ゴミが消せて平和に:raised_hands: