OmniAICreator/Qiita-1.07M huggingface dataset:
PlayCanvasのコードエディターでコード補完をする

PlayCanvas標準のコードエディタを利用している場合にコード補完が効かない場合があります。その場合にはJSDocのアノテーションを追加することで標準のエディターでコード補完ができます。

```javascript
var Exmaple = pc.createScript('example');

Example.prototype.initialize = function() {
  // ① ※ pc.GraphNodeとされるためEntityのコード補完が効かない
  const cube = this.app.root.findByName("Root");
  cube.rotateLocal(0, 0.1, 0);

  // ② ※ pc.Entityとして扱われる
  /** @type {pc.Entity} */
  const typedCube = this.app.root.findByName("Root");
  typedCube.rotateLocal(0, 0.1, 0);
}
```

### ① / ②それぞれの違いについて

> ① ※ pc.GraphNodeとされるためEntityのコード補完が効かない
![スクリーンショット 2022-08-22 13.50.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257048/629276dd-71e5-10f6-5545-259083f6cb99.png)


> ② ※ pc.Entityとして扱われる
![スクリーンショット 2022-08-22 13.50.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257048/9137e0b9-9925-dcbe-24e3-4a67311c3f70.png)

#### 参考
変数以外にも関数などについても同様に補完ができます。記述方法などについてはこちらが参考になります。
- [JSDocリファレンス](https://www.typescriptlang.org/ja/docs/handbook/jsdoc-supported-types.html)

PlayCanvasのコンポーネント名などについてはこちらが参考になります。
- [API Reference PlayCanvas](https://developer.playcanvas.com/api/pc.html)
MongoDBのCRUD操作を整理

# きっかけ
* MongoDBのCRUD操作について、自分自身の整理のために一度まとめを実施

# 環境
* MongoDB V4.4.17

# DB作成・切り替え

```
# DB作成
use [DB名];

# DB切替
use [DB名]; (存在しないDBの場合は新規でDBが作成される)

# DB一覧確認
show dbs

#現在のDBを確認
db.stats()

```


# CRUD操作とは
CRUDはデータを操作する４つの基本機能の頭文字を取ったもの。
４つとは**Create(作成)、Read(読み取り)、Update(更新)、Delete(削除)**
 

# DBにデータの作成(Create)
* db.コレクション名.insertOne({key: value})　=>1つのデータのみ作成可能
* db.コレクション名.insertMany([{key: value}, {key: value}])　　=>複数のデータを作成可能
* db.コレクション名.insert([{key: value}, {key: value}])  =>1つと複数のどちらでも作成可能

```利用例
db.sample.insert([{name:'村上',team:'ヤクルト',homeRun:55},{name:'岡本',team:'巨人',homeRun:28},{name:'丸',team:'巨人',homeRun:27}])

// 複数のデータを作成する場合は配列の中にオブジェクトを作成すること
```


# DBのデータの読み取り(Read)
* db.コレクション名.findone(検索条件,射影) =>1つのデータのみ読取する場合に利用
* db.コレクション名.find(検索条件,射影)

```利用例
// 処理名
db.sample.find({name:'村上'})

// 結果
{ "_id" : ObjectId("632901c8ba80d3398393536e"), "name" : "村上", "team" : "ヤクルト", "homeRun" : 55 }
```


# DBのデータの更新(update)
* db.コレクション名.updateOne({検索条件}, {更新内容})  =>1つのデータを更新する場合に利用
* db.コレクション名.updateMany({検索条件}, {更新内容})　=>複数のデータを更新する場合に利用
```利用例
// 処理名
db.sample.updateOne({name:'村上'},{$set:{homeRun:60}})

// 結果
{ "_id" : ObjectId("632901c8ba80d3398393536e"), "name" : "村上", "team" : "ヤクルト", "homeRun" : 60 }
```


# DBにデータの削除(Delete)
*db.コレクション名.deleteOne({key: value}) =>単一データを削除する場合に利用
*db.コレクション名.deleteMany({key: value})　=>複数のデータを削除する場合に利用


# MongoDBで使える演算子

### 比較演算子
| name | 説明 |
| :-- | :-: |
| $eq | 一致するレコードを表示する(equal to) |
| $gt | より大きいレコードを表示する(greater than) |
| $gte | 以上のレコードを表示する(greater than or equal to) |
| $lt | より小さいレコードを表示する(less than) |
| $lte | 以下のレコードを表示する(less than or equal to) |

### 論理演算子
| name | 説明 |
| :-- | :-: |
| $and | 全ての条件にあてはまるレコードを表示する |
| $or | 一つでも条件にあてはまるレコードを表示する |
| $nor | 2つの条件のうちどちらにもあてはまらないレコードを表示する |
| $not | 不随した条件にあてはまらないレコードを表示する |


# 学んだこと
* MongoDBのDB作成方法・切り替え方法
* MongoDBにおけるCRUD操作方法
* MongoDBで使える演算子
AWS EC２へZabbix Managerをインストール

# はじめに
EC2(RHEL8)へZabbix Managerを導入するための、備忘録です。


# 0. 事前作業

下記作業については、事前に済ませておくこと。

```java:パッケージの更新
# yum update
```

```java:タイムゾーンの変更
# timedatectl set-timezone Asia/Tokyo
```

```java:ホスト名の変更
# hostname set-hostname Zabbix-Server
```

```java:ループバックアドレスへホスト名の追加
# vi /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4 Zabbix-Server
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
```


# 1. Apacheのインストール

```java:
# yum install httpd
```


# 2. MySQLのインストール・初期セットアップ

```java:
# yum install mysql-server mysql-devel
# systemctl start mysqld
# systemctl enable mysqld

# mysql -u root -p
password
mysql> set password for root@localhost = 'P@ssw0rd';
mysql> quit;
```


# 3. WEB ブラウザからのプラットフォーム確認

```java:サイトから自身のプラットフォームを確認する
https://www.zabbix.com/download
```


# 4. Zabbix Managerのインストール

```java:Zabbix リポジトリをインストール
# rpm -Uvh https://repo.zabbix.com/zabbix/6.2/rhel/8/x86_64/zabbix-release-6.2-3.el8.noarch.rpm
# dnf clean all
```

```java:PHP の DNF モジュールのバージョンを切り替える
# dnf module switch-to php:7.4
```

```java:Zabbix サーバー、フロントエンド、エージェントのインストール
# dnf install zabbix-server-mysql zabbix-web-mysql zabbix-apache-conf zabbix-sql-scripts zabbix-selinux-policy zabbix-agent
```

```java:初期データベースの作成
# mysql -u root -p
password
mysql> create database zabbix character set utf8mb4 collate utf8mb4_bin;
mysql> create user 'zabbix-user'@'localhost' identified by 'P@ssw0rd';
mysql> grant all privileges on zabbix.* to 'zabbix-user'@'localhost';
mysql> SET GLOBAL log_bin_trust_function_creators = 1;
mysql> quit;
```

```java:Zabbix サーバー ホストで、初期スキーマとデータをインポート
# zcat /usr/share/doc/zabbix-sql-scripts/mysql/server.sql.gz | mysql zabbix -u zabbix-user -p
```

```java:データベース スキーマをインポートした後、log_bin_trust_function_creators オプションを無効にする
# mysql -u root -p
password
mysql> SET GLOBAL log_bin_trust_function_creators = 0;
mysql> quit;
```

```java:Zabbix サーバーのデータベースを構成する
# vi /etc/zabbix/zabbix_server.conf 
DBUser=zabbix-user
DBPassword=P@ssw0rd
```

```java:Zabbix サーバーとエージェントのプロセスを開始する
# systemctl restart zabbix-server zabbix-agent httpd php-fpm
# systemctl enable zabbix-server zabbix-agent httpd php-fpm
```

```java:WEB UIへの接続
http://<IPアドレス>/zabbix/setup.php
```


# 5. その他(エラー確認)

・ホストの監視がいいえの場合
```java:アクセスログの確認
less /var/log/zabbix/zabbix_server.log
```
【備忘録】Git・Githubリポジトリ構成とメッセージ管理で参考にした情報

# はじめに
受託開発企業でシステムエンジニアをしている、@fusassyといいます。

受託開発プロジェクトにてチーム開発を進めるにあたり、バージョン管理でGit・Githubを採用することになり、Gitに関するルールを定めることになりました。Git・Githubについては、有益な記事が既に多くあります。プロジェクトで新たにルール策定をするにあたり、実際に参考にした記事・情報を備忘録として残します。

# Gitリポジトリ構成管理
https://qiita.com/KosukeSone/items/514dd24828b485c69a05

https://qiita.com/y-okudera/items/0b57830d2f56d1d51692

開発プロジェクトでは、開発・検証・本番の3種類のデプロイ環境先が用意されているとします。上記の記事におけるルールを少しアレンジした例を記します。ブランチを切る際に、「/」（スラッシュ） を使用することで、ブランチに階層構造を持たせることができます。master・develop・feature以外のブランチは、用途がハッキリ分かる名前にて命名し、適宜追加すれば良いと思います。 

```
master：本番環境デプロイ用。リリースした時点のソースコードを管理するブランチ。
develop：開発環境デプロイ用。masterから派生。開発作業の主軸ブランチ。
feature：developから派生する、各機能を実装するためのブランチ。 「feature/xx」、「feature/yy」のように命名。
validation：検証環境デプロイ用。develop（またはhotfix）から派生。実装を完了した後、リリースに向けて検証を実施するブランチ。
hotfix：masterから派生。リリースされた後に発生したバグに対し、緊急対応するためのブランチ。「hotfix/zz」、「hotfix/xyz」のように命名。
```

# コミットメッセージルール
https://qiita.com/konatsu_p/items/dfe199ebe3a7d2010b3e

https://www.tam-tam.co.jp/tipsnote/program/post16686.html

コミットメッセージのルール案も色々あるのですが、個人的には以下の書き方が気に入っています。

### コミットメッセージ雛形
```
＜Prefix＞：＜Subject＞
＜空白行＞
＜Body＞
＜空白行＞
＜Footer＞
```

### コミットメッセージ例
```
Fix: 表記ルールに従って文言を修正する

表記ルールでは「続きをよむ」は「続きを読む」になっていた。
詳しくは、表記ルールの〇〇を参照。

#test
https://example.com/
```

### Prefix
何をしたかを接頭辞で短く示す。Angular.js の開発者ガイドが情報源。
（https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#type）

```
feat:新しい機能
fix:バグの修正
docs:ドキュメントのみの変更
style:空白、フォーマット、セミコロン追加など
refactor:仕様に影響がないコード改善(リファクタ)
perf:パフォーマンス向上関連
test:テスト関連
chore:ビルド、補助ツール、ライブラリ関連
```

### Subject
何をしたか50文字未満の短い文章にします。チームメンバーが日本人開発者のみの場合、日本語表記がベターです。Subjectが長すぎることは、コミットの粒度が大きすぎる可能性が考えられます。（なお、GitHubでは50文字以上で警告、72文字以上で省略されるみたいです。）

### Body
何故それをしたのか、追加・修正等が必要だった理由を文章にします。チームメンバーが日本人開発者のみの場合、日本語表記がベターです。コミットメッセージに修正内容を書きつつ、コード側でも同様の内容を充分に説明しておくことが望ましいです。（自己文書化（＝コメントがなくてもコードの意図が分かる状態）がベスト。）

### Footer
補足情報を記載します。チームメンバーが日本人開発者のみの場合、日本語表記がベターです。


# Github Issue（Issues）の活用
https://qiita.com/janus_wel/items/ba47259f107b161c5727

受託開発プロジェクトにおいて上流工程の要件～設計フェーズでは、どうしてもExcelを多用する場面が多いため、Excel上での指摘・修正依頼が良いと思います。一方、実装フェーズにおける、コードレビュー後のプログラムの指摘や修正依頼については、Github Issueを利用する方が良いと思います。Markdownが利用できることも嬉しいです。ここではタイトルは簡潔に、コメントは丁寧を意識して書きます。もちろん、チームメンバーが日本人開発者のみの場合、日本語表記がベターです。


# .gitignoreの定義内容
https://qiita.com/inabe49/items/16ee3d9d1ce68daa9fff

https://qiita.com/ljourm/items/39856bbda20e2b4f2594

追跡対象にしたくないファイルを定義します。.gitignoreで指定するファイルはパターン化されますので、一度決めてしまえば類似プロジェクトで流用可能になります。

# さいごに
以上、Git・Githubを利用する際のルールについて、情報を整理させていただきました。実際にアサインされた受託開発プロジェクトでも、これらのルールを基本として適用し、上手く機能しています。もし運用で新たに課題が発生した場合は、その解決施策についても随時、追記をしていきたいと思います。
Dell PowerEdge のファンコントロール

オフィスに置いたPoweredgeのサーバーのファンがうるさいので調整した。
よく忘れるのでメモ

12世代、13世代で確認済み
- [Dell EMC PowerEdgeサーバーの世代を識別する方法 \| Dell 日本](https://www.dell.com/support/kbdoc/ja-jp/000137343/how-to-identify-which-generation-your-dell-poweredge-server-belongs-to)

## うるさい原因

サードパーティーのPCIeカードを追加したりするとだめらしい

> 現象
非標準の PCIe アダプタは、冷却が不十分なために加熱またはスロットリングを行います。
原因
PCIe カードなどの追加のハードウェアが追加された場合、追加の冷却が必要になる場合があります。熱制御アルゴリズムは、サードパーティ製の PCIe カードに対して十分な冷却を提供しない場合があります。
>[IDRAC7 および iDRAC8 のファン速度オフセットの調整 \| Dell 日本](https://www.dell.com/support/kbdoc/ja-jp/000138639/%E3%83%95%E3%82%A1%E3%83%B3%E9%80%9F%E5%BA%A6%E3%81%AE%E3%82%AA%E3%83%95%E3%82%BB%E3%83%83%E3%83%88-%E7%AC%AC12%E4%B8%96%E4%BB%A3%E3%81%AE%E3%82%B5%E3%83%BC%E3%83%90%E3%82%92%E8%AA%BF%E6%95%B4%E3%81%97%E3%81%BE%E3%81%99)

### 回避法
サードパーティースロットリングを強制OFF
- [iDrac 7 and 8: Lower fan noise on Dell Servers \- Angry Sysadmins](https://angrysysadmins.tech/index.php/2022/01/grassyloki/idrac-7-8-lower-fan-noise-on-dell-servers/)

iDRACにSSHログインして `racadm set system.thermalsettings.ThirdPartyPCIFanResponse 0` する。
```sh
/admin1-> racadm get system.thermalsettings.ThirdPartyPCIFanResponse
[Key=system.Embedded.1#ThermalSettings.1]
ThirdPartyPCIFanResponse=Enabled

/admin1-> racadm set system.thermalsettings.ThirdPartyPCIFanResponse 0
[Key=system.Embedded.1#ThermalSettings.1]
Object value modified successfully
``` 

## ファンスピードを手動調整

ipmitoolで直接変更

```sh
# print temps and fans rpms
ipmitool -I lanplus -H <iDRAC-IP> -U <iDRAC-USER> -P <iDRAC-PASSWORD> sensor reading "Ambient Temp" "FAN 1 RPM" "FAN 2 RPM" "FAN 3 RPM"
#
# print fan info
ipmitool -I lanplus -H <iDRAC-IP> -U <iDRAC-USER> -P <iDRAC-PASSWORD> sdr get "FAN 1 RPM" "FAN 2 RPM" "FAN 3 RPM"
#
# enable manual/static fan control
ipmitool -I lanplus -H <iDRAC-IP> -U <iDRAC-USER> -P <iDRAC-PASSWORD> raw 0x30 0x30 0x01 0x00
#
# disable manual/static fan control
ipmitool -I lanplus -H <iDRAC-IP> -U <iDRAC-USER> -P <iDRAC-PASSWORD> raw 0x30 0x30 0x01 0x01
#
# set fan speed to 0 rpm
ipmitool -I lanplus -H <iDRAC-IP> -U <iDRAC-USER> -P <iDRAC-PASSWORD> raw 0x30 0x30 0x02 0xff 0x00
#
# set fan speed to 20 %
ipmitool -I lanplus -H <iDRAC-IP> -U <iDRAC-USER> -P <iDRAC-PASSWORD> raw 0x30 0x30 0x02 0xff 0x14
#
# set fan speed to 30 %
ipmitool -I lanplus -H <iDRAC-IP> -U <iDRAC-USER> -P <iDRAC-PASSWORD> raw 0x30 0x30 0x02 0xff 0x1e
#
# set fan speed to 100 %
ipmitool -I lanplus -H <iDRAC-IP> -U <iDRAC-USER> -P <iDRAC-PASSWORD> raw 0x30 0x30 0x02 0xff 0x64
```
[Dell Fan Noise Control \- Silence Your Poweredge : homelab](https://www.reddit.com/r/homelab/comments/7xqb11/dell_fan_noise_control_silence_your_poweredge/)

ただこれだと温度に対して脆弱になるので、温度モニタと回転数コントロールをセットで導入したほうがいい。
MacでUiPathを動かす

# はじめに
前回の記事で、MacOSにUiPath Assistantをインストールしてみたので、今回はMacOSでUiPathを動かしてみます。

https://qiita.com/shuy/items/d3b020bc02b1b5313c99


# つかうもの
※ クラウド環境は2022年9月時点のもの
* UiPath Assistant　v2022.4　※Mac版
* UiPath Studio　v2022.4
* Automation Cloud（Orchestrator）　※ Community版


# ワークフローを作る
Macで動くワークフローを作るには、WindowsのPCに入れたStudioを使い、プロジェクト作成時に「対応OS」を「クロスプラットフォーム」にします。

:::note warn
ワークフローを作成する環境（Windows）と動かす環境（Mac）が全く異なるので、実装する際はその違いに注意する必要があります。
:::

![Studio1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89445/e69d8a05-7bf1-f16a-6dca-13aa2f54db42.png)

クロスプラットフォームで作成されたプロジェクトでは、デフォルトでインストールされるパッケージは以下となります。
因みに対応OS「Windows」で作成したプロジェクトでは、UiPath.WebAPI.Activitiesの代わりに、UiPath.Excel.ActivitiesとUiPath.Mail.Activitiesがインストールされます。

* UiPath.System.Activities
* UiPath.UIAutomation.Activities
* UiPath.WebAPI.Activities

![Studio2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89445/3d8730ea-042d-d6b3-ee62-596f5f919d9c.png)

UiPath.System.ActivitiesとUiPath.UIAutomation.Activitiesについて、同じ.NET5/6アーキテクチャで動く、対応OS「Windows」と比べてみると、内包するアクティビティの数が全く違います。
クロスプラットフォームの場合、自動化できるのはOSに依存しない範囲に限られるため、使えるアクティビティが大幅に制限されています。

|パッケージ|クロスプラットフォーム|Windows|
|--|--:|--:|
|UiPath.System.Activities 22.4.4|103|131|
|UiPath.UIAutomation.Activities 22.4.7|16|150|

↓クロスプラットフォームのUiPath.UIAutomation.Activities（22.4.7）に含まれるアクティビティ
最低限のブラウザ操作は自動化可能です。Macでブラウザの自動化をする場合、Safariには対応していないので、MacにChromeとアドオンをインストールしておきます。
![Studio3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89445/33033352-db99-81f3-bb3e-052b70b91998.png)

クロスプラットフォームでも、UiPath.Excel.ActivitiesやUiPath.Mail.Activitiesなどをインストールすることは可能ですが、他パッケージ同様、アクティビティの数は制限されています。

↓クロスプラットフォームのUiPath.Excel.Activities（2.12.3）に含まれるアクティビティ
MS Office for Macには対応していないため、「システム > ファイル > ワークブック」カテゴリのアクティビティしか使えません。
![Studio4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89445/baf5f70e-5f08-e7d8-7e80-f77168b15353.png)


# ワークフローを動かす
作成したプロジェクトをOrchestratorへパブリッシュします。

:::note info
Mac版ではローカルパッケージフィードは使えないので、必ずOrchestratorへパブリッシュする必要があります。
:::

Mac版のAssistantでは、対応OSが「クロスプラットフォーム」で作成されたプロセスしか表示されません。
Windows版のAssistantでは、すべて表示されます。

![Assistant1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89445/4510d777-61dd-383b-37ed-8a6fe18942b7.png)

また、Mac版のAssistantでは、PiPでの実行ができません。
![Assistant2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89445/164402cd-a380-2154-18a6-c0f2b096af94.png)


# おわりに
Mac版に対応しているアクティビティは、Windows版に比べると少ないですが、正直なんとかなるレベルかと思いました。
Windowsに比べMacを普段使いしているビジネスユーザは多くないため、自動化のニーズがあると言えない領域ですが、StudioもMac対応したら、もう少し活発になるかもしれませんね。
cscの作法 その276

# 概要
cscの作法、調べてみた。
練習問題やってみた。

# 練習問題
RegisterRawInputDevices使ってください。

# 方針
- マウスとキーボードやる。


# サンプルコード


```
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace App
{
	public partial class Form1 : Form {
		[DllImport("user32.dll")]
		private static extern int RegisterRawInputDevices(RawInputDevice[] devices, int number, int size);
		[DllImport("user32.dll")]
		private static extern int GetRawInputData(IntPtr rawInput, int command, out RawInput data, ref int size, int headerSize);
		private struct RawInputDevice {
			public short UsagePage;
			public short Usage;
			public int Flags;
			public IntPtr Target;
		}
		private struct RawInputHeader {
			public int Type;
			public int Size;
			public IntPtr Device;
			public IntPtr WParam;
		}
		private struct RawInput {
			public RawInputHeader Header;
			public short a;
			public short b;
			public short c;
			public ushort d;
			public ushort e;
			public int f;
			public int g;
			public int h;
		}
		private TextBox textBox1;
		public Form1() {
			textBox1 = new TextBox();
			textBox1.Location = new System.Drawing.Point(30, 30);
			textBox1.Multiline = true;
			textBox1.Size = new System.Drawing.Size(200, 40);
			textBox1.TabIndex = 2;
			Controls.AddRange(new Control[] {
				textBox1
			});
			const int RIDEV_INPUTSINK = 0x00000100;
			int size = Marshal.SizeOf(typeof(RawInputDevice));
			RawInputDevice[] devices = new RawInputDevice[2];
			devices[0].UsagePage = 1;
			devices[0].Usage = 2;
			devices[0].Target = this.Handle;
			devices[0].Flags = RIDEV_INPUTSINK;
			devices[1].UsagePage = 1;
			devices[1].Usage = 6;
			devices[1].Target = this.Handle;
			devices[1].Flags = RIDEV_INPUTSINK;
			RegisterRawInputDevices(devices, 2, size);
		}
		private void log(string msg) {
			Console.WriteLine(msg);
			textBox1.Text = msg;
		}
		protected override void WndProc(ref Message m) {
			const int WmInput = 0xFF;
			if (m.Msg == WmInput)
			{
				const int RidInput = 0x10000003;
				int headerSize = Marshal.SizeOf(typeof(RawInputHeader));
				int size = Marshal.SizeOf(typeof(RawInput));
				RawInput input;
				GetRawInputData(m.LParam, RidInput, out input, ref size, headerSize);
				string str = "";
				if (input.Header.Type == 0)
				{
					short ButtonData = input.c;
					sbyte delta = (sbyte) (input.d);
					int LastX = input.f;
					int LastY = input.g;
					str = string.Format("{0},{1},{2},{3},{4},{5}\r\n", "Mouse", input.Header.Device, LastX, LastY, ButtonData, delta);
					log(str);
				}
				else if (input.Header.Type == 1)
				{
					string message = "";
					ushort VKey = input.d;
					if (input.e == 256)
					{
						message = "KeyDown";
					}
					else if (input.e == 257)
					{
						message = "KeyUp";
					}
					str = string.Format("{0},{1},{2}\r\n", message, input.Header.Device, VKey);
					log(str);
				}
			}
			base.WndProc(ref m);
		}
		[STAThread]
		public static void Main() {
			Application.Run(new Form1());
		}
	}
}





```

以上。
HTTPの社内研修（モブワーク）でデモしたことまとめ

## はじめに

株式会社船井総研デジタルの よもぎた と申します。所属はインフラストラクチャーチームになります。

2022年9月に中途で入社しました。日々研修に励んでおります。中途採用＝即戦力・即現場投入という先入観があったため、ホントにいいのか？と若干困惑気味です。

先日、開発チームのHTTPのモブワークに参加してツールの紹介とデモ・ハンズオンをしたので、その内容を簡単ですがご紹介したいと思います。なお、参加者全員がリモート参加でした。

## ツールの紹介

開発チームはWebアプリの研修をしています。そこで、LinuxのコマンドラインからHTTP(S)アクセスに使えるツールを紹介しました。

具体的には、wget、curl、ncとその派生版、opensslコマンドのs_clientコマンドです。

w3mとかのテキストベースのWebブラウザで阿部寛のページを表示するデモをやろうかと思いましたが、ボツにしました。

紹介するにあたって軽く調べなおして、自分でも新たに知ったことが2つほどありました。

* wgetは、いまwget2の開発が始まっている。wgetも更新されているので、wgetがオワコンというわけではないようですが、どうなっていくのか、たまに気にしたいと思います。

* ncの最新版リリースは1996年3月。もう25年以上前です。そのツールが現役というのもすごいですが、一緒に研修している人に **その時生まれていなかった人がいる** という事実に震えました。

## デモ・ハンズオン

### 拡張子の違いによってWebブラウザでの表示に違いが出るのを見る

Webサーバにデモ用のHTMLファイルを置きます。内容はタイトルとボディに1行メッセージだけという簡単なものです。そのファイルを、拡張子を ```.txt``` に変えてコピーします。

```Bash
cp -pv demo.html demo.txt
```

WebサーバはUbuntu上のApache2.4です。まずは、それぞれのファイルにWebブラウザでアクセスしてもらいました。拡張子 ```.html``` は普通に見えますが、拡張子 ```.txt``` はファイル全体がテキストで表示されます。

curlでアクセスしてもらって、種明かしをしました。

```Bash
curl -i https://<DemoDomain>/demo.html
curl -i https://<DemoDomain>/demo.txt
```

もうお分かりと思いますが、レスポンスヘッダのうち ```Content-Type``` ヘッダが異なり、Webブラウザでの表示が変わるというのを見てもらいました。

その後、ファイルをダウンロードして、ハッシュ値を比較して同じファイルであることも確認してもらいました。

```Bash
curl -o demo.html https://<DemoDomain>/demo.html
curl -o demo.txt  https://<DemoDomain>/demo.txt
md5sum demo.html demo.txt
```

### エコーサーバにアクセスしてWebブラウザのリクエストの違いを見る

まずは、Webブラウザから受け取ったリクエストをそのまま出力するエコーサーバ（スクリプト）を用意します。それに手持ちで使っていないドメイン名を割り当てました。

そして、Webブラウザで次のURLにアクセスしてもらいました。

```
http://<DemoServerIPAddress>/echoscript
http://<DemoDomain>/echoscript
```

Webブラウザが送信しているリクエストのうち、 アクセスするURLによって ```Host``` ヘッダが異なることを確認してもらいました。実際にはデモ用ドメインは複数用意して、みんな同じIPアドレスに向けました。


### Wiresharkで通信を見てみる

実際のコンテンツをHTTPで配信しているサイトを探すより、自分でたてた方が256倍早い、と思い、自分でクラウド上にWebサーバを立てて、それにアクセスした様子をパケットキャプチャしてみてもらいました。まあ、実際には上記のエコーサーバなのですが。

Wiresharkよりtcpdumpがいい！という人がいて、将来有望だと思いました。

## やり終えての言い訳など

ここで紹介するまでもないデモ・ハンズオンもすこしやりました。
やることが決まってから二日後に実施、という強行スケジュールだったのが大変でした。（完全に言い訳。とはいえ、実際に手を動かした時間はそれほどでもなく、何を見せるか考えるほうに時間がかかってます）。とはいえ、自分で言い出したことなので、なんとか最低限の形にはなってよかったです。

内容が体系化されてなくて抜け漏れがあるとか、ツッコミどころ満載だと思います。たとえばBasic認証に触れてないとか。（最低限の形になったとは一体・・・）。次の機会に活かせればと思います。（もしあれば、ですが）
当日の説明も至らないところがあったな、と反省してます。

次は、複数人で内容を揉んで準備してやりたいですね。（これを読んでくれるであろう会社のエライ人向け）
Json文字列の変換

元の質問 : [List<Map<String, Object>>をapex:pageBlockTableで表示させる](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000A9AYl)


今回のポイントはdeserializeStrictの中でList変数として呼び出しているところだ。
こんな使い方ができるとは思ってなかった...

```
    public static void test002() {
        
        String theJsonString = '[{"id":1, "name":"Abc_SS", "description":"Abc", "address":"Abc"}, {"id":2, "name":"sales", "description":"sales", "address":"Abc"}]';
        
        LIST<JsonTestClass> JyuhatyuList = (LIST<JsonTestClass>)JSON.deserializeStrict(theJsonString,LIST<JsonTestClass>.class);//Json-->Object
        system.debug(Logginglevel.INFO,' === JyuhatyuList ==>>  '+ JyuhatyuList );
        
    }
    
    
    public class JsonTestClass {
        public String id;
        public String name;
        public String description;
        public String address;
    }
```
PHP デバック方法 var_dump


## はじめに

PHPのデバックに必ず使うといってもいいような方法とちょっとした工夫もつけくわえます。

## var_dump使ってみる

```
<?php
$array = array('apple', 'orange', 'Grape', 'melon');
var_dump($array);
?>
```
ブラウザで結果はこんな感じで返ってきます。
array(4) { [0]=> string(5) "apple" [1]=> string(6) "orange" [2]=> string(5) "Grape" [3]=> string(5) "melon" }

```
<?php
$array = array('apple', 'orange', 'Grape', 'melon');
echo '<pre>';//ここを追加
var_dump($array);
echo '</pre>';//ここを追加
?>
```

これをつけると

```
array(4) {
  [0]=>
  string(5) "apple"
  [1]=>
  string(6) "orange"
  [2]=>
  string(5) "Grape"
  [3]=>
  string(5) "melon"
}
```

みやすくなるのでひと手間ですがおすすめです。

## 最後に

先程の変更前と変更後をまとめました

```
//変更前//
<?php
$array = array('apple', 'orange', 'Grape', 'melon');
var_dump($array);
?>

結果
array(4) { [0]=> string(5) "apple" [1]=> string(6) "orange" [2]=> string(5) "Grape" [3]=> string(5) "melon" }

//変更後//
<?php
$array = array('apple', 'orange', 'Grape', 'melon');
echo '<pre>';//ここを追加
var_dump($array);
echo '</pre>';//ここを追加
?>

結果
array(4) {
  [0]=>
  string(5) "apple"
  [1]=>
  string(6) "orange"
  [2]=>
  string(5) "Grape"
  [3]=>
  string(5) "melon"
}
```

データが多くなるほど確認しやすくなるので使い分けてもいいかなと思います。
oVice をちょっとだけ便利にする chrome 拡張を作った話

# oVice とは
ブラウザ上でリアルに近い感覚でコミュニケーションが取れるバーチャルオフィスツールです。
私が所属する[ユニークビジョン株式会社](https://qiita.com/organizations/uniquevision)ではリモート勤務時に利用しています。

https://ovice.in/ja/

# oVice あるある言いたい
リモートワーク中

？？「白石さん！今ちょっとお時間よろしいでしょうか？」

白石「あ、oVice で誰か私に話しかけているな。**でもタブを開きすぎて oVice をどのタブで開いているか分からない**...」

？？「白石さん！聞こえていますか？ 今いないかな...」

白石「聞こえているんだけどタブが見つからない！あ、あった、これか！」

白石「タブを開いて、ミュートを解除して… はい！聞こえています！どうしましたか？」

「...」

白石「あ、もういなくなってる…」

# oViSwitch で解決
こういうやり取りが 100 回はあったので、chrome 拡張を作ることで解決しました。
その名も、**oViSwitch** です。

https://chrome.google.com/webstore/detail/oviswitch/ldohahnbhclmpimkninjoellgemepljl?hl=ja

# できること
機能は超シンプルです。

### アイコンクリックで oVice タブにジャンプ & ミュートの切り替え
![qiitademo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474068/7304e0c4-4596-548a-a65c-3057d85d8707.gif)


### `Alt + P` でジャンプする直前のタブに戻る
![qiitademo2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474068/14d59eba-8f55-8694-916f-225a7249e0cf.gif)

### 例えば
こんな感じのときに便利です！
* Qiita の記事を読んでいるときに呼びかけられたので `Alt + O` で oVice のタブにジャンプ
* 更に `Alt + O` でマイクの ON / OFF 切り替え
* `Alt + P` で元のタブに戻る

# 開発方法
私は Vue.js を使い慣れているので、Vue.js で Chrome 拡張を簡単に書ける [vitesse-webext](https://github.com/antfu/vitesse-webext) というフレームワークを使って開発しました。

詳しい使い方は、下記の記事で解説しています。

https://qiita.com/punkshiraishi/items/7ec1448984599d0ec40f

フレームワークを使わない、最小構成での chrome 拡張開発は下記の記事が参考になると思います。

https://qiita.com/punkshiraishi/items/5eca74202f6445025650

# ソースコード
ソースコードも公開しています。プルリクエストや、バグ報告、要望などお待ちしております！

https://github.com/punkshiraishi/oviswitch

# 最後に
フロントエンド周りのことをよく呟いています。よければフォローお願いします。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ユニークビジョンという会社のエンジニアです。<br>フロントエンド開発と品質向上に取り組んでいるので、そのあたり興味ある方はフォローしていただけると嬉しいです。<br><br>品質の高いサービスを提供し続ける会社であるために／品質向上チーム <a href="https://t.co/vI7YsKL6QW">https://t.co/vI7YsKL6QW</a></p>&mdash; シライシ@ユニークビジョン (@punksy2) <a href="https://twitter.com/punksy2/status/1576934123670630404?ref_src=twsrc%5Etfw">October 3, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
PHP削除機能実装方法

PHPの削除機能が実装できたため、備忘録として説明する。

```php

<form method="get" action="delete.php">
    <input type="hidden" name="id" value="<?php echo h($todo["id"]) ?>">
    <button >削除</button>
</form>

```

※前提として＄["id"]にidが入っている前提。
↑
データベースで「id」を入れること、
（例：    $stmt = $pdo->query("SELECT name, brith, department_id,
　　       account, password, id FROM users"); ）

※<form method="get" action="delete.php">
がgetであることを確認する。
※「　form　」タグを作り「　delete.php　」でPOST送信する。



```php

//①DBベース接続
$pdo = new PDO("mysql:charset={$char_set};dbname={$db};host={$host}", $user, $password);


// ②新規作成 start このページにアクセスしたら、
// ゲットデータを取得する。
if(isset($_GET["id"])){  //変数に値が入っているかどうかを確認するためのisset関数
  $id = $_GET["id"];  //main.phpで入れた内容が入ってくる。  

//→POSTに変更するとうまくいく場合がある。

    try {
      $pdo->beginTransaction();

      // ③データを登録するSQL
      $stmt = $pdo->prepare("DELETE FROM todo_list WHERE id=:id");
      
      // ④値をセット
      $stmt->bindParam( ':id',$id,PDO::PARAM_STR);
 
      // ⑤SQL実行
      $res = $stmt->execute();
  
      // コミット
      if( $res ) {
        $pdo->commit();
      }
  
    } catch(PDOException $e) {
  
      // エラーメッセージを出力
      echo $e->getMessage();
      
      // ロールバック
      $pdo->rollBack();
    }
};

//⑤．データ登録処理後
if($res==false){
    sql_error($stmt);
  }else{
    redirect("main.php");
  }
?>
```

①DBベース接続する
②ゲットデータを取得する
③SQLにデータ登録する
③値をセットをする
④SQLの実行をする
⑤データ登録後の処理をする


※IDの動きを意識しながら、作業を行うとうまくいく。
Bitbucketでリポジトリのクローンができない

## 問題
```:コマンド
git clone git@bitbucket.org:〇〇.git
```
を打ったら
```
git@bitbucket.org: Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
```
というエラー

## 解決方法
BitbucketのPersonak settingsからアプリパスワードを追加する
![スクリーンショット 2022-09-20 8.24.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223280/4ebc380d-ec59-00c9-489c-50d2f1361663.png)
Ubuntu22.04.1LTS環境でAndroid Emulatorのサウンドを有効にするとyoutubeなどの音声にノイズが乗る問題

## 環境
#### マシンスペック
- Ryzen5 5600X
- B550M AORUS ELITE
- Radeon RX6600XT
- DDR4-3200 8gb × 4
- M.2 Gen3 1TB（デュアルブート）

```bash
→ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.1 LTS"
```
- サウンドデバイスに問題がないことは同じマシンの別osで確認済み

## 解決策
### Solution1
https://stackoverflow.com/questions/48484850/strange-sound-produced-by-android-emulator-when-turned-on-in-android-studio
![Screenshot_1663625557.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648231/9f96ffa2-10f7-8756-c430-787139ab687e.png)

ココらへんのother sounds and vibrationsをすべてoffにして、emulatorを再起動する。

### Solution2
https://ubuntuforums.org/showthread.php?t=1789459&p=10974454#post10974454

```bash
sudo vim /etc/pulse/default.pa

...
load-module module-udev-detect tsched=0
# tsched=0を追加する
...

# その後以下のコードを実行する
pulseaudio -k
```

```bash
sudo vim /etc/pulse/daemon.conf

...
default-sample-rate = 48000
# 44100を48000に変更する
...

# その後以下のコードを実行する
pulseaudio -k
```
おそらくこれで解決するはずです。
Promiseで定義したコールバックの実行順序

Promiseを定義したときにasync/awaitするとコードを見たまま上から下に実行されるので難しくないのですが、then/catchで後の処理を定義するとどのタイミングでコールバックが実行されるのかわかっていませんでした。

ちょっと調べてみたのでまとめます。

# サンプル

aとbというPromiseを作ってそれぞれの関数の中でログを出力してみます。
また、各定義の間と、aとbをPromise.allした後にもログを出力します。

```TypeScript
const a = new Promise((resolve, reject) => {
  console.log('a');
  resolve('a: resolve');
})
  .then(() => { console.log('a: then'); });

console.log('aの後')

const b = new Promise((resolve, reject) => {
  console.log('b');
  resolve('b: resolve');
})
  .then(() => { console.log('b: then'); });

console.log('bの後')

Promise.all([a, b])
  .then(() => { console.log('c: then'); });

console.log('d');
```

結果は次のようになりました。

```
[LOG]: "a" 
[LOG]: "aの後" 
[LOG]: "b" 
[LOG]: "bの後" 
[LOG]: "d" 
[LOG]: "a: then" 
[LOG]: "b: then" 
[LOG]: "c: then"
```

ふむ、thenの中の出力は定義後のdの後に表示されました。

# どうしてこうなった

書き慣れてる人はこんな挙動は当然よく見てて知ってると思うのですが、どういう仕様なんでしょう？

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise

https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Using_promises

これらのページを読んでたら下のように定義されていました。

> 保証
> 旧来のコールバック渡しとは異なり、プロミスでは以下のことが保証されています。
> 
> - then() によって追加されたコールバックは、現在の JavaScript イベントループの現在の処理の完了より前には決して呼び出されません。

サンプルに書いたような状況だとdを出力する箇所が完了してからすべてのthenが処理されるという感じですかね。
async/awaitとthen/catchをなんとなくで書き分けないで状況によって書き分けられるようになりたいですねー。
「アウトプット大全」を読んでアウトプットする

[学びを結果に変えるアウトプット大全 (サンクチュアリ出版) | 樺沢紫苑 |本 | 通販 | Amazon](https://www.amazon.co.jp/dp/4801400558)
![](https://images-fe.ssl-images-amazon.com/images/I/51FKGFMH4tL._SY291_BO1,204,203,200_QL40_ML2_.jpg)

自己啓発本と言ってしまうとその類であることはたしかなのだが、著者の方が

> 「メルマガ、毎日発行13年」「Facebook、毎日更新8年」
「YouTube、毎日更新5年」「毎日3時間以上の執筆11年」
「年2~3冊の出版、10年連続」「新作セミナー、毎月2回以上9年連続」

とのことなので胡散臭いことを言っているというよりは、「確かに、ここまでやれば変わるよな...」という紛れもない事実をまとめていると思う。

なのでそのすべてをすぐに「じゃあ自分も！」とはいかないのだが、その何分の一かでも真似ることができたら自分にも良い影響は確かにあるだろうな、と思う。そのエッセンスがまとまっている本だと思った。

## その要点

### アウトプットの基本法則

- インプットは自分の内面を変えるもの
- アウトプットは、現実世界に働きかけて変えるもの
    - アウトプットとは運動
    - アウトプットとはフィードバックサイクルを回すもの
    - なので、アウトプットとは自己成長につながるもの

### 科学に裏付けられた、伝わる話し方

- アウトプットの一つ「話す」
- 「話す」ことも、記憶の定着や、自分の知識に大きく貢献する
- 事実だけではなく、感想や意見も添えて良い
    - 「ラーメン屋に行ってきた」だけでなく、～～が美味しかった、好きだ、など
- 自分に影響するものなので、なるべくポジティブに話すのが当然良い影響がある
- 断るということをしても良い
- 怒るは単に自分に向けたもの
- 叱るは相手に向けて向上をうながすもの

### 能力を最大限に引き出す書き方

- もう一つのアウトプット「書く」
- ツールは何でも良い
- 早く書くでも良い
- TODOリストを書く
- 気づきをメモする
- ひらめく
- 引用する、要約する
- 目標を書く
- 構想をメモする

### 圧倒的に結果を出す人の行動力

- 行動する
- 教える
- 楽しむ

### アウトプットを高める7つのトレーニング方法　

- 日記を書く
- 健康を記録する
- 読書感想文を書く
- 発信する
- SNSに書く
- ブログに書く
- 趣味について書く

## 参考
[【要約】学びを結果に変えるアウトプット大全 - Qiita](https://qiita.com/i-tanaka730/items/78b6014f8fc3f2ab6954)
[エンジニアが「アウトプット大全」を読んだ感想 - Qiita](https://qiita.com/watatakahashi/items/b08550306a343214add3)
[学びを結果に変えるアウトプット大全　個人的な大事だと思ったとこまとめ - Qiita](https://qiita.com/ganyariya/items/d1aa94925f793a7982b9)

以上です～
JavaScript 忘備録 ~効果音の鳴らし方

# JavaScriptで効果音の鳴らし方
JavaScriptを用いて効果音を付けたいときのプログラムを書いていきます。howlerというライブラリを使います。
# HTML側 
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.1.2/howler.min.js"></script>
```
# JavaScript側
```javascript
//タイプ音読み込み
const sound = new Howl({
  src: ['./sound/type.mp3']; //パスは変えて下さい
});
sound.play();// 任意タイミングで
```
2022/9/20主にITとかセキュリティの記事

Magent向けFishPigプラグインがサプライチェーン攻撃の標的に - 悪意あるコード混入(9/18)
https://news.mynavi.jp/techplus/article/20220918-2456523/

国税庁から「税金を払え」とSMSが大量に!?(9/17)
https://ascii.jp/elem/000/004/106/4106005/?rss

YouTube経由で拡散するゲーマーを標的とするマルウェア、対象ゲームの確認を(9/18)
https://news.mynavi.jp/techplus/article/20220918-2456812/

Windows 10 バージョン 21H1、12月にサービス終了(9/18)
https://www.zaikei.co.jp/article/20220918/690006.html

スノーデン事件で関係を悪化させた英米の諜報機関(9/18)
https://sputniknews.jp/20220918/12969181.html
アルゴリズムでよく使う手法（Ruby)

# アルゴリズムでよく使う手法まとめ
paizaでアルゴリズムの練習問題でよく使い、よくつまずくポイントを残します。

## 向きについて
マスを進んでいく問題で向きを変えながら一マスずつ進む問題での向き判定

```rb
# 左から上、右、下、左
move = [[-1, 0], [0, 1], [1, 0], [0, -1]]

# 向き
now = 0

# 初期位置
y, x = [3, 3]

# 向きによってy, xを変える
# 向きの値を4で割り、その値によってmoveに入っている変化する値を取得できる。
ny = y + move[now % 4][0]
nx = x + move[now % 4][1]

# 方向変換がある場合、値を1増減することで４で割って出るあまりの値を変える。
if d == 'L'
  now -= 1
else
  now += 1
end

# 枠が指定されている場合はみ出さないように判定する
h = 10
w = 10
0 <= ny && ny <= h - 1 && 0 <= nx && nx <= w - 1
```

## 累積和
**配列の任意の合計を求める**

```rb
array = [1, 2, 3, 4, 5, 6]
s = [0]
array.each do |i|
  s << s[-1] + i
end 
#[0, 1, 3, 6, 10, 15, 21]
```

**いもす法**
一つ前の要素との比較でどれだけ増減しているのかを記録した配列を作成し、その配列を使い累積和を作成する。
例題
店に0〜１０時の間の１時間ごとに何人の客がいたかを調べる
客ごとの在席時間は2~5, 3~4, 8~10とする。

```rb
# 店の営業時間
n = 10

# 客の在席時間
people = [[2, 5], [3, 4], [7, 9]]

# 一時間前との比較
s = Array.new(n + 1, 0)
people.each do |e, l|
  s[e] += 1
  s[l + 1] -= 1
end

# s == [0, 0, 1, 1, 0, -1, -1, 1, 0, 0, -1]

times = Array.new(n + 1, 0)
times[0] = s[0]
1.upto(n) do |i|
  times[i] = times[i - 1] + s[i]
end

# times == [0, 0, 1, 2, 2, 1, 0, 1, 1, 1, 0]
```

## 二次元の累積和
**縦横の累積和**

```rb
s = Array.new(h + 1) { Array.new(w + 1, 0) }
0.upto(h - 1) do |y|
  0.upto(w - 1) do |x|
    # ゼータ変換
    s[y + 1][x + 1] = a[y][x] + s[y][x + 1] + s[y + 1][x] - s[y][x]
  end
end
```

**任意の長方形の領域の総和**

```rb
section.each do |a, b, c, d|
  puts s[d][c] + s[b - 1][a - 1] - s[d][a - 1] - s[b - 1][c]
end
```
[python]ニコニコ動画のダウンロード mylistから一括

ニコニコ動画のダウンロード　マイリストから一括
ただのメモに近い。

```python
# -*- config: utf-8 -*-
#------------------------------------------------------------------------------
# import
#------------------------------------------------------------------------------
from niconico import NicoNico
import pprint
import concurrent.futures
import time

# 並列用のラッパー
def wapper_x(line_list, max, b):
    for i in range(len(line_list)):
        if i % max == b:
            url = line_list[i][1]
            with client.video.get_video(url) as video:
                video.download(f"{video.video.id} - {video.video.title}.mp4")
    
    return 0

URL = "<マイリストのURL>"
client = NicoNico()
for mylist in client.video.get_mylist(URL):
    line_list = []
    for line in mylist.items:
        line_list.append([line.video.id, line.video.url, line.video.title])
pprint.pprint(line_list, width=300)

futures = []
max = 5
executor = concurrent.futures.ThreadPoolExecutor(max_workers=max)
# concurrent execution
for a in range(max):
    #print(a)
    #wapper_x(line_list, max, a)
    futures.append(executor.submit(wapper_x, line_list, max, a))
    time.sleep(1)

# wait
for future in concurrent.futures.as_completed(futures):
    True

exit()
```
<Active Record> has_manyのsourceオプションはいつ使うのか

has_manyメソッドのsourceオプションは次の場合に使用します。

1. 多対多のアソシエーションに別名をつける
2. has_manyで指定するモデル名が重複している

例として、ユーザーが投稿を作成・いいねできる関連付けを行います。

#### いいねした投稿を取得する
```ruby
#models/user.rb
class User < ApplicationRecord
  has_many :posts
  has_many :likes
end

#models/like.rb
class Like < ApplicationRecord
  belongs_to :user
  belongs_to :post
end

#models/post.rb
class Post < ApplicationRecord
  has_many :likes
  belongs_to :user
end
```
上記のモデルにいいねした投稿を取得しようと`has_many :posts`としても、すでに存在するので書くことはできません。

そこで、`has_many :like_posts`と命名した上で、中間テーブルのLikesテーブルを通してPostsテーブルからデータを取得できるようにします。

```diff_ruby
#models/user.rb
class User < ApplicationRecord
  has_many :posts
  has_many :likes
+ has_many :like_posts, through: :likes, source: :post
end
```

![qiita-image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1881292/053db736-90b1-83ee-8377-7dc51705ef82.png)

この時、like.rbの`belongs_to :post`を参照してくれます。

自由に関連付け名を指定した場合、どこのテーブルからデータを取得すれば良いかを判断してくれないので、`source`オプションで指定してあげることで解決できます。

#### 投稿にいいねしているユーザーを取得する

また、ある投稿にいいねしているユーザーを取得したい場合は、
```diff_ruby
#models/post.rb
class Post < ApplicationRecord
  has_many :likes
  belongs_to :user
+ has_many :users, through: :likes
end
```
とします。
この場合、命名が重複しないので`users`のままでも大丈夫ですが、命名を変更する場合は`source`オプションを指定する必要があります。

sourceオプションは多対多のアソシエーションの場合ですが、一対多のアソシエーションの場合は`class_name`オプションで解決できます。

# class_nameオプション

上記の例をそのまま使用し、仮にmodels/user.rbで`has_many :posts`を`has_many :create_posts`としなければならなかったとします。

この場合、userテーブルとpostテーブルの関係は一対多なので、

```diff_ruby
#models/user.rb
class User < ApplicationRecord
- has_many :posts
+ has_many :create_posts, class_name: 'Post', foreign_key: :user_id
  has_many :likes
end
```
`class_name: 'Post'`とし、どこのテーブルを参照するのか、どの外部キーを参照するのかを指定する必要があります。

https://railsguides.jp/association_basics.html

https://sakaishun.com/2021/03/20/classname-source/
KongのNginxの設定を変更してみる

## はじめに

OSSのKongは世界で最も人気のあるAPI Gatewayで、認証認可や流量制御などプラグインを有効化するだけで用意することができます。KongですがNginx(Openresty)をベースに作られており、kongの設定値を介してNginxの設定値を変更することもできます。

この記事ではNginx設定変更についての備忘録になります。
主に以下の公式ドキュメントの内容になります。
https://docs.konghq.com/gateway/latest/reference/configuration/#nginx-injected-directives-section

## Kongの設定値の指定方法

kongの設定は`KONG_`の接頭辞の環境変数か`/etc/kong/kong.conf`ファイルで指定することができます。


**設定ファイルを用いる場合**

`/etc/kong/kong.conf` or `/etc/kong.conf`をデフォルトで読み込む設定になっています。  
変更する場合は`kong start --conf /path/to/kong.conf`で指定します。
設定例は`/etc/kong/kong.conf.default`に記載があります。

(例) `kong.conf`での設定定義

```
plugins = bundled
database = off
log_level = notice
```

Dockerfileでコピー

```
FROM kong:2.8.1-alpine
...
COPY kong.conf /etc/kong/kong.conf
```

**環境変数を用いる場合**

`KONG_`の接頭辞がついた環境変数をkongの設定値として認識します。

(例) Dockerfileでの環境変数定義

```
FROM kong:2.8.1-alpine
...
ENV KONG_PLUGINS bundled
ENV KONG_DATABASE off
ENV KONG_LOG_LEVEL notice
```


## Nginxの設定値の指定方法

KongはNginxをベースに動いており、Nginxのパラメータ設定も環境変数または設定ファイルで行うことができます。

**設定ファイルを用いる場合**

`nginx_<namespace>_<directive>`を指定することで`[prefix (default to /usr/local/kong/)]/nginx.conf`に挿入されます。

（例）httpブロックの設定を挿入したい場合

  1. `kong.conf`に記載する

      ```
      nginx_http_client_body_buffer_size=15m
      nginx_http_proxy_buffering=on
      nginx_http_proxy_buffers=8k
      nginx_http_proxy_buffer_size=8k
      ```

  2. httpブロックに挿入される
 
  /usr/local/kong/nginx-kong.confを確認

      ```
      http {
        ...
        # injected nginx_http_* directives
        client_body_buffer_size 150m;
        ...
      }
      ```

他も同様の仕組みで挿入される

| prefix                       | Target              | 
|------------------------------|---------------------|
| nginx_main_<directive>       | root in nginx.conf  |
| nginx_events_<directive>     | events {} block     |
| nginx_http_<directive>       | http {} block       |
| nginx_proxy_<directive>      | server {} block     |
| nginx_upstream_<directive>   | upstream {} block   |


**設定ファイルを用いる場合**

上記に`KONG_`の接頭辞をつけた環境変数を設定します。  

(例) Dockerfileでの環境変数定義

```
FROM kong:2.8.1-alpine
...
ENV KONG_NGINX_HTTP_CLIENT_BODY_BUFFER_SIZE 15m
ENV KONG_NGINX_HTTP_PROXY_BUFFERING on
ENV KONG_NGINX_HTTP_PROXY_BUFFERS 8k
ENV KONG_NGINX_HTTP_PROXY_BUFFER_SIZE 8k
```
【AWS】用語を整理しながら学ぶAWS - part10 Amazon AppFlow

# 【AWS】用語を整理しながら学ぶAWS - part10 Amazon AppFlow

## はじめに

この記事では Amazon AppFlow(以下、AppFlow) を学習していく記事です。
主な内容としては実践したときのメモを中心に書きます。（忘れやすいことなど）
誤りなどがあれば書き直していく予定です。

## Amazon AppFlowとは

AppFlow はAWSとSaaSを統合するSaaS統合サービスです。

AWSでは次のように紹介されています。
> Amazon AppFlow は、Salesforce、SAP、Zendesk、Slack、および ServiceNow などの SaaS (Software-as-a-Service) アプリケーションと、Amazon S3 や Amazon Redshift などの AWS のサービスとの間で、たった数回のクリックでデータを安全に転送できるフルマネージド統合サービスです。

参考：[Amazon AppFlow](https://aws.amazon.com/jp/appflow/)

AppFlow を導入することでAWSのリソースをSaaSサービスで利用できるようになります。
参考：[統合できるSaaS一覧](https://aws.amazon.com/jp/appflow/integrations/)

この記事ではSalesforce の連携を通してAppFlowの特徴を見ていきます。
oO(そもそもSalesforceってなに？)

## Salesforceとは

Salesforce は顧客情報を一元管理するCRMのSaaSです。

[Salesforce](https://www.salesforce.com/jp/)

:::note info
CRM = Customer Relationship Management
:::

AWSとSalesforceの連携にはPrivateLinkによる連携を利用できます。

:::note warn
PrivateLinkによる連携を利用する為には
Salesforceの商用アカウントと以下のリンクにある非公開接続の設定が必要です。
[非公開接続を使用したクロスクラウド連携の保護](https://help.salesforce.com/s/articleView?id=sf.private_connect_overview.htm&type=5)
:::

では実際にAppFlowでSalesforceと連携する場合、どのような手順を辿るのでしょうか。

## AppFlow で SaaSを統合する手順

AppFlow=>Salesforceをつなぐ流れを例に手順を示します。
統合するSaaSによって手順は変わってきます。

1. コネクタを元に接続を作成する
2. 連携に必要なデータを用意する
3. 接続を使ってフローを作成する
4. フローで連携元サービスと連携先のサービスを指定する

SalesforceとAppFlowを連携する場合はSandBox環境を利用して検証することができます。

oO(コネクタ？フロー？SandBox？Production？わからん用語が多い。。。)

## コネクタとは

コネクタはAWSとSaaSをつなぐ為の仕組みです。
SaaS毎にコネクタが用意されています。

このコネクタがあるかないかで連携できるサービスが決まります。
コネクタからAWSとSaaSの接続を作成して接続からフローを作成します。

## フローとは

フローはAWSとSaaSをどう連携するかを決める仕組みです。

:::note info
送信元サービスと送信先サービスはフローで決めます
:::

コネクタからフローを作成すれば、AWSとSaaSの接続ができますが
業務で検証したいこともあると思います。

そんな時に利用できるのが、SandBox環境です。

## SandBox環境とは

SandBox環境は商用環境で実装する前にSalesforceとの接続を検証できる環境です。
[SandBox 環境にログインする](https://test.salesforce.com/)

:::note info
ログインIDとパスワードは商用と同じです。
:::

## Production環境とは

対してProduction環境はいわゆる商用環境のことです。
ライセンスや利用できるインターフェイスに応じてできることが変わります。

:::note warn
SandBox 環境でできることとProduction 環境でできることは異なります。
:::

SalesforceとAWSの接続は
SandBox環境で接続を検証して問題なければ、Production 環境に移行するという流れになります。

## まとめ

AppFlowはAWSと他のSaaSをつなぐ架け橋的なサービスです。

使い方次第で、AWSでできることを増やせるのでとても良いサービスであるものの
SaaSと接続する際にSaaSの操作が必要になるのでAWSの知識だけでなくSaaSの知識も必要になる部分は
ちょっとした落とし穴だと思いました。

## おわり
よく使うLinuxコマンド一覧【カテゴリ別】

随時追加予定です。

## 現在地の移動

| コマンド | 内容 |
|:-|:-|
| cd フォルダ名 | 下層ディレクトリへ移動  |
| cd ../ | 上層ディレクトリへ移動  |
| cd ~ | ホームディレクトリへ移動  |
| cd / | ルートディレクトリへ移動  |


## 表示

| コマンド | 内容 |
|:-|:-|
| pwd | 現在位置を表示  |
| ls | フォルダの中身を表示  |
| ls -l| フォルダの中身と詳細情報を表示  |
| ls -a| 隠しファイルを含めてフォルダの中身を表示  |
| cat ファイル名| ファイルの内容を表示 |

## 検索

| コマンド | 内容 |
|:-|:-|
| find 検索パス -name sample.jpg |  完全一致検索 |
| find 検索パス -name '\*sample*'|  部分一致検索 |
| find / -name 検索語句| 全ディレクトリから検索 |
| find ./ -name 検索語句| 現在のディレクトリ内で検索 |
| find 検索パス -name 検索語句 2> /dev/null| エラーメッセージ非表示で検索  |


## ファイルやフォルダの作成・削除

| コマンド | 内容 |
|:-|:-|
| mkdir フォルダ名 | フォルダ作成  |
| touch ファイル名 | ファイル作成  |
| rm ファイル名 | ファイル完全削除 |
| rm -r フォルダ名 | フォルダの中身ごと完全削除 |
| rmdir フォルダ名 | 空のフォルダを完全削除  |


## ファイルやフォルダの操作

| コマンド | 内容 |
|:-|:-|
| mv 変更前の名前 変更後の名前 |  ファイル・フォルダ名の変更 |
| mv -i 変更前の名前 変更後の名前 |  上書き可否の確認有りでファイル・フォルダ名の変更 |
| mv 移動させたい対象 移動先 |  ファイル・フォルダの移動 |
| mv 移動させたい対象 ../ |  ファイル・フォルダを１つ上のディレクトリへ移動 |
| mv hoge01.txt hoge02.txt 移動先 | 複数をまとめて移動  |
| cp コピぺ対象 コピぺ後の名前 | ファイルのコピぺ |
| cp -r コピぺ対象 コピぺ後の名前 | フォルダのコピぺ |
| nano ファイル名 | nanoエディタでファイルを開く |

## 権限・ユーザー変更系

| コマンド | 内容 |
|:-|:-|
| su ユーザー名 | ユーザー切り替え  |
| sudo コマンド | ルートユーザーの権限でコマンド実行 |
| sudo su | ルートユーザーへ切り替え  |
| ls -l| パーミッションや所有者の確認 |
| chmod 664 変更対象 |  パーミッションを664に変更 |
| chown ユーザー名 変更対象 |  所有者を変更 |
| chown :グループ名 変更対象 |  所有グループを変更 |
| chown ユーザー名:グループ名 変更対象 |  所有者と所有グループを変更 |
| chown -R ユーザー名:グループ名 変更対象 | フォルダ内も含め所有者とグループを変更 |
| cat /etc/group| グループ情報確認 |
| usermod -a -G グループ名 ユーザー名| グループにユーザーを追加 |
2022年度付近のアウトプット周りの取り組みまとめ（ポエム多め）


### 自己紹介
・ハンドルネーム: @seigot
・関西在住
・Qiita: https://qiita.com/seigot
・Github: https://github.com/seigot
・ソフト開発
　・プログラミング言語：C言語, python, シェルスクリプト
　・資格：エンベデッドシステムスペシャリスト、情報処理安全確保支援士試験合格、
　　　　　TOEIC830点

---

### 最近の課題認識
・パワポにもやもや
・これまで学んできた知識を必ずしも活かせる環境になくてもやもや
・リモートワークが定着するも、メリットを活かせていない気がしてもやもや





もやもやをなんとか解決したい気持ち

---

### 2022年度付近の取り組み

・やってみて良かったこと
・やってみて挫折したこと
・やってみたいけど未着手なこと

---

### やってみて良かったこと
・学んだことをQiita等にアウトプット
　[エンベデッドシステムスペシャリスト試験について感じていることを書く](https://qiita.com/seigot/items/3bd3fbf50c75a54c00d5)
　[情報処理安全確保支援士試験を合格するために読んだ本まとめ](https://qiita.com/seigot/items/80a0ed8437b8918c723a)

・[テトリスを題材にpythonを学べるツールを作成してみた話](https://qiita.com/seigot/items/0b42a807217dbe636226)
　　テトリスpythonローカル大会も実施 [動画](https://www.youtube.com/watch?v=9hxtCJVXFjU)

・[Qiitaアドベントカレンダー2021](https://qiita.com/advent-calendar/2021)の記事投稿



Qiitaの記事書いてるだけ？-->そんなことない、、はず

---

### やってみて挫折したこと
・[第四回自動運転AIチャレンジ](https://www.jsae.or.jp/jaaic/final.html)への参加（負けた）
・他の情報系資格の勉強（本だけじゃ限界ある）
・[Qiitaアドベントカレンダー2021](https://qiita.com/advent-calendar/2021)のカレンダー作成（過疎った）


Qiitaから脱却できてない気がする-->そんなことない、、はず

---

### やってみたいけど未着手なこと
・ものつくりイベントへの出展（例.[MakerFaire202X](https://makezine.jp/event/mft2022/)）
・Web系のコンペへの参加（例.ISUCON,CTF,Web系のHackason）
・XXConへの参加（例.PyCon, Ruby kaigi, Go Conference）
　　pyconjp2022 staff 参加させて頂いております
　　https://pyconjp.blogspot.com/2022/09/pycon-ja-2022-keynote.html


アウトプット多めでいきたい

---

もやもやをなんとか解決したい気持ちです
というポエムでした
【備忘録】ubuntu20.04インスタンス作成後の初期設定（新規ユーザー作成、公開鍵設定、rootログイン無効化）

個人メモとして残しておきます。

**実行環境：**
クライアント側： MacOS ターミナル 
サーバ側： Ubuntu 20.04 LTS

## VMインスタンス作成後の初期設定

### 作業概要
1. 新規ユーザー作成
2. 公開鍵認証の設定
3. パスワード認証、rootのログイン無効化


## 1. 新規ユーザー作成

```shell:サーバー側
# 新規ユーザを追加
$ adduser ユーザー名

# sudoグループに追加 （と確認コマンド）
$ gpasswd -a ユーザー名 sudo
$ cat /etc/passwd
```

## 2. 公開鍵認証の設定

```shell:クライアント側
# 鍵を作成
$ cd ~/.ssh
$ ssh-keygen -t rsa
$ chmod 700 ~/.ssh/id_rsa.pub

# サーバに公開鍵を渡す
scp -P 22 ~/.ssh/id_rsa.pub ユーザー名@ホスト名やIPアドレス:~/.ssh/authorized_keys

```

```shell:サーバ側
# パーミッションを変える
chmod 600 ~/.ssh/authorized_keys

# サーバ側で公開鍵認証を許可する
$ vi /etc/ssh/sshd_config
	#PubkeyAuthentication yes
		↓
	PubkeyAuthentication yes

# 再起動
$ systemctl restart sshd
```



```shell:公開鍵認証の確認
# クライアント側にて。公開鍵によるログイン確認
ssh -i .ssh/id_rsa ユーザー名@ホスト名やIPアドレス


```

## 3. パスワード認証、およびrootログインの無効化

```shell:サーバー側
# パスワード認証、およびrootログインの無効化
$ vi /etc/ssh/sshd_config
	#PasswordAuthentication yes
        ↓
	PasswordAuthentication no


	PermitRootLogin yes 
		↓
	PermitRootLogin no

# 再起動
$ systemctl restart sshd

# ログアウトして、パスワード認証できないことを確認
$ ssh ユーザー名@ホスト名やIPアドレス -o PreferredAuthentications=password

# rootログインもできないことを確認
$ ssh root@ホスト名やIPアドレス

```



## メモ
新規ユーザーでログインできることを確認してからrootログイン無効化すること。
サーバに入れなくなる（恐）
PythonでPostgreSQLを操作する(psycopg2)

# インストールが必要パッケージ
```
# dnf -y install python3-devel postgresql-devel
# pip install psycopg2-binary
# pip install psycopg2
```

# データを出力する
```
import psycopg2

# 接続情報を記入 
dsn = "dbname=shop host=psql user=dbuser password=dbpasswd"

# コネクトオブジェクト生成
conn = psycopg2.connect(dsn)

# カーソルオブジェクト生成
cur = conn.cursor()

# SQLを実行する
cur.execute("SELECT * FROM shohin")

# データをすべて出力
print(cur.fetchall())

# オブジェクトをクローズする
cur.close()
conn.close()
```

## いろいろなデータの出力
データを1つだけ出力
```
print(cur.fetchone())
```
1つずつ取得
```
for row in cur:
  print(row)
```
カラム名を出力する
```
print([col.name for col in cur.description])
```
レコードを指定して出力
```
# データをすべて出力してから
data = cur.fetchall()
# 1レコード目のみ出力
print(data[0])
```

そのうち、もう少し追記します
正規表現：曖昧なパターンはエンジンによって動作が変わる（教訓）

検索してどういうことなのか調査してみようとしたのですが、上手に検索できませんでした…。
検索しても全然それっぽい情報が出てこない！
のでとりあえず記事にしてみます。

もし原因をご存じの方いましたらお教えいただけると嬉しいです…！


# 環境
- グループ1（JavaScript系）
  - JavaScript (Firefox 104.0.2)
  - JavaScript (Google Chrome 105.0.5195.127)
- グループ2（Perl系など）
  - PCRE (PHP 7.3.11 & PCRE 10.32 2018-09-10: [RegExr.com](https://regexr.com/))
  - Python 3.10 (re モジュール)
  - コメントに頂いた検証：Ruby 3.1.2 (Onigmo)
  - コメントに頂いた検証：CotEditor 4.3.4 (ICU)


PCREは「PCRE ライブラリは、Perl 5 と同じ文法構文を用いた 正規表現パターンマッチ処理を実装した関数群ですが、多少異なる点もあります (以下を参照ください)。現在の実装は Perl 5.005 に対応しています。 」とのことです。
参考：[正規表現 (Perl 互換)](https://www.php.net/manual/ja/intro.pcre.php)

Pythonの正規表現は「Perl に見られる正規表現マッチング操作と同様のもの」とのことです。
参考：[re --- 正規表現操作 — Python 3.10.6 ドキュメント](https://docs.python.org/ja/3/library/re.html)


# やりたかったこと
- 文字列
- abc文字列abc

のように、特定の文字列の**前後**に同じパターンがあった際に一緒に扱いたかった。


# テストする文字列
```:テストする文字列
文字列
abc文字列
文字列abc
abc文字列abc
```
最初の```文字列```と最後の```abc文字列abc```のみにマッチしてほしい！


# 最初書いたパターン
```:パターン
(abc)?文字列\1
```
abcはあってもなくてもよくて、abcが先頭にあった場合は末尾にもあってほしい。

…グループの外にハテナつけたときって参照はちゃんと効くのかな…？
不安に思ったのでテストしてみます。


## 結果
```:グループ1（JavaScript系）でマッチした文字列
文字列
abc文字列abc
```

両方にマッチした！うれしい。
しかし…

```:グループ2（Perl系など）でマッチした文字列
abc文字列abc
```

なんと、環境が変わるとマッチしなくなってしまった…！
さっきテストしたらマッチしてたのに…
（当然マッチしてると思っていたので原因がわからなくてけっこう悩みました）


# 書き直したパターン
```:パターン
((?:abc)?)文字列\1
```
ハテナごとまとめてグループにすることで、確実に記憶がされるようにしました。
テストしてみます。

・追記：コメント欄にもっとスマートなパターンを頂きました。
こっちの方がすっきり！（テスト結果は同じです）
```:パターン
(abc|)文字列\1
```

## 結果
```:グループ1（JavaScript系）でマッチした文字列
文字列
abc文字列abc
```

```:グループ2（Perl系など）でマッチした文字列
文字列
abc文字列abc
```
両方ちゃんとマッチするようになりました！
わーい！


# 教訓
正規表現はエンジンが変わると、細かい動作が普通に変化することがあり得る…！
文字クラスの中身が変わったりするのは知っていましたが（例：pythonではデフォルトで```\d```に全角数字が入る）
こういう動作の変化の仕方もあるのは盲点でした…

これからはなるべく曖昧さを排除して確実なパターンを書くように心がけます。
それと、テストする際は必ず実環境と同じエンジンでテストする！
20代後半のインフラエンジニアが転職した話②　　転職先の絞り込み

自身の経験をもとに応募・面接段階と内定段階に分けて、
転職先の絞り込み方についてまとめています。
※あくまで個人の見解で、年代等によっても考え方は異なります

この記事の続きです

https://twitter.com/UmaUuma321/status/1568628119183171584


# 前提
・20代後半インフラエンジニアの転職
・SIerからの転職
・転職先候補は広めに見てた（外資ベンダ、ITコンサル、事業会社、SIer）

# 結論
応募・面接段階
・業界/職種が絞り込めていないうちは、同一業界/職種の企業を2社まで選んで面接

内定段階
・（できれば）転職経験のある信頼できる上司、先輩等に相談

# 応募・面接段階
業界/職種が絞り込めていないうちは、同一業界/職種の企業を2社まで選んで面接をしました
（やさしいエージェントさんのアドバイス）

理由として以下です。
・面接、準備時間がもったいない！
・2社面接すれば、大体自分と合う合わないが分かる

リモートワークが推進されている最近は、Web面接が主流となり転職活動かなりしやすくなりました。
とは言え、何社も応募・面接すると業務と並行するには時間が足りないです。。
しかし、多くのエージェントさんは十数社は応募するよう言ってきます
（ノルマとかあるんですかね。。）
そんな中、あるエージェントさんからは同一業界/職種の企業をまず2社絞ることをお勧めしてもらいました。
ひとまず2社面接までたどり着いて、会話する中で話のテンポ等から判断して合わなければその業界/業種は全部切るというイメージです。
この方法は実際に有効で、ITコンサル、事業会社は今の自分の希望/適性とは合わないことが分かりました。

# 内定段階
（できれば）転職経験のある信頼できる上司、先輩等に相談するのが良いと思います
※転職する意思が固まっているのであれば、内定が出るまでは今いる会社の上司には相談しないほうがよいです
　大抵の場合は止められるか、評価を下げてしまうだけなので

理由としては以下
・業界に詳しいのは結局その業界にいる人だから
・経験、情報を持っている人に話を聞いたほうがよい（転職経験あり、転職への感度が高い人の方がよい）
・内定が出た後はエージェント、転職先はあてにならない（あとは成約するだけの段階だから）

あくまで信頼できる上司、先輩がいる場合に限りますが、
内定を取ったことを伝えて、転職する意思をくみ取ってくれれば最後の選択へのアドバイスをくれます。
実際に私も最後の最後で転職先変えました。。。
あそこではなく、こっちならまあ分かる。それなら止めない。といった感じでした。
どっちがよかったかまだ判断できませんが、業界での経験が長い人の方が知識もあるので、
アドバイスを聞いて損はないと思います。

内定後のエージェント、転職先の人のアドバイスはあてにならないです。
当然ですが、成約させたい・来てもらいたいが最優先だからです。
同一のエージェントの紹介で複数内定が出た場合は、相談してみてもよいかもしれないです。
【MongoDB】DBのバージョン変更後に起動時「Shutting down with code: 62」が発生する

## 概要
最近、PCに入れていたMongoDBのバージョンを更新して、その後起動時に`Shutting down with code: 62`というエラーが発生し起動しなくなってしまいました。原因と対応についてメモ書きします。

## 原因
[MongoDB - shutting down with code:62](https://stackoverflow.com/questions/47850004/mongodb-shutting-down-with-code62)にある通り、元々使用していたバージョンのDBファイルと変更後のバージョンで、互換性がない場合に発生するエラーのようです。

## 対応
DB再作成で問題ない場合は、一番簡単な対応は新しくDBのファイルを作成することです。[MongoDB サーバー (mongod) を起動する](https://maku.blog/p/3ucs8n3/)の記事にある通り、DBファイルのパスを起動時に指定できるので、、旧バージョンとは別のパスを指定して起動すればエラーは発生しませんでした。
もし、データの移行が必要な場合、旧バージョンで一度jsonでデータバックアップしておいて、新バージョンにインポートするような対応も考えられます。