2024,江端さんの技術メモ

昨夜、8台目のディスプレイと6台目のカメラが搬入されました。個人デートレーダに匹敵する環境になったような気がします。

気分は、学生のころは、研究室に寝袋持ち込んで、コーディングしたいたものですが −− リタイアを目前としたシニアエンジニアとは思えない状況です(と、この内容を打ち込んでいる最中も、バックエンドで、”sudo apt upgrade”が動き続けています)。

で、

Raspberry Pi 4でUbuntuデスクトップを動かして遊ぶ

を、参考にさせていただいて、vscodeをインストールしてみたのですが、普通に動く。

結構びっくりしています。

これからは、ディスプレイがあるところ(会社とか研究室)なら、ラズパイ4を持ち歩くだけで、十分かもしれません。

とりあえず拡張機能として、当然に

Japanese Language Pack for Visual Studio Code

をインストール。

で、文章作成環境も必須なので、こちらもインストールしておく

江端風、最小コストで電子書籍(PDF)を作ってアプロードする方法

vscodeでMarkdownを使って文章を書いている時、図面のコピペを文書の中にサクっと入れることができるアドイン "Paste Image"

2台目のラズパイ用にメモとして残しています。

2024,江端さんの技術メモ

User
You
OBJECTID,BLDG_ID,Posting,HH_id,CENTROID_X,CENTROID_Y,AnsFlag,Shape_Area 1,1,1,,139.6193534,35.3662534,,2994.84232 2,3,0,,139.6247907,35.36777712,,2311.216892 3,4,0,,139.6238161,35.36573877,,1814.524575 4,5,0,,139.6243819,35.36882641,,1669.266149
と記載されたcsvファイルのテーブル作成に必要なスキーマを作るSQL文を作って下さい
=============
ChatGPT

指定されたCSVファイルの内容に基づいて、PostgreSQLのテーブルを作成するためのSQL文は以下の通りです。

sql
CREATE TABLE your_table_name (
OBJECTID INTEGER,
BLDG_ID INTEGER,
Posting INTEGER,
HH_id INTEGER,
CENTROID_X FLOAT,
CENTROID_Y FLOAT,
AnsFlag INTEGER,
Shape_Area FLOAT
);

このSQL文を実行することで、指定されたカラムとデータ型が定義された"your_table_name"という名前のテーブルが作成されます。
=============

で、まあ後は、
$ psql -U postgres -h 192.168.0.23 -p 15432
postgres=# \c tomioka_pt2018
で、
CREATE TABLE part4_oe (
OBJECTID INTEGER,
BLDG_ID INTEGER,
Posting INTEGER,
HH_id INTEGER,
CENTROID_X FLOAT,
CENTROID_Y FLOAT,
AnsFlag INTEGER,
Shape_Area FLOAT
);
をコピペしてテーブル作って、

\copy part4_oe from 'part4_oe.csv' delimiter ',' csv header;

とすれば、テーブル完成です。

=============

努力をしない(スキーマ設計すら生成AIにぶん投げる)自分が、日々"バカ"になっているような気がします。
生成AIを(こき)使う方は色々学んでいるんですけどね。

2024,江端さんの技術メモ

PostgreSQLで漢字を使えるようにするには、いくつかのステップがあります。

  1. データベースのエンコーディングを設定する: データベースのエンコーディングをUTF-8に設定します。UTF-8は、多言語の文字をサポートするための広く使われているエンコーディングです。データベースを作成する際に、以下のように指定します。
    sql
    CREATE DATABASE your_database_name ENCODING 'UTF8';
  2. csvファイルもUTF8にして、
    tomioka_pt2018=# \copy stn from 'stn.csv' delimiter ',' csv header encoding 'UTF-8';
    にする。
  3. で、
    oid | name | folderpath | popupinfo | point_x | point_y | zoneflag
    -----+--------------------------+------------+-----------+-------------+------------+----------
    1 | □□□}□x□□ | Code_Stn | 700001 | 139.6298946 | 35.3670993 | 2
    2 | □V□□□c | Code_Stn | 700002 | 139.619429 | 35.386768 | 2
    3 | □□□c | Code_Stn | 700003 | 139.6159047 | 35.3835577 | 2
    4 | □\□□□□ | Code_Stn | 700004 | 139.629443 | 35.3608848 | 2
    5 | □w□|□□□w | Code_Stn | 700005 | 139.685247 | 35.628743 | 1とこんなザマになるんだけど、SQL(shell)を使うと、
    oid | name | folderpath | popupinfo | point_x | point_y | zoneflag
    -----+--------------------------+------------+-----------+-------------+------------+----------
    1 | 京急富岡 | Code_Stn | 700001 | 139.6298946 | 35.3670993 | 2
    2 | 新杉田 | Code_Stn | 700002 | 139.619429 | 35.386768 | 2
    3 | 杉田 | Code_Stn | 700003 | 139.6159047 | 35.3835577 | 2
    4 | 能見台 | Code_Stn | 700004 | 139.629443 | 35.3608848 | 2
    5 | 学芸大学 | Code_Stn | 700005 | 139.685247 | 35.628743 | 1
    6 | 旗の台 | Code_Stn | 700006 | 139.7027206 | 35.6048821 | 1
    7 | 恵比寿 | Code_Stn | 700007 | 139.7101065 | 35.6467334 | 1
    8 | 国立競技場 | Code_Stn | 700008 | 139.7143886 | 35.6797457 | 1と、ちゃんと出るんだな、
    これが。クライアントの問題だけならいいんだど

ERROR: character with byte sequence 0xe9 0xb7 0x97 in encoding "UTF8" has no equivalent in encoding "SJIS"

に解決策が書いてありました。

yoko_db=# set client_encoding to utf8;
SET
yoko_db=# \encoding
UTF8

As:SQL でも表示されました。

 

 

2024,江端さんの技術メモ

以下の方法は、以下のようにGeometry型にしなければならないらしい → 可読性が悪くなるので、この方法は採用しないことにした。
OBJECTID,BLDG_ID,Posting,HH_id,centroid_geom,AnsFlag,Shape_Area
1,1,1,,"POINT(139.6193534 35.3662534)",,2994.84232
2,3,0,,"POINT(139.6247907 35.36777712)",,2311.216892
3,4,0,,"POINT(139.6238161 35.36573877)",,1814.524575
4,5,0,,"POINT(139.6243819 35.36882641)",,1669.266149

================================
以下のHH.csvというファイルがあったとします。
OBJECTID,BLDG_ID,Posting,HH_id,CENTROID_X,CENTROID_Y,AnsFlag,Shape_Area
1,1,1,,139.6193534,35.3662534,,2994.84232
2,3,0,,139.6247907,35.36777712,,2311.216892
3,4,0,,139.6238161,35.36573877,,1814.524575
4,5,0,,139.6243819,35.36882641,,1669.266149
5,7,1,13033,139.6213946,35.36896447,1,1377.877194CENTROID_X CENTROID_Yが、それぞれ経度と緯度の情報が入っています。 このcsvファイルを使って、作成手順を具体的に説明して下さい。
================================
以下は、PostgreSQLにCSVファイルをインポートし、PostGISを使用して緯度経度情報を含むデータを扱う手順です。
  1. PostGIS拡張機能の有効化: PostgreSQLでPostGIS拡張機能を有効化します。
    CREATE EXTENSION postgis;
  2. テーブルの作成: CSVファイルをインポートするためのテーブルを作成します。緯度経度情報を含むカラムには、地理空間データ型のポイント(Point)を使用します。
    CREATE TABLE HH (
    OBJECTID INTEGER,
    BLDG_ID INTEGER,
    Posting INTEGER,
    HH_id INTEGER,
    CENTROID_GEOM GEOMETRY(Point, 4326),
    AnsFlag INTEGER,
    Shape_Area NUMERIC
    );

    ここで、HHはテーブルの名前を指定します。CENTROID_GEOMカラムは、緯度経度情報を格納する地理空間データ型のカラムです。

  3. CSVファイルのインポート: COPYコマンドを使用して、CSVファイルを作成したテーブルに直接インポートします。
    COPY HH (OBJECTID, BLDG_ID, Posting, HH_id, CENTROID_X, CENTROID_Y, AnsFlag, Shape_Area)
    FROM 'HH.csv'
    DELIMITER ','
    CSV HEADER;

    ここで、path_to_your_csv_fileは、インポートするCSVファイルのパスを指定します。

  4. 緯度経度情報の更新: インポートしたテーブル内の緯度経度情報を使用して、地理空間データ型のカラムを更新します。
    UPDATE HH SET CENTROID_GEOM = ST_SetSRID(ST_MakePoint(CENTROID_X, CENTROID_Y), 4326);

これで、CSVファイル内の緯度経度情報を持つデータをPostgreSQLにインポートし、PostGISを使用して地理空間データとして扱う準備が整いました。QGISなどのGISソフトウェアを使用して、地理情報を可視化したり分析したりすることができます。

2024,江端さんの技術メモ

「レイヤ」→「輝度を透明度に変換」→不透明度保護にチェック → 白で塗りつぶし(バケツ)

上記のレイヤーの下に新規レイヤー→黒で塗りつぶし

 

2024,江端さんの技術メモ

■tcを使って帯域を10Mbpsに制限する"だけ"のコマンド
sudo tc qdisc add dev eth0 root tbf rate 10mbit burst 10kb latency 100ms
(burst 10kb latency 100msを付けないと、エラーになる)

■tcを使って遅延を500msに制限するだけのtcコマンド
sudo tc qdisc add dev eth0 root netem delay 500ms

■tcを使ってパケットロスを10%に制限する"だけ"のコマンド
sudo tc qdisc add dev eth0 root netem loss 10%

■tcを使ってパケットを保持できるキューの最大数を1000に制限する"だけ"のコマンド
sudo tc qdisc change dev eth0 root handle 1: pfifo limit 1000

  • change: 既存のキューイング方式を変更する際に使用されるオプションです。
  • dev eth0: 変更を加える対象となるネットワークインターフェースを指定します。この場合はeth0です。
  • root: ルートキュー(ルートディスクリプタ)に変更を加えることを示します。
  • handle 1:: ルートキューを特定するためのハンドルを指定します。1:は一般的にルートキューを表します。
  • pfifo: パケットを先入先出順で処理する単純なキューイング方式です。
  • limit 1000: パケットを保持できるキューの最大数を指定します。ここでは1000としています。
分類 qdiscの名前 カーネルソースファイルの場所 概要
クラスレス qdisc pfifo_fast net/sched/sch_generic.c デフォルトのqdiscです。FIFOのキューが3つあります
pfifo net/sched/sch_fifo.c FIFOのキューが1つあります。キュー長の最大値はパケット数で表します
bfifo 同上 FIFOのキューが1つあります。 キュー長の最大値はバイト数で表します
sfq(Stochastic Fairness Queueing) net/sched/sch_sfq.c フローにもとづいてパケットをスケジューリングします。フローとは送信元/送信先IPアドレス、ポート番号の組です
tbf(Token Bucket Filter) net/sched/sch_tbf.c パケットシェーピング機能を提供します。制限レートを超えたパケットはキューに保留されます
netem(Network Emulator) net/sched/sch_netem.c 送信パケットに対して、パケット廃棄、遅延等の操作をするためのqdiscです
fq(Fair Queue Packet Schedule) net/sched/sch_fq.c Fair Queue Packet Scheduler (per flow pacing)
クラスフル qdisc prio net/sched/sch_prio.c ルールにしたがってパケットを分類(class)します。デフォルトでは3つのクラスがあります。それぞれのクラスにqdisc(sfq,tbf等)を設定することができます。
htb(Hierarchy Token Bucket) net/sched/sch_htb.c 1つのリンクを複数のサービス(www,ftp等)で共有する場合、各サービスに最低限必要な帯域を割り当てることができます

計測は、iperf3で行う

iPerf3を使用したネットワーク速度計測

sudo tc qdisc add dev eth0 root tbf rate 10mbit burst 10kb latency 100ms このコマンドにパケットロス10%を追加して下さい

sudo tc qdisc add dev eth0 root handle 1: tbf rate 10mbit burst 10kb latency 100ms sudo tc qdisc add dev eth0 parent 1:1 handle 10: netem loss 10%

 

 

 

2024,江端さんの技術メモ

/*
	c:\Users\ebata\tomioka3b\others\main42.go
	指定されたファイルから時刻表を読み込み、最も近い未来の時刻を取得します。
*/
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
	"time"
)

func main() {
	// 指定されたファイル名
	fileName := "To_Sengakuzi_weekdays.csv" // ここにファイル名を入力してください

	// 指定されたファイルから時刻表を読み込む
	schedule, err := readScheduleFromFile(fileName)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	//fmt.Println("時刻表:", schedule)

	// 現在時刻を取得
	now := time.Now().Format("15:04:05")
	now = "12:29:00"

	// 最も近い未来の時刻を取得
	nextTime := getNextTime(schedule, now)

	// 結果を出力
	fmt.Println("最も近い未来の時刻:", nextTime)
}

func readScheduleFromFile(fileName string) ([]time.Time, error) {
	// ファイルを開く
	file, err := os.Open(fileName)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var schedule []time.Time

	// ファイルから時刻を読み取る
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		times := strings.Split(line, ",")
		for _, t := range times {
			//fmt.Println("時刻:", t)
			t1, err := time.Parse("15:04:05", t)
			if err != nil {
				fmt.Println("時刻のパースに失敗しました:", err)
				return nil, err
			}
			schedule = append(schedule, t1)
		}
	}

	// fmt.Println("pass4")
	// fmt.Println("schedule: ", schedule)

	return schedule, nil
}

// 指定された時刻表から最も近い未来の時刻を取得する関数
func getNextTime(schedule []time.Time, inputTime string) string {
	// 入力時刻のパース
	input, err := time.Parse("15:04:05", inputTime)
	if err != nil {
		panic(err)
	}

	// 時刻表の各時刻との差を計算し、最小の差を見つける
	minDiff := time.Hour * 24
	var nextTime string
	for _, t := range schedule {
		// 時刻の差を計算
		diff := t.Sub(input)

		// 負の差(過去の時刻)を無視
		if diff < 0 {
			continue
		}

		// 最小の差を更新
		if diff < minDiff {
			minDiff = diff
			nextTime = t.Format("15:04:05")
		}
	}

	return nextTime
}

To_Sengakuzi_weekdays.csv

4:53:00
5:08:00,5:23:00,5:32:00,5:44:00,5:55:00
6:03:00,6:14:00,6:26:00,6:33:00,6:40:00,6:44:00,6:49:00,6:53:00,6:59:00
7:04:00,7:09:00,7:14:00,7:19:00,7:26:00,7:30:00,7:37:00,7:46:00,7:52:00,7:58:00
8:06:00,8:14:00,8:21:00,8:26:00,8:33:00,8:41:00,8:47:00,8:54:00
9:02:00,9:10:00,9:21:00,9:31:00,9:41:00,9:53:00
10:03:00,10:13:00,10:24:00,10:33:00,10:44:00,10:53:00
11:04:00,11:13:00,11:24:00,11:32:00,11:44:00,11:53:00
12:04:00,12:13:00,12:24:00,12:33:00,12:44:00,12:53:00
13:04:00,13:13:00,13:24:00,13:33:00,13:44:00,13:53:00
14:04:00,14:13:00,14:24:00,14:33:00,14:43:00,14:52:00
15:02:00,15:12:00,15:22:00,15:31:00,15:41:00,15:52:00
16:01:00,16:10:00,16:20:00,16:31:00,16:42:00,16:53:00
17:02:00,17:13:00,17:23:00,17:34:00,17:43:00,17:53:00,17:59:00
18:12:00,18:19:00,18:28:00,18:38:00,18:48:00,18:57:00
19:08:00,19:18:00,19:26:00,19:36:00,19:46:00,19:55:00
20:06:00,20:16:00,20:27:00,20:36:00,20:46:00,20:56:00
21:08:00,21:15:00,21:18:00,21:29:00,21:39:00,21:50:00
22:01:00,22:11:00,22:21:00,22:26:00,22:38:00,22:53:00
23:12:00,23:33:00,23:54:00

 

2024,江端さんの技術メモ

/*
	c:\users\ebata\tomioka3b\src\others\main41.go
	2次元スプライン関数を使用して、緯度と経度のペアに対応する目的地までの時間を計算します。
*/

package main

import (
	"fmt"
	"sort"
)

// スプライン補間用の関数
func splineInterpolation(dataSet [][]float64) func(float64, float64) float64 {
	n := len(dataSet)

	// xの値を昇順にソートする
	sort.Slice(dataSet, func(i, j int) bool {
		return dataSet[i][0] < dataSet[j][0]
	})

	// トリディアゴナル行列を作成
	h := make([]float64, n-1)
	for i := 0; i < n-1; i++ {
		h[i] = dataSet[i+1][0] - dataSet[i][0]
	}

	// 2階微分の値を計算
	delta := make([]float64, n)
	for i := 1; i < n-1; i++ {
		delta[i] = (dataSet[i+1][1]-dataSet[i][1])/h[i] - (dataSet[i][1]-dataSet[i-1][1])/h[i-1]
	}

	// トリディアゴナル行列を解く
	m := make([]float64, n)
	l := make([]float64, n)
	zArray := make([]float64, n)
	l[0] = 1
	for i := 1; i < n-1; i++ {
		l[i] = 2*(dataSet[i+1][0]-dataSet[i-1][0]) - h[i-1]*m[i-1]
		m[i] = h[i] / l[i]
		zArray[i] = (delta[i] - h[i-1]*zArray[i-1]) / l[i]
	}
	l[n-1] = 1
	zArray[n-1] = 0

	c := make([]float64, n)
	b := make([]float64, n)
	d := make([]float64, n)
	for j := n - 2; j >= 0; j-- {
		c[j] = zArray[j] - m[j]*c[j+1]
		b[j] = (dataSet[j+1][1]-dataSet[j][1])/h[j] - h[j]*(c[j+1]+2*c[j])/3
		d[j] = (c[j+1] - c[j]) / (3 * h[j])
	}

	// 補間関数を返す
	return func(xVal, yVal float64) float64 {
		// xの範囲を確認
		if xVal < dataSet[0][0] || xVal > dataSet[n-1][0] {
			panic("x value is out of range")
		}

		// 対応するiを探す
		i := 0
		for i < n-1 && dataSet[i+1][0] <= xVal {
			i++
		}

		// スプライン補間を計算
		dx := xVal - dataSet[i][0]
		return dataSet[i][2] + b[i]*dx + c[i]*dx*dx + d[i]*dx*dx*dx
	}
}

func main() {
	// データ点の定義
	dataSet := [][]float64{
		{35.7281578, 139.7680665, 73},
		{35.7214573, 139.7754384, 63},
		{35.7141672, 139.7748342, 57},
		{35.7075171, 139.7564025, 67},
		{35.698383, 139.7704968, 65},
		{35.6997175, 139.7618655, 61},
		{35.7020484, 139.7509267, 66},
		{35.6918216, 139.7683569, 63},
		{35.6812362, 139.7645499, 57},
		{35.6750133, 139.7604455, 59},
		{35.666379, 139.7557649, 55},
		{35.6553809, 139.754554, 54},
		{35.6457361, 139.7449875, 54},
		{35.6284713, 139.7361848, 43},
		{35.6208763, 139.7405387, 50},
		{35.6147448, 139.7412068, 49},
		{35.6086671, 139.7426731, 45},
		{35.6052508, 139.7421627, 50},
		{35.5983959, 139.7391046, 50},
		{35.58754, 139.7355111, 51},
		{35.5788485, 139.7348961, 40},
		{35.5721351, 139.7318494, 53},
		{35.5666392, 139.7281759, 53},
		{35.5613144, 139.7215761, 33},
		{35.5446458, 139.7493338, 46},
		{35.5329877, 139.6982966, 30},
		{35.5348941, 139.7449763, 42},
		{35.5229857, 139.6889874, 41},
		{35.5179115, 139.6811867, 40},
		{35.5071467, 139.677526, 34},
		{35.4998507, 139.6713032, 31},
		{35.4923606, 139.6622968, 30},
		{35.4852628, 139.6544734, 29},
		{35.4846744, 139.6452731, 32},
		{35.4808759, 139.6394986, 26},
		{35.4763238, 139.631979, 30},
		{35.4688634, 139.6268306, 32},
		{35.4659811, 139.6194871, 20},
		{35.4571602, 139.6199226, 27},
		{35.4464751, 139.6235656, 25},
		{35.436673, 139.6217708, 24},
		{35.4334892, 139.6206713, 18},
		{35.4314711, 139.6030542, 16},
		{35.424238, 139.5927802, 17},
		{35.4201765, 139.586678, 14},
		{35.413768, 139.582819, 10},
		{35.3819518, 139.6165374, 3},
		{35.4091204, 139.5781752, 7},
		{35.3966138, 139.6051573, 4},
		{35.3645904, 139.6267988, 1},
		{35.3428573, 139.6190711, 3},
		{35.3314185, 139.6176347, 6},
		{35.330416, 139.6295796, 17},
		{35.3337822, 139.630869, 18},
		{35.3407534, 139.6332478, 18},
		{35.3400425, 139.6390968, 20},
		{35.323276, 139.6151587, 13},
		{35.2973885, 139.5758056, 31},
		{35.3158184, 139.6222558, 15},
		{35.312573, 139.6250891, 16},
		{35.308405, 139.628248, 17},
		{35.2825803, 139.6405151, 19},
		{35.2916167, 139.6283632, 17},
		{35.277848, 139.6379121, 21},
		{35.2802815, 139.6599103, 19},
		{35.2786985, 139.6674653, 20},
		{35.2616259, 139.6679659, 26},
		{35.2635438, 139.6841348, 23},
		{35.2482969, 139.6775595, 25},
		{35.2509382, 139.712402, 30},
		{35.2315701, 139.699661, 29},
		{35.2120725, 139.6824547, 33},
		{35.2055645, 139.671602, 44},
		{35.1986888, 139.663162, 37},
		{35.1880928, 139.6507295, 39},
		{35.1775554, 139.6306392, 42},
	}

	// スプライン補間関数を作成
	interpolatedFunction := splineInterpolation(dataSet)

	// 特定の座標で補間された値を計算
	xValue := 35.4688634
	yValue := 139.6268306

	xValue, yValue = 35.7214573, 139.7754384

	interpolatedValue := interpolatedFunction(xValue, yValue)

	// 結果の出力
	fmt.Printf("補間された値: %.2f\n", interpolatedValue)
}

2024,江端さんの技術メモ

作業中のプロジェクト: ないしょ
番号: ないしょ
ID: ないしょ
自分のAPIキー AXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXE

困っていたこと

Google MAP Directions APIを使いたいのですが、自分のAPIキーを使っても、以下のようになります。
https://maps.googleapis.com/maps/api/directions/json?origin=Disneyland&destination=Universal+Studios+Hollywood&key=AXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXE
{
   "error_message" : "This API project is not authorized to use this API.",
   "routes" : [],
   "status" : "REQUEST_DENIED"
}
対策を教えて下さい。
意外なところで解決しました。

で、再度実行したら、こうなりました。

ところが、鉄道の情報が出てこない。

 

うまくいっていない理由確定

 

Google Maps Platform FAQ  |  Google for Developers

https://developers.google.com

Google マップのルートサービスでは、交通機関の対象リストに記載されているすべての交通機関(日本を除く)をサポートしています。

ということで、日本で使用できるのは walking と driving の2モードのみのようです。

あかんやんか・・・

2024,江端さんの技術メモ

SSHキーペアは、通常はローカルマシンで生成され、その後、公開鍵がリモートサーバーに配置されます。以下が一般的な手順です:

  1. id_rsa.pub (公開鍵):
    • ローカルマシンで生成されます
    • ssh-keygenなどのツールを使用して、ローカルマシン上でSSHキーペアを生成すると、id_rsa.pubという名前のファイルが生成されます。このファイルが公開鍵であり、リモートサーバーに登録されます。
  2. id_rsa (秘密鍵):
    • ローカルマシンで生成されます
    • 同様に、SSHキーペアを生成すると、id_rsaという名前のファイルが生成されます。このファイルが秘密鍵であり、クライアント側で認証に使用されます。この秘密鍵は、厳重に保管される必要があります。
  3. authorized_keys:
    • リモートサーバーに配置されます
    • リモートサーバーには、認証を許可する公開鍵が含まれるauthorized_keysファイルが存在します。このファイルには、リモートサーバーにアクセスを許可するために、クライアント側から送信された公開鍵が追加されます。

したがって、SSHキーペアの生成と配置の一般的なパターンは、ローカルマシンで生成された公開鍵がリモートサーバーに配置され、秘密鍵はクライアント側のローカルマシンに残されることです。