OmniAICreator/Qiita-1.07M huggingface dataset:
Ubuntu 14.04にOpenJDK 8をインストール（Zulu Community）

# はじめに

Zulu Communityを利用してUbuntu14.04にOpenJDK8をインストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)
参考：[Download OpenJDK Java Linux Windows macOS Alpine Java 11 Java 8](https://www.azul.com/downloads/zulu-community/)

## サポート

本手法で導入した場合、[Zulu Community Java OpenJDK free download TCK tested](https://www.azul.com/products/zulu-community/)より、2026-03がEOLになると思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。

## LOG

### レポジトリ登録

```shell-session
# apt update; apt install -y software-properties-common
# apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0xB1998361219BD9C9
# apt-add-repository 'deb http://repos.azulsystems.com/ubuntu stable main'
```

### インストール

```shell-session
# cat /etc/os-release
NAME="Ubuntu"
VERSION="14.04.6 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.6 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"

# apt update; apt install -y zulu-8
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (Zulu 8.40.0.25-CA-linux64) (build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM (Zulu 8.40.0.25-CA-linux64) (build 25.222-b10, mixed mode)
```
【環境構築】CentOS7.7 + Apache2.4.6でドキュメントルート変更手順

#はじめに
CentOSからApacheのドキュメントルートを変更したときにハマったので、対処方法を備忘録として残します。

#環境
・CentOS 7.7.1908
・Apache/2.4.6

#1.httpd.confの編集

下記ファイルを編集していきます。

```
/etc/httpd/conf/httpd.conf
```

```:httpd.conf
DocumentRoot "/var/www/html"
```
↑のパスを自分が公開したいドキュメントルートパスに書き換えます。
例として、下記のようなフォルダ階層で"__/home/vagrant__"をドキュメントルートにしたい場合は

<img width="700" alt"フォルダ階層.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509479/67a7188e-94b0-40a7-4b53-f05435ff0802.png">

```:httpd.conf
DocumentRoot "/home/vagrant"
```
↑のように編集します。
次に、Directoryを修正します。
Directoryのパスを、編集したドキュメントルートに合わせて書き換えます。

```:httpd.conf
<Directory "/var/www">  ←ここのパスを変更
    AllowOverride None
    # Allow open access:
    Require all granted
</Directory>
```

```:httpd.conf
<Directory "/home/vagrant">
    AllowOverride None
    # Allow open access:
    Require all granted
</Directory>
```

ここまでできたら下記コマンドでApacheを再起動します。

```
$ systemctl restart httpd
```

この状態でドキュメントルートにアクセスするとPermission deniedと言われます。
ブラウザには403 Forbiddenと出てくると思います。

<img width="700" alt"パーミッションDenied.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509479/82817e15-dd4d-c872-df3d-cc086f7f8feb.png">

Apacheからドキュメントルートフォルダに読み取り権限がないため、権限を与えなければなりません。

#2.ドキュメントルートフォルダにパーミッション付与
例として、"__/home/vagrant__"をドキュメントルートにした場合、下記のコマンドで権限を付与します。

```
$ chmod 755 /home/vagrant
```

これで読み取り権限を付与できました。
もう一度ドキュメントルートにアクセスすると、ブラウザ上できちんと表示されていると思います。
Ubuntu 14.04にOpenJDK 7をインストール（Zulu Community）

# はじめに

Zulu Communityを利用してUbuntu14.04にOpenJDK7をインストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)
参考：[Download OpenJDK Java Linux Windows macOS Alpine Java 11 Java 8](https://www.azul.com/downloads/zulu-community/)

## サポート

本手法で導入した場合、[Zulu Community Java OpenJDK free download TCK tested](https://www.azul.com/products/zulu-community/)より、2023-07がEOLになると思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。

## LOG

### レポジトリ登録

```shell-session
# apt update; apt install -y software-properties-common
# apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0xB1998361219BD9C9
# apt-add-repository 'deb http://repos.azulsystems.com/ubuntu stable main'
```

### インストール

```shell-session
# cat /etc/os-release
NAME="Ubuntu"
VERSION="14.04.6 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.6 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"

# apt update; apt install -y zulu-7
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "1.7.0_232"
OpenJDK Runtime Environment (Zulu 7.31.0.5-CA-linux64) (build 1.7.0_232-b6)
OpenJDK 64-Bit Server VM (Zulu 7.31.0.5-CA-linux64) (build 24.232-b6, mixed mode)
```
複数あるStoryboardで起動するStoryboardを選択するやり方

# 状況
**後から新たに作成した`First.storyboard`から起動したい**(`Main.storyboard`ではなく)

ググってみると
Storyboardを複数作成した場合の起動画面(Storyboard)の選択方法はこんな感じ
・起動するStoryboardをxcodeprojで選択しましょう
・`is Initial ViewController`を選択しましょう
->**全部やってます、、、、でも`Main`で起動される**
![スクリーンショット 2019-10-11 21.18.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427937/2afe6c99-2916-1e44-e96d-cf13e00baa7c.png)

・`Main.storyboard`消してみる(referenceのみ)

```
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Could not find a storyboard named 'Main' in bundle NSBundle </Users/hoge/data/Containers/Bundle/Application/hoge/hoge.app> (loaded)'
*** First throw call stack:
```
`Main.storyboard`がないよー　と言われる始末、、、、

# 対策
いったいどこで`Main.storyboard`を参照してやがるんだと`Main`でプロジェクト全体に検索をかけたところ
(`ApplicationScene Manifest`->`Scene Configuration`->`Application Session Role`->`Item 0 ...`->`Storyboard Name`)
**↓ここでした**
![スクリーンショット 2019-10-11 21.18.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427937/31a77f55-b595-5ed0-cede-55297a606991.png)


なぜここを変えないとできないのかはよく分かりませんが
いくら調べても出てこなかったので備忘録として。

# 参考
**・[アプリ起動時に呼び出すStoryboardを指定したい | moxt](https://hogehuga.com/post-105/)**
**・[[iOS] 複数のStoryboardを使って画面遷移を作成する ｜ DevelopersIO](https://dev.classmethod.jp/smartphone/iphone/use-multiple-storyboards/#toc-storyboard3)**
**・[perhaps the designated entry point is not set?　が表示された時の対処方法 - Qiita](https://qiita.com/milkoala_fs9/items/c68f8ee3ad404dcadeb9)**
**・[iOSのスプラッシュ画面実装における注意点と実装方法 - Qiita](https://qiita.com/k-boy/items/7de88a834bf01a6e858f)**

**・[[iOS] 複数のStoryboardを使って画面遷移を作成する ｜ DevelopersIO](https://dev.classmethod.jp/smartphone/iphone/use-multiple-storyboards/#toc-storyboard3)**
->単純に`Storyboard`の分割の意図についてためになる記事でした(5年以上前の記事だけど)
Railsチュートリアル 第９章＜復習＞

第９章の復習メモです。
個人的に重要と思ったことを書きます。

前回と同様、以下３つの視点で書きます。

- 分かったこと
- 分からなかったこと
- 今回はスルーしたこと


#分かったこと

##永続セッション
前章では、一時cookieを使ったので、ブラウザを閉じると情報が消えてしまった。本章では、ブラウザを閉じても消えない**永続cookie**を使った。

前章の通りRailsでは、**sessionメソッド**を使うことで、一時cookieに情報を保存できる。sessionメソッドは、保存する際に情報を暗号化してくれるので、安全性が高い。
一方で、永続cookieの場合は、**cookiesメソッド**を使う。cookiesメソッドは、自動で暗号化する機能が無いため、安全性が低い。

今回、永続cookieのセキュリティを強化するため、以下の対策を行った。

- cookieにユーザIDを保存する際、暗号化の処理を行う。
- ユーザIDに加えて、サーバ上でトークンを発行し、cookieに保存する。

今回、永続セッションを作成した手順は以下の通り。

1. ランダムな文字列を生成し、これをトークンとする。
2. ブラウザのcookiesにトークンを保存する。有効期限も設定しておく。
3. トークンをデータベースに保存する。その際、ハッシュ値に変換する。
4. ブラウザのcookiesに、暗号化したユーザーIDを保存する。
5. 永続ユーザーIDを含むcookiesを受け取ったら、そのIDでデータベースを検索し、トークンのcookiesがデータベース内のハッシュ値と一致することを確認する。


#分からなかったこと、今回はスルーしたこと

- 永続セッション実装の詳細

今回は、セッションそのものの仕組みについて、理解することに努めました。コーディングは一通り実装してみて、流れは分かったかな、という感じです。

- テスト全般


#参考
以下を参考にさせていただきました。
https://qiita.com/hot_study_man/items/147f8b767b4135fe6fe4
https://www.masalog.site/entry/2017/08/31/171712
YOLO on blogspot(blogger)

Here is another example of having AI application on blog.  Parent method is used once more to make it as a part of article posted.![YOLO.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373401/8839042b-b555-915a-402e-cf65b34fbb81.jpeg)



Blog
https://randomwalkjapan.blogspot.com/2019/10/yoloai-lets-play-on-yoloai-scene.html


Code is in GitHub 
https://github.com/tanakayutaka/Yolo-on-blogspot-blogger-
Vue + SVG で作るグラフィックアプリの骨格

# はじめに

この記事はもう一つの記事、
[Vue + Canvas で作るグラフィックアプリの骨格](https://qiita.com/Satachito/items/625a07d26f3a77abfdb7)
の SVG 版です。

Canvas や SVG のおかげでブラウザ上でもインタラクティブにグラフィックを簡単に扱えるようになりました。

おまけに Vue を使うとまるでパソコン上のアプリを作るかのように Web 上にグラフィックアプリを作ることができます。

この記事では Vue + SVG でマウスで四角を書いていくような 80 行程度の簡単なサンプルを作ることで、Web 上のグラフィックアプリの骨格を示したいと思います。

できあがったものは、以下のような感じです。
![ss.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73493/c546cf1e-9cd5-02b7-ff4d-26caa0fcc1b9.gif)

# 準備

* node, npm をダウンロードします

https://nodejs.org
この記事では node v12.4.0 で検証しています

* vue-cli をダウンロードして、とりあえず qvs という名前でアプリを作ります。

```console
$ npm i @vue/cli -g
$ vue create qvs
$ cd qvs
$ yarn serve
```

この記事では vue 3.12.0 で検証しています。yarn を使ってない人は最後の行は

```console
$ npm run serve
```

になると思います。

なお、以下のコードは ESLint の掟に従ってないので、`vue create qvs` の時に ESLint をはずさないと多分エラーになると思われます。
また、セパレータを前に書いたり、引数とか変数の名前が _ だったりするのは単なる趣味ですので、気に入らなくても怒らないでください。

# コード

src/App.vue を以下のようにしてみます。

``` App.vue
<template>
	<div id=app style="overflow: scroll">
		<div id=menu style="position: fixed; top: 0; left: 0">
			<button @click="mode='select'"	>select </button>
			<button @click="mode='rect'"	>rect	</button>
		</div>
		<svg
			style		= "margin: 24px 4px 4px 4px; background: aliceblue"
			:class		= "{ drawRect: mode == 'rect' }"
			:width		= "extent[ 0 ]"
			:height		= "extent[ 1 ]"
			@mousedown	= "mouseDown"
			@mousemove	= "mouseMove"
			@mouseup	= "mouseUp"
			@keyup.esc	= "keyUpESC"
		>
			<template v-for="_ in elements">
				<rect v-bind="_" stroke=black fill=none />
			</template>

			<rect v-bind=dragRect stroke=blue fill=none />
		</svg>
	</div>
</template>

<script>
export default {
	data	: () => (
		{	b			: null
		,	c			: null
		,	mode		: 'select'
		,	elements	: []
		}
	)
,	computed: {
		extent	() {
			return [ 700, 500 ]
		}
	,	svg		() {
			return this.$el.getElementsByTagName( 'svg' )[ 0 ]
		}
	,	dragRect() {
			return ( ! this.b || ! this.c )
			?	null
			:	{	x		: this.b.offsetX
				,	y		: this.b.offsetY
				,	width	: this.c.offsetX - this.b.offsetX
				,	height	: this.c.offsetY - this.b.offsetY
				}
		}
	}
,	methods	: {
		mouseDown( _ ) {
			this.b = _
		}
	,	mouseMove( _ ) {
			this.c = _
		}
	,	mouseUp( _ ) {
			this.c = _
			switch ( this.mode ) {
			case 'rect':
				this.elements.push( this.dragRect )
				break
			}
			this.b = null
		}
	,	keyUpESC( _ ) {
			this.mode = 'select'
		}
	}
,	mounted() {
		this.svg.setAttribute( 'tabindex', 0 )
	}
}
</script>

<style>
.drawRect {
	cursor: crosshair
}
</style>
```

# 勘所

## キーイベントの取得

svg に tabindex 属性をつけると、キーイベントを取得できるようになります。

```js
	this.svg.setAttribute( 'tabindex', 0 )
```

## カーソルの切り替え

mode が 'select' と 'rect' の2つの状態が存在します。
'rect' の状態の時にクロスヘアカーソルを表示するために
[クラスとスタイルのバインディング](https://jp.vuejs.org/v2/guide/class-and-style.html)を動的に使っています。

```vue
	:class = "{ drawRect: mode == 'rect' }"


<style>
.drawRect {
	cursor: crosshair
}
</style>
```

## v-bind でプロパティを一括設定

プロパティ名と同じキーを持つ辞書を用意して

```js
dragRect = {
	x		: 100
,	y		: 200
,	width	: 300
,	height	: 400
}
```

```vue
<rect v-bind=dragRect />
```

とやると、

```vue
<rect x=100 y=200 width=300 height=400 />
```

と展開されます。

# 最後に

この記事が何かの役にたてたら幸いです。わからないことがあればコメントください！
ReactorKitでFirestoreをListenする方法

# 概要
`ReactorKit`を使ったプロジェクトで`Firestore`を使うことになったので、`Pring`を用いて実装しました。

# 環境

- Xcode 11.0
- Swift 5.1
- ReactorKit 1.2.1 (https://github.com/ReactorKit/ReactorKit)
- Pring 0.17.3 (https://github.com/1amageek/Pring)

# 実装

`User`というモデルを`Firestore`から取得してくるという設定です。

## Reactor側

`Action`, `Mutation`, `State`, `mutate`, `reduce`はやるだけって感じです。
ポイントは`dataSource`を以下のように用意して、

```swift
private let dataSource: DataSource<User>?
```

`setupDataSource()`内で`DataSource`を`listen()`してやることです。
この時`.on`の中で`self?.action.onNext(.updateUsers(users))`することで、`Firestore`から取得したデータをReactorのストリームにうまく取り込んでます。

```swift
private func setupDataSource() {
    dataSource = User.query.dataSource()
        .on { [weak self] _, _ in
            guard let users = self?.dataSource?.documents else { return }
            self?.action.onNext(.updateUsers(users))
        }
        .listen()
}
```

全実装は以下のようになります。

```swift
import ReactorKit
import RxSwift
import Pring

final class UserListReactor: Reactor {
    enum Action {
        case updateUsers([User])
    }

    enum Mutation {
        case setUsers([User])
    }

    struct State {
        var users: [User] = []
    }

    // MARK: - Variables

    let initialState = State()
    private let dataSource: DataSource<User>?

    // MARK: - Initializer

    init() {
        setupDataSource()
    }

    // MARK: - Setup Methods

    private func setupDataSource() {
        dataSource = User.query.dataSource()
            .on { [weak self] _, _ in
                guard let users = self?.dataSource?.documents else { return }
                self?.action.onNext(.updateUsers(users))
            }
            .listen()
    }

    // MARK: - Reactor Methods

    func mutate(action: Action) -> Observable<Mutation> {
        switch action {
        case let .updateUsers(users):
            return .just(Mutation.setUsers(users))
        }
    }

    func reduce(state: State, mutation: Mutation) -> State {
        var state = state
        switch mutation {
        case let .setUsers(users):
            state.users = users
        }
        return state
    }
}
```

## ViewController側

いつも通り`bind(reactor:)`内で`UserListReactor.State.users`を`bind`してやれば終わりです。

```swift
import UIKit
import RxSwift
import ReactorKit

final class UserListViewController: UIViewController, View {
    // MARK: - Variables

    var disposeBag = DisposeBag()
    ...
    // MARK: - Bind Methods

    func bind(reactor: UserListReactor) {
        // State
        reactor.state.map { $0.users }
            .distinctUntilChanged()
            .bind { users in
                // tableView or collectionViewの更新
            }
            .disposed(by: disposeBag)
    }
}
```
運用手順書はどこまで作成するべきか

# はじめに
システム運用において、**どこまで手順書を作成するべきか**という課題には、皆さん頭を悩ませているのではないでしょうか。もちろん、すべての作業について手順書があれば、品質が担保できます。しかし、実際の現場では、作成、メンテナンスの手間を考えるとすべての作業に対して手順書を作成することは、現実的ではないしょう。先日、システム運用の品質担当者の方が、その課題について２つの基準をお話してくれたので、その内容を共有したいと思います。

また、そこでSRE的には、どのような基準で手順書の作成や自動化を行っているのか、という質問を受けました。その問いに対する、個人的な意見も合わせて共有します。

## 手順を作成するべき作業の基準
### 基準１：お客様と約束を交わしているかどうか
基準１はわかりやすいのですが、お客様と手順書の作成について、約束を交わしている場合です。この場合、どんな単純な作業でも手順書を作成する必要があります。作成された手順書の内容を、お客様にレビューしていただき、合意をとって、その手順どおりに運用することが求められるでしょう。

### 基準２：リスクを受容できるか
基準２ですが、手順書がない作業を行って、起きたリスクを受容できなければ、その作業は手順書を作成するべきでしょう。逆に、リスクが起きたとしても、簡単にリカバリをできるものであれば、あえて手順書を作成する必要はないと言えます。これは、情報セキュリティマネジメントの、「リスク保有」と同じような考え方で、リスクの持つ影響力が小さい場合や、コストに見合ったリスク対応の効果が得られない場合が当てはまります。

> 参考：情報セキュリティマネジメントとPDCAサイクル
> https://www.ipa.go.jp/security/manager/protect/pdca/risk.html


## SRE的、手順を作成するべき作業の基準（個人の意見も含む）
そもそも、SREは単純に作業フローの見える化や見直し、自動化する活動ではないと考えています。しかし、どのような運用作業を自動化するべきかには、ある程度基準があります。SREでは、その自動化するべき作業のことを**トイル**と呼んでいます。

#### トイルの定義
以下の特徴に、１つ以上当てはまれば、その作業はトイルである可能性が高いです。

##### 手作業であること
自動化スクリプトを、手作業で実行するような作業のことです。

##### 繰り返されること
繰り返し何度も行われている作業のことです。作業が１回や２回しか行われないものであれば、それはトイルではないでしょう。

##### 自動化できること
マシンが人間同様に行えるタスクのことです。そのタスクに人間の判断が欠かせないのであれば、それはトイルではないでしょう。しかし、そもそも人間の判断が必要な、運用の設計に問題がある可能性もあります。

##### 戦術的でないこと
割り込みで始まり、問題などが生じたことへの対応として行われる作業のことです。

##### 長期的な価値を持たないこと
あるタスクを終えても、サービスが同じ状態であれば、そのタスクはトイルである可能性が高いです。

##### サービスに対してO(n)であること
サービスのサイズ、トラフィック量、ユーザー数などに比例してスケールするようなタスクのことです。

### なぜ、トイルを自動化するべきか
トイルは、自動化せずにいると、どんどん拡大し、運用作業者の時間の100%を埋め尽くしてしまう傾向があるためです。トイルを減らすことで、サービスのサイズが大きくなっても、運用チームの規模は比例しなくなり、純粋な開発チームや運用チームに比べて、より効率的にサービスを管理できるようになります。

## おわりに
理論的には、基準があっても、いざ現場でフローの見える化や見直し、自動化を行うことは簡単ではないです。まずは、小さいことからでも、現場の人が改善しようという意思を持って行動に踏み出すことが大切だと思います。
Ruby ユーザ の 入力数値 を 変数 に 格納する

# 目的

- Rubyにてユーザからの入力数値を受け取り、変数に格納する方法をまとめる。

# 書き方の例

- 入力を受け取るにはメソッド`gets`を使用する。
- 入力の改行もなくして変数に格納したいためオプション`chomp`を付ける。
- 入力が数値であるため、さらにオプション`to_i`を付ける。
- 下記に処理を記載する。

```ruby
変数 = gets.chomp.to_i
```

# より具体的な例

- 入力された数値をコンソールに出力する処理を考える。
- コンソールには「好きな数値を入力してください。」 → 入力待ち → 「入力された数値は○○です。」と表示されるようにする。
- 入力された数値は変数`input`に格納する。
- 下記に処理を記載する。

```ruby
puts "好きな数値を入力してください。"
input = gets.chomp.to_i
puts "入力された数値は#{input}です。"
```
DockerのLinux OSイメージにあるコマンド一覧を出す

# 動機

Dockerを使ってみようと思っていろいろ調べていると、イメージを作成するには、ベースとなるOSのイメージに対して、いろいろとファイルを追加していく所作を`Dockerfile`に記述するそうなのですが、そこで「べースとなるOSにあらかじめ導入されているコマンドは何か？」という素朴な疑問が湧きます。

# 原始的な方法でいいではないか

調べたいイメージを走らせて`find`でリストする、という原始的な方法を使ってみた。下記は[公式のCentos8](https://hub.docker.com/_/centos)のパスにあるコマンド一覧を表示させた例。

```bash:centos8の実行例
% docker run -it --rm centos:8 /bin/bash -c 'find ${PATH//:/ } -type f -perm /0100 | sort'
/usr/bin/[
/usr/bin/addr2line
/usr/bin/alias
/usr/bin/ar
...(途中略)...
/usr/sbin/weak-modules
/usr/sbin/wipefs
/usr/sbin/zdump
/usr/sbin/zic
/usr/sbin/zramctl
```

# バリエーション

上記実行例では、GNUの`find`が入っていることを仮定している。BSD系の`find`が入っているOSイメージの場合には、`find`のオプションを`-perm /0100`から`-perm -0100`に変える必要があるのではないかと思う。また、**そもそもOSイメージにfindが入っていなかったら使えない**方法ではある。

# 応用

同様の方法で、もともとインストールされているパッケージの一覧も表示させてみた。下記の例はRedHat系Linux想定して、host OSでソート。

```bash:応用例
% docker run -it --rm centos:8 rpm -qa | sort
acl-2.2.53-1.el8.x86_64
audit-libs-3.0-0.10.20180831git0047a6c.el8.x86_64
basesystem-11-5.el8.noarch
bash-4.4.19-7.el8.x86_64
bind-export-libs-9.11.4-16.P2.el8.x86_64
...(途中略)...
vim-minimal-8.0.1763-10.el8.x86_64
xz-5.2.4-3.el8.x86_64
xz-libs-5.2.4-3.el8.x86_64
yum-4.0.9.2-5.el8.noarch
zlib-1.2.11-10.el8.x86_64
```
Visual Studio CodeのPreview状態のタブを通常状態にする地味に便利なKeyBind

※[自身のBlog](https://blog.piyosi.com/)に投稿したのと同じ記事ですが、検索するのが難しい事象であるため、人目に付くであろうこちらにも寄稿します。

## 困りごと

`Ctrl + P`のQuickOpenでファイルを開いたり`F12`でコードジャンプすると、タブがPreview状態(タブ名がイタリック表記)で開かれます。  

![タブの状態.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375564/1527c0f0-16ca-b783-d0e5-4f7f4b0b9b24.png)
※左:通常状態 右:Preview状態のタブ

これは`workbench.editor.enablePreviewFromQuickOpen`が有効なためです。

![PreviewFromQuickOpen設定画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375564/7a039080-40c4-85e3-6d7b-153e17b9d8a1.png)

この状態で別ファイルを開くと、同じタブでファイルが開かれてしまいます。
せっかくファイルを開いたのに。本当は別タブで開いて欲しいのに…。

`F12`でコードジャンプした先のタブを開いたままにしておきたい！  
`Ctrl + P`でファイルを開く際に、Preview表示と普通に開くのを使い分けたい！

という方への記事です。

## 右矢印で開く

`Ctrl + P`で開きたいファイルをハイライト状態にしたあと、キーボードの`右矢印キー`を押下します。

すると通常状態でファイルが開けます。ファイルを開いてもQucikOpen Windowは表示されたままなので、沢山ファイルを開きたいときに便利です。


![QuickOpenDemo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375564/21cfd039-3f5e-ab3c-e645-5fd97ee57878.gif)

ちなみに`Alt + Enter`で画面をSplitしてファイルを開くことも可能です。

## Preview状態のタブをキーボードショートカットを使って通常状態にする

`F12`などでコードジャンプをした際に開かれるPreview状態のタブを通常状態に切り替えるにはどうしたらよいでしょうか。

調べた結果`ビュー:エディターを保持`でPreview状態のタブを通常状態に変更できるらしいです。

デフォルトでは`Ctrl + K, Enter`に割り当てされています。  
※私の環境では。

## ショートカットキーの変更

よく使う機能なのにデフォルトの`Ctrl + K, Enter`では使いにくい！Bindを変更します。

`テキストエディタがアクティブ` かつ `タブがPreview状態`のときに`Escapeキー`というBindに変更します。

```json
    {
        "key": "escape",
        "command": "workbench.action.keepEditor",
        "when": "editorTextFocus && editorPinned == false"
    }
```

## 参考

[VSCode keyboard shortcut for optionally triggering keepEditor when using quickOpen?](https://stackoverflow.com/questions/52649520/vscode-keyboard-shortcut-for-optionally-triggering-keepeditor-when-using-quickop)

[vscode: Open file instead of previewing file from quick open](https://stackoverflow.com/questions/47249180/vscode-open-file-instead-of-previewing-file-from-quick-open)

[Visual Studio Code - #Context](https://code.visualstudio.com/docs/getstarted/keybindings#_contexts)

## おわり

結構長い間どうにかしたいと思っていたので、`ビュー:エディターを保持`の存在を知ったときは[@okazukiさんが以前書いていた`code -r .`](https://blog.okazuki.jp/entry/2019/09/12/171955)に匹敵する衝撃を受けました
ejsのテンプレートに文字列の配列(?)を渡すと「"」(ダブルクォーテーション)が削られてエラーになる対応方法

本内容を利用した場合の一切の責任を私は負いません。

# バージョン
- OS  
OS 名:                  Microsoft Windows 10 Home  
OS バージョン:          10.0.18362 N/A ビルド 18362   
システムの種類:         x64-based PC  
- Chrome  
バージョン: 77.0.3865.90（Official Build） （64 ビット）
- node.js  
node-v10.16.0-win-x64  
ejs@2.6.2  
express@4.17.1  

# 本題
ejsが古いためかもしれないが、文字列の配列(?)をテンプレートに渡すと、文字列の「"」(ダブルクォーテーション)括りが削られてエラーになってしまう。
その回避方法。

```Javascript:server.js
const express = require('express');
const ejs = require('ejs');

const App = express();

App.engine('ejs', ejs.renderFile);
App.get('/',
    function(req, res)
    {
        res.render('client.ejs',
            {
                ToTemplate: ["ab", "cd", "ef"]
            });
    });
App.listen(8080);
```

```Javascript:views/client.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>double quotation into array by ejs</title>
<script id="script_1">
var no_good_1 = <%= ToTemplate %>;
var no_good_2 = [<%= ToTemplate %>];
<%
var no_good_3 = [];
var good = [];

for (var i = 0; i < ToTemplate.length; i++)
{
    no_good_3.push(ToTemplate[i].toString());
    good.push("\"" + ToTemplate[i].toString() + "\"");
}
%>
var no_good_3 = [<%- no_good_3 %>];
var good = [<%- good %>];
</script>
</head>
<body>
「&lt;script id="script_1"&gt;」タグ内<br>
<br>
<script>
var content = document.getElementById("script_1");
document.write(content.text);
</script>
</body>
</html>
```

上記の結果。

```HTML:out.htm
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>double quotation into array by ejs</title>
<script id="script_1">
var no_good_1 = ab,cd,ef;
var no_good_2 = [ab,cd,ef];

var no_good_3 = [ab,cd,ef];
var good = ["ab","cd","ef"];
</script>
</head>
<body>
「&lt;script id="script_1"&gt;」タグ内<br>
<br>
<script>
var content = document.getElementById("script_1");
document.write(content.text);
</script>
</body>
</html>
```

```TEXT:display.txt
「<script id="script_1">」タグ内

var no_good_1 = ab,cd,ef; var no_good_2 = [ab,cd,ef]; var no_good_3 = [ab,cd,ef]; var good = ["ab","cd","ef"];
```

上記は下記のgithubに。 
https://github.com/github895439/other_qiita/tree/master/double_quotation_into_array_by_ejs

# 主な履歴
2019/10/16　JSONの方法を追加(good_2、good_3)
Hyper-V有効化でのVirutalBox (AMD編) 

# 結論
現時点(2019/10/11)、Zen系(AMD)のCPUだと、Hyper-Vを有効にするとVirtualBoxでVMが起動しない。

# 環境
VirtualBox 6.0.12
OS: Windows10 Pro 18362
CPU: Ryzen 9 3900X
MB: PRIME X570-PRO 
BIOS: 1201(AGESA 1.0.0.3ABBA)
メモリやグラボなどは影響がないので割愛。
2019/10/11時点で最新の状態です。

# 具体的に何がどうだったのか
Hyper-Vを有効にする前に、BIOS画面でSVM ModeがEnableになってることを確認しています。
タスクマネージャーのパフォーマンスのCPUのところで、「仮想化: 有効」となってるのも確認しています。
また、HWiNFOでAMD-Vが有効化(緑色)ことも確認しています。
この状態で、VirutalBox上でVM(CentOS8 64bit)が起動することは確認しています。

Hyper-Vを有効後、念のためにVirtualBoxを再インストール(リペア)を行ってます。
もちろんBIOSは変更していないので、SVM ModeがEnableのままの状態です。
タスクマネージャーでも、「仮想化: 有効」のままです。
ただし、HWiNFOではAMD-Vが非サポート状態(灰色、ただし無効化なら赤色)になっていました。
これはおそらく、Hyper-Vになってると、AMD-Vではアプリ側から仮想化関連のAPIが触れなくなってるからかなと思います。
で、VirutalBoxでVMを起動しようとすると、すぐに「AMD-V is not available」とエラーになります。
これはHWiNFOと同じ状態なのかなと思います。
VirutalBoxのVMの設定の「アクセラレーション」に準仮想化インターフェースを選べたり、「VT-x/AMD-V有効化」のチェックボックスがあるので、設定を変えてみてみましたが有効ではなかったです。
ひょっとすると、32bit OSなら「VT-x/AMD-V有効化」をオフにするのは有効だったかもしれませんが、それで動作したとしてもさすがに使い物にはならないので、試していないです。
なので、VirutalBox側なのか、Windows側かどっちなのかわかりませんが、現状のままではZen系のCPUだと起動しないです。
試したのはZen2ですが、Zen(1000番台)のCPUでも同様の症状の人がいるので、エラーメッセージを鑑みても、Zen系全般だと思います。
https://forums.virtualbox.org/viewtopic.php?f=6&t=90853&start=90

一方、Intel CPUで動いたという報告があるそうですが、全部が動くわけでもないっぽいので、まだまだこなれてない感じがします。


# ちょっとした補足
このあとHyper-Vを無効化しても、VirtualBoxは「AMD-V is not available」のままでVMが起動してくれないです。
これは、HWiNFOで確認すればわかるのですが、なぜかAMD-Vが非サポート状態のままになってしまってるからです。
いったん再起動してBIOSからSVM ModeをDisableにしてOSを起動、そのあと再起動してBIOSでSVM ModeをEnableにすれば、先ほどのエラーは解消します。
なにかしらOS内の状態（レジストリ？）がHyper-Vを無効化しただけだと更新されないってのが原因なのかなと思いますが、Hyper-Vを頻繁に有効/無効にする人はあんまりいないので、ほとんど問題にならないってことなんでしょうね。

あと、BIOSからSVM ModeをDisableにした状態では、HWiNFOではAMD-Vが無効化(赤字)の状態になってるのを確認しています。
タスクマネージャーでも、「仮想化: 無効」「Hyper-vサポート: はい」が確認できます。
一方、今回触れなかったCPU-Zだと、このあたりが思った通りの情報が取れてなかったです。
おそらく、HWiNFOで色がつく（緑赤）かつかないか(灰)の違い、言い換えるとCPUがAMD-Vをサポートしてるかしていないか、が取れているっぽいです。
なので、CPU-ZでAMD-Vの表示があった場合でも、AMD-V自体は無効化の場合があるので、AMD-Vの確認にはちょっと向いていないなと思いました。
【AWS】EC2のRuby/Rails環境構築中のwe're sorry, but something went wrongでハマった話

こんばんは！ポートフォリオをいよいよデプロイしようとした時にハマったエラー

## we're sorry, but something went wrong

```terminal
[ec2-user@ip-172-31-23-189 ~]$ unicorn_rails -c config/unicorn.rb -E production -D
```

で問題なくunicornが走ったと思い`http://<ElasticIP>:30000`にアクセスすると**we're sorry, but something went wrong**

#### いつも通り再起動

```terminal
[ec2-user@ip-172-31-23-189 ~]$ sudo shutdown -r now
[ec2-user@ip-172-31-23-189 ~]$ sudo service mysql stop
[ec2-user@ip-172-31-23-189 ~]$ sudo service mysql start
[ec2-user@ip-172-31-23-189 ~]$ cd /var/www/sample-app
[ec2-user@ip-172-31-23-189 sample-app]$ cd /var/www/sample-app
[ec2-user@ip-172-31-23-189 sample-app]$ unicorn_rails -c config/unicorn.rb -E production -D
```

まだnginxの設定していない状態だけど、いつもだとこれでうまくいくはず。だけど今回はダメだった。

## production.rbのログ確認

エラーの糸口が掴めずメンターに聞くと教えてくれた

```terminal
[ec2-user@ip-172-31-23-189 sample-app]$ cd log
[ec2-user@ip-172-31-23-189 log]$ cat production.log
```
`catコマンド`でログの内容を確認していくと見覚えのあるエラーを発見。`ActionView::Template::Error`

## 解決

トップページに設置している画像が存在してないよってことでした。

```erb
<%= image_tag("hoge.png"), class:"hoge" %>
```

`hoge.png`はapp/assets/images配下に置いてた画像で`gitignore`してました。

ひとまず`img src`に書き換える

```erb
<img src="http://hogehoge.png" alt="" class-"hoge">
```

これでもう一度、unicornを再起動して走らせたら無事にアクセスできました。

## アセットファイルをコンパイル

```terminal
[ec2-user@ip-172-31-40-237 sample-app]$ rails assets:precompile
Yarn executable was not detected in the system.
Download Yarn at https://yarnpkg.com/en/docs/install
```

怒られた。

```terminal
[ec2-user@ip-172-31-40-237 sample-app]$ npm install yarn -g
//これでも怒られたら
[ec2-user@ip-172-31-40-237 sample-app]$ sudo npm install yarn -g
//これでいけるはず
[ec2-user@ip-172-31-40-237 sample-app]$ rails assets:precompile
~~
success Saved lockfile.
//unicornをkill -9 [pid]してunicorn再起動
[ec2-user@ip-172-31-40-237 sample-app]$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D
```

無事にレイアウトも綺麗になりました。

>参考
EC2にてnpm install yarn -gが失敗する
https://qiita.com/tsumita7/items/a40a367088018b5bbe33

## まとめ
2度目のデプロイですが、やはり一筋縄ではいきません。ハマったエラーはメモって次回はハマらないようにしていきます。

#### 終わり
Firebase めちゃ便利！Onekilo (iosアプリ）リリースしました！

# Firebase めちゃ便利!! Onekiloリリースしました！

### Outline 
- 自己紹介
- Onekiloとは？
- Firebase のおすすめ点（もうみんな知ってるか笑)
- 最後に

##　自己紹介

初めまして！
立命館大学理工学部3年の葛上です！[watnow](www.watnow.jp)の代表をしています！！
[Twitter](https://twitter.com/ankuma777)フォローしてください！[Facebook](https://www.facebook.com/kaito.kuzukami.5)も友達になってください！

#### メンバー
ios 2人
UI/UXデザイナー　1人
動画作成　1人
の計４人で開発しました。

ios 開発歴はまだ2年目で、今まで開発したサービスは５つほどしかありません。
Firebase に関しては、一年前にRealtimeDatabase 少し使ってtwitterみたいなのを使ったくらいです！


## Onekilo とは？

今回作成したサービスが[Onekilo](https://apps.apple.com/jp/app/onekilo/id1480858532)になります！
抽象的ではありますが、

##### 「今すぐ」何かするって当たり前になってきてるな

と思い、足掛かりとしてマッチングアプリを作りました。
概要としては　1km圏内の人とランダム通話ができると言う事です。
マッチング界はほとんどレッドオーシャン状態になっていますが、
すんごいニッチなターゲット選定をしています笑　そこが売りであり、僕たちの強みでもあり弱みでもあります笑
<img width="375" alt="IMG_642E445D70BF-1.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310283/dbe85efa-5c32-aed5-136a-82f48f07d45e.jpeg">

#### onekiloで使用したFirebaseの機能

(本音を言うとアプリに関係なく全て活用したかったです笑)
<br>

- Authentication
    - ユーザー登録する際に用いました
- Cloud Firestore
    - Database として使用しました
- Storage
    - 画像の保存や引っ張てくるのに用いました。
- Remote Config
    - 強制的にバージョンをアップデートを行うために用いました！（すんごい便利)
- Cloud Messaging
    - ユーザーに通知を送るために使用しました。
- アナリティクス（全て）
    - 実際にユーザーの反応を見るのにすごく便利です。

##### 他にもML Kit とか使いたかったです。。。
#### 上記の使い方などは要望があれば別で描こうと思います。

## 最後に

実は今年の4月くらいにOnekiloのアイデアが自分の頭の中ででていました。

こんなん誰も使わんやろと思いながら３ヶ月くらいすぎて、Cyber Agentやリクルートのインターンに参加させていただいた際にちゃんと事業戦略練ればいけるんじゃないかと期待してくれたのが今回僕が動く結果になりました。

ありがとうございます。


「マッチングサービスはレッドオーシャン」
「半径１kmのマッチングはニッチすぎる」

と指摘されることは多々ありますが、自分の事業戦略を通して勝ち筋通りに進めたらいいなと思います。
もっと書きたいことはありますが、このような話は[note](https://note.mu/ankuma/n/na4900a62a258)に記しますので興味ある方は読んでください。。！

最後にベータ版ではありますが、[Onkilo のインストール](https://apps.apple.com/jp/app/onekilo/id1480858532)をよろしくお願いいたします。

最後まで読んでいただきありがとうございます。

watnow
mememe
代表
葛上
SFTPサーバのCSVをトレジャーデータに取り込む【備忘録】

【やりたいこと】
SFTPサーバに置いてある売上CSV（/treasure/uriageYYYYMMDDHHmmss.csv）をトレジャーデータ（以下TD）のDBテーブルとしてインポートする。

【ToDo】
①ブラウザでTDサイトにログイン
クラウドの名称はペリオン？

②左端のツールバーみたいなのの一番上「Integrations Hub」（Versionなどによっても変わるかも）をクリック
サブメニューが表示されるので「Catalog」をクリック
接続先のカタログ？メニューが表示されるので「SFTP」をクリック
Authentincation？の作成ダイアログが表示されるので
/////////////////////////////////////////////////////////////////////
「Host」：SFTPサーバのIP
「Port」：22（デフォルト）
「User」：ログインID
「Authentincation mode」：Password
「Password」：サーバのログインパスワード
以下デフォルト
/////////////////////////////////////////////////////////////////////
を入力して「Continue」ボタンを押すと次のダイアログが表示されるので適当に入力して「Done」ボタンを押すとAuthentincation？が作成される。

③「Catalog」メニューの上の「Authentications」をクリックするとAuthentincationのリストが表示されるので先ほど作成したものを探し「New Source」のボタンを押す
ダイアログが表示されるので作成物に応じて適切な値を入力していく
/////////////////////////////////////////////////////////////////////
Is user directory root?：取込ファイルのフォルダrootじゃないしとりあえずチェックを外す
Path prefix：/treasure/uriage
Path match pattern：.*csv
Incremental?：チェックを入れると上記ファイル名の条件を満たしたファイルが追加されるとテーブルに累積していってくれるらしい
Start after path：
/////////////////////////////////////////////////////////////////////
「Next」ボタンを押すとSource Previewが表示されるので「Next」ボタンを押して次のダイアログに進む
/////////////////////////////////////////////////////////////////////
Database：インポート先のDBを選択
Table： Create New Table
インポートするテーブル名を入力
以下デフォルト
/////////////////////////////////////////////////////////////////////
その後もダイアログが表示されていくので適当に入力して設定を終わらせるとSourceが作成されテーブルも作成される
Realm StudioでDBの内容を確認する方法【Android・Mac】

Realm Studioでデータベースを確認する方法について紹介します。
他のサイトで解説している通りでは上手くいかなかったため、
僕の場合は最終的にこのような方法になりました。
参考になれば幸いですm(_ _)m

※環境はAndroid Studio3.5

## adbコマンドの有効化
adbコマンドを実行して、

```
bash: adb: command not found
```

と出る場合は、adbコマンドを有効化する必要があります。

Android Studioの「ファイル」→「その他の設定」→「デフォルト・プロジェクト構造…」にある、
Android SDK ロケーションのファイルパスをコピーします。
![Screenshot 2019-10-11_19-23-05-223.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330156/7bcf2411-f208-7a55-f424-b74389cda2d2.png)
![Screenshot 2019-10-11_19-25-16-061.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330156/11d8951e-b523-0b6f-ed1a-14bd440b2517.png)

Android Studioのターミナルに、コピーしたファイルパスを以下のように入力します。

```
export PATH=$PATH:/Users/ユーザー名/Library/Android/sdk/platform-tools
```

これでadbコマンドが使用できます。

## AndroidのDBをインポートする
続いてAndroid Studioのターミナルに、

```
adb kill-server

adb start-server

adb shell
```

を入力します。

次にプロジェクト名をコピーして以下のように実行します。

```
run-as com.example.hoge

cd files

cat default.realm > /sdcard/export_db.realm
```
３行目の`export_db`の部分は任意の名前で構いません。

続いて、「control + d」を2回入力してshellを終了し、

```
adb pull /sdcard/export_db.realm ./
```

これでDBを取得できました。

あとはRealm Studioで、プロジェクトフォルダに保存されたRealmのファイルを開けばデータの中身が見れます。
![Screenshot 2019-10-11_19-56-46-428.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330156/5789f3a3-c3f2-06d9-64ec-a3953bf971a8.png)

## おわり
adbコマンドを有効化するところから解説している記事がなかったため書いてみました。
【初心者向け】PG二年目の私がコーディングでもっと早くから気をつけたかったこと

## はじめに
コードを書く時、「こういう時ってどう書いたらいいの？」「そもそも何が綺麗なコードなの？」と悩んだことはありませんか？
私はあります。
この記事はかの有名な `リーダブルコード` を読んだ際、私自身が出来ていなかったこと、意識しなければならないと思ったことを纏めたものです。
自分なりに纏めていますので、おかしい記述等もあるかもしれませんが、その際はご指摘ください。

## 命名規則について
### 具体的な名前を付ける
- 誰が見ても、その名前だけで以下の２点が分かるような名前を付ける。
  - 何をするメソッドか
  - 何が格納されている変数か
- 以下の項目を意識すると具体的な名前になりやすい。
  - 動詞を使うときは、より明確な動詞を選ぶ。汎用的なものはなるべく使わない。（類語を調べ、その中から選ぶといい）
     - 私は[こちら](https://qiita.com/Ted-HM/items/7dde25dcffae4cdc7923)の記事を参考にするようにしています。
  - 値の単位を付ける。（時間、サイズなど）
  - 「どんな」を意識する。具体的にいうと形容詞や中身を連想できる名詞を添える。 
     - `records` よりも `messages`、 ハッシュを格納する変数であれば`○○_hash` の方が直感的に中身の想像が出来る。

## リファクタリングするときに意識すること
### ベースとして意識することについて
- 同じことは何度も書かない。
  - 同じことを何度も書く必要がある場合はメソッドに分ける、変数に格納する
- 並び順に意味を持たせる。
  - 複数変数が出てくる場合、定数が複数出てくる場合はその並びに意味を持たせる。
    - 例：アルファベット順、画面での並び順、ファイルへの出力順など
- 行数が多い場合は適度に改行を挟み、見やすくする。
    - 例：処理のまとまり単位で改行、など。

## コメントについて
### 書いてはいけないコメント
- コードを見れば誰でも分かること
- メソッド名や変数名について説明するようなコメント（それは付けている名前が悪い）

### 不具合があるコードに付けるコメント
- 以下のprefixを付ける

|prefix|意味|
|:-----|:---|
|TODO:|あとで直す|
|FIXME:|既知のバグがあるコード|
|HACK:|あまり綺麗じゃない|
|XXX:|大きな問題がある|

※`prefix`が大文字の場合は大きな問題、小文字の場合は小さな問題という意味合いになります。
※`TODO(ラテ太郎):` みたいな書き方をします。

### コメントを書いてもいい場所
- 読み手が一見で分からない or 疑問を持ちそうなところ
 - なんで？これは何？と思われるようなコードであるならば、コメントの記載が必要です。
- 間違えて使われる可能性がありそうなところ

### 簡潔なコメントの書き方
- `その`のような指示語は避ける。（自分が思っているものと違う認識をされる可能性がある為、具体的に書くのが良いです。）
- `かどうか`という表現は使わない。
  - どうなったらどう、という書き方を心がける
  - `×： Aかどうか` `○
: AならばB`
- 情報密度の高い言葉を使う。
  - 自分の伝えたい内容が集約された言葉を選ぶことを意識すればコメントが簡潔になります。
- 実例を書く

## ループ・ロジックの単純化
### 条件式
- 条件は肯定が正義。（わかりやすい）
  - ド・モルガンの法則を駆使してなるべく肯定的な条件になるようにする。否定の否定、は使わない。悪。
- 目立つ条件、重要な条件から書く。
- 何でもかんでも三項演算子を使わない（わかりにくくなるため）
- 早期リターンできる時は早期リターンする（早期リターンすることでネストが減る。）


## まとめ
やっぱり命名って難しい！！！！！
まずは上記のような、常に付きまとってくる問題と戦いながら、可読性の高いコードを書けるようになりたいと思います。

## 参考
- [リーダブルコード](https://www.amazon.co.jp/%E3%83%AA%E3%83%BC%E3%83%80%E3%83%96%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89-%E2%80%95%E3%82%88%E3%82%8A%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%8F%E3%81%9F%E3%82%81%E3%81%AE%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%A7%E5%AE%9F%E8%B7%B5%E7%9A%84%E3%81%AA%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF-Theory-practice-Boswell/dp/4873115655)
データを削除しようとしたらそのテーブルに主キーがなくて消せないんだけど

# 冒頭

LaravelからRailsに改修をする案件をしていたときのことで、
既存のDBがあるためそれを`self.table_name`で指定してあげて使えるようにしているのですが、
データを論理削除する際に以下の問題にぶち当たりました。

# 問題のエラー

```console
ActiveRecord::StatementInvalid (Mysql2::Error: Unknown column 'テーブル名.' in 'where clause')
```

え、なんでカラムがないの？
と思いSQLを出力させたところ、

```sql
UPDATE `テーブル名`
   SET `テーブル名`.`deleted_at` = '2019-10-11 18:12:27'
     , `テーブル名`.`updated_at` = '2019-10-11 18:12:27'
 WHERE `テーブル名`.`` IS NULL
```

といった状態に。

DB設計書を確認したところ、どうやら主キー(Primary Key)がこのテーブルないとさ。
なるほど、そりゃ主キーないんだからカラムが空なわけ。

# 調査

where句を別のものに指定できないものかと調べたらRails6から実装されている[こんなもの](https://github.com/rails/rails/blob/f4d2eadaaa4e1af7a9178405096099c3781d51a0/activerecord/lib/active_record/relation.rb#L605)を見つけました。

```ruby
# Finds and destroys all records matching the specified conditions.
# This is short-hand for <tt>relation.where(condition).destroy_all</tt>.
# Returns the collection of objects that were destroyed.
#
# If no record is found, returns empty array.
#
#   Person.destroy_by(id: 13)
#   Person.destroy_by(name: 'Spartacus', rating: 4)
#   Person.destroy_by("published_at < ?", 2.weeks.ago)
def destroy_by(*args)
  where(*args).destroy_all
end
```

だけどこれ結局のところ`delete_all`使ってるんで意味ないやん。
あ"　き"　ら"　め"　た"

# 対応

生SQLをつかうことにした。

```ruby
sql = <<-SQL
UPDATE `テーブル名`
   SET `テーブル名`.`deleted_at` = '#{Time.current}'
     , `テーブル名`.`updated_at` = '#{Time.current}'
 WHERE `テーブル名`.`カラム名` = 'XXX'
SQL

con = ActiveRecord::Base.connection
con.execute(sql)
```

# Railsつよつよの方へ

もしなにかしら方法をしっていたら教えてください🙇‍♂️
いや、普通に主キー作ればいいんだけどさ...
【Movable Type】MTで特定の記事だけ上位に表示させる

##開始タグ
Movable Typeでアーカイブページで特定の記事だけ上位に表示させたいという要望のもと実装したのでメモ。

・カスタムフィールドに数値を入力した場合は優先して上位に表示される
・入力のないものは日時順でソート。

##方法

１、まずはカスタムフィールドを作成。
※多言語展開する必要があれば、システムで作成してもいいかも。

今回は例として「cf_runk」というベースネームで作成。

２、記事一覧ページで、`Entries`タグで以下のように記述するだけでOK。

```mt:アーカイブテンプレート
<mt:Entries sort_by="field:cf_runk" sort_order="ascend>
</mt:Entries>
```

3、記事内のカスタムフィールド入力欄に数値を入力。（1,2,3・・・など）

これで記事一覧でカスタムフィールドへ値を入れた記事が上位に表示されるようになりました。
記事一覧では数値の若い順から表示されます。

##閉じタグ
連番（1,2,3・・・4,5,6・・・）にしないと優先された記事の順番を正確に操作できないのが解決できなかった。
１００とか1000とか入れてみたけれど、優先はされども優先された記事内の順番を思い通りにはできず。。
途中で割り込ませたい場合なんかはどうしようか・・・と思いつつ、今後よりよい方法を模索していきたいと思います。
会社で書いてるコードも「OSSで公開しちゃえ！」ってしたいからOSSガイドラインを作った

エンジニアをやっている限り、OSSの恩恵にあずかりまくりなので何かしらの形で恩返しというか貢献したいって気持ち少なからずあると思う。僕はある。でも、実際OSSを公開とかコントリビュートするのってすごくハードルが高いイメージが強い。

OSSを公開したり、コントリビュートしたりする精神的な敷居をさげるために、どうしたらいいのかなぁって思いまずはガイドラインを作ってみることにした。率先してOSSに取り組んでるなかひこくん ([@takanakahiko](https://twitter.com/takanakahiko)) にインターンで手伝ってもらったり、Debianのメンテナーをやっている Hideki Yamane さんにレビューしてもらったり、本当に感謝しかない。

<img width="1324" alt="スクリーンショット 2019-10-11 19.25.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9416/8a47e978-0649-cb2a-d524-27dbbf82b640.png">
https://sites.google.com/gaiax.com/gaiax-oss-guideline

会社の社員としてOSSに取り組むにあたり、あれやこれやとルールや注意事項や手続きやら、理解しないといけない条件などを、できる限り減らして、**カジュアルにやっちゃいなよ！** という思い（方針）にこだわった。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">「公開する以上、OSSはちゃんとしなくてはいけない」とか「メンテナンスする責務がある」とか思いがちなんだけど、そうじゃなくて、自分たちが良いと思うユースケースの範囲内で、メンテナンスする「権利」があるんだよ、と思っているしそう言う話をしたりしていた</p>&mdash; songmu (@songmu) <a href="https://twitter.com/songmu/status/1182139986562301952?ref_src=twsrc%5Etfw">October 10, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

 [@songmu](https://twitter.com/songmu) さんもこんなツイートしていて、さすがだなって思う。そうそう、こういうこと言いたかった。

あと、最近参加してすごくよかったイベントが、[OSS Gate](https://oss-gate.github.io/)！
まだOSSに貢献したことがない人を、半日フルサポートしてOSSの門を手を繋いで一緒にくぐってくれるイベント。もし、すこしOSSに貢献することに興味があるけど、まだ実行する勇気や手段がわからない人がいれば絶対に参加した方がいい。
イベントは経験者と未経験者のマンツーマン制（そこがすごく良い）で、毎回サポーター不足で参加人数に限りがあるため、がんばって参加できるタイミングつかみましょう。

以上
WPFでカーソルの位置を取得する(C#)

# はじめに
ウィンドウ外にカーソルがあってもその位置を取得する方法です。
調べてもすぐに出てこなかったため、備忘録として残します。

# 動作環境
- Visual Studio Community 2019 - 16.3.2
- .NET Framework - 4.7.03190

# 方法
`System.Windows.Forms`を使用します。まずはソリューションエクスプローラーから`参照`を右クリックし、`参照の追加`を選択します。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398510/afe41707-7996-45d7-4c29-c4c8dae6bedb.png)

検索欄から"Forms"等と入力して、` System.Windows.Forms`を**チェック**して`OK`を選択します。
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398510/e61a66cb-17e5-8ee5-2975-3ec5e3ed01a2.png)

あとは`System.Windows.Forms.Cursor.Position`で場所が取得できます。

```csharp
System.Drawing.Point p = System.Windows.Forms.Cursor.Position;

// Labelを作成し、そこに出力するサンプル
label.Content = "(x, y) = ("+ p.X +", "+ p.Y +")"; // p.X, p.Yで取得できます。
```

`System.Drawing.Point`で怒られたら同じく`参照の追加`から`System.Drawing.Point`を持ってくると大丈夫です。
ブランチ名をコミットメッセージで使いたい時のコピーコマンド

e.g.)
ブランチ名:`feature/add_model_for_new_features`

## ターミナルに出力したい
コマンド:`cm`

```sh
alias cm="git symbolic-ref --short HEAD | sed -e 's/_/ /g' | sed -e 's/.*\///g'"
cm
# => add model for new features
```

## クリップボードにコピーしたい
コマンド:`cmp`

クリップボードにコピーされるためcmd-vで"add model for new features"の貼り付けができる

```sh
alias cmp="git symbolic-ref --short HEAD | sed -e 's/_/ /g' | sed -e 's/.*\///g' | tr -d '\n' |pbcopy"
cmp
```

## ブランチ名をコミットメッセージにしてコミット
コマンド:`cmcm`

もう一気にコミットまでしたい場合。

```sh
alias cmcm="git commit -a -m '`cm`'"
cmcm
```

## aliasの設定

```sh
alias cm="git symbolic-ref --short HEAD | sed -e 's/_/ /g' | sed -e 's/.*\///g'"
alias cmp="git symbolic-ref --short HEAD | sed -e 's/_/ /g' | sed -e 's/.*\///g' | tr -d '\n' |pbcopy"
alias cmcm="git commit -a -m '`cm`'"
```
Talentio API 候補者一覧

## API
https://talentio.com/api/v1/candidates

## 候補者情報
|column|内容|examples|
|---|---|---|
|id|id|--|
|firstName|名|一郎|
|lastName|姓|田中|
|email|Email| `tanaka@example.jp` |
|description|補足|補足情報|
|requisition|求人情報|詳細は `候補者情報 requisition` を参照|
|registeredAt|登録日|2019-10-11T16:37:47+09:00|
|appliedAt|応募日|2019-10-11T00:00:00+09:00|
|fixedAt|更新日|2019-10-11T00:00:00+09:00|
|joinedAt|入社日・入社予定日|2020-02-01T00:00:00+09:00|
|stages|選考情報|詳細は `候補者情報 stages` を参照|
|status|ステータス|・ongoing = 選考中<br>・reject = 辞退<br>・fail = 不合格<br>・pass = 採用<br>・poolActive = コンタクト中<br>・poolInactive = 非コンタクト中<br>※内定しているが内定承諾前の場合は ongoing。採用 = 内定承諾|
|channelType|採用チャネル|・agent = エージェント（個別担当）<br>・custom = カスタム<br>・employee = 社員紹介<br>・site = 応募ページ<br>・agentCompany = エージェント(会社)|
|agent|エージェント担当者の情報|channelType が agent のときのみ出力される<br>詳細は `候補者情報 agent` を参照|
|agentCompany|エージェント会社の情報|詳細は `候補者情報 agentCompany` を参照|
|customChanneName|カスタム採用チャネル名|channelType が custom のときのみ出力される<br>※Talentio への連携対応をされていない採用チャネルを手動登録した場合など|
|priority|優先度|0-10|
|tags|タグ|詳細は `候補者情報 tags` を参照|
|customFields|カスタムフィールド|詳細は `候補者情報 customFields` を参照|

## 候補者情報 - requisition
|column|内容|examples|
|---|---|---|
|id|id|--|
|name|求人名|カスタマーサクセス|
|active|募集中 or 募集終了|true or false|

## 候補者情報 - stages
|column|内容|examples|
|---|---|---|
|id|id|--|
|type|選考種別|・contact = コンタクト<br>・resume = 書類選考<br>・interview = 面接<br>・reference = リファレンスチェック<br>・final = 内定判定|
|step|ステップ数<br>※同じ種別の選考があった場合の順番を表す数字|1|
|status|ステータス|・ongoing = 選考中<br>・fail = 不合格<br>・pass = 合格<br>|
|scheduledAt|予定日|2019-10-08T10:00:00+09:00<br>※未設定の場合は false が設定される|
|fixedAt|更新日|2019-10-08T10:00:00+09:00|
|description|補足|補足説明の文字列|

## 候補者情報 - agent
|column|内容|examples|
|---|---|---|
|id|id|--|
|name|エージェント担当者名|鈴木次郎|
|email|エージェント担当者のEmail|`agent@example.jp`|
|active|アクティブ or 停止中|true or false|

## 候補者情報 - agentCompany
|column|内容|examples|
|---|---|---|
|id|id|--|
|name|エージェント会社名|なんたらエージェント|

## 候補者情報 - tags
|column|内容|examples|
|---|---|---|
|id|id|--|
|name|タグ名|自分でつけた任意のタグ名|

## 候補者情報 - customFields
|column|内容|examples|
|---|---|---|
|name|カスタムフィールド名|自分でつけた任意の名前|
|value|カスタムフィールド値|設定した値。値の種類は設定した内容次第|

## 追記 - 2019/12/10
Talentio に公式のAPIドキュメントが整備されました！

https://www.talentio.co.jp/developers

## 資料
* [APIの利用 | Talentio Help Center](https://intercom.help/talentio/ja/articles/1957111-api%E3%81%AE%E5%88%A9%E7%94%A8)
AWS Elastic Beanstalk 環境状態監視

#問題
AWS EBでヘルスチェックには問題ないが、一部のインスタンスが障害のままで不安定の状態が続く。

#ソリューション
インスタンスごとzabbixに自動登録で監視したが、EB環境が変わる度にインスタンスが入れ替わりゴミホストが増える。しかもzabbixの動作が不安定になったため中止した。（中止すると安定した・・・当時VER3.0.2）
環境状態をまとめ評価する監視に変更。

#Zabbix
  * AWSプロファイル作成: aws configure --profile [マクロ{$ACCOUNT}]

  * マクロ
    * {$ACCOUNT}: アカウント（複数アカウントがある場合）
    * {$EB_APP}: アプリケーション名
  * アイテム
    * 名前：EnvStatus
    * タイプ：外部チェック
    * キー：cw_eb_status.sh["{\$ACCOUNT}","{\$EB_APP}"]
  * トリガー
    * 条件式: 3回連続「Ok」ではないと障害！ {host:cw_eb_status.sh["{\$ACCOUNT}","{\$EB_APP}"].count(#3,'Ok')}=0

```bash:cw_eb_status.sh
#!/bin/bash

Account="$1"
AppName="$2"

export AWS_PROFILE=$Account

result=`aws elasticbeanstalk describe-environments --application-name ${AppName} \
        | jq '.Environments[0].HealthStatus' | sed 's/^.*"\(.*\)".*$/\1/'`

echo $result
```

#その他
zabbixの経由にしないのであればEBコンソール上にある「アラーム（CloudWatch）」を利用してもよい。

#参考
jq前

```bash
{
    "Environments": [
        {
            "EnvironmentName": "xxx-env-xxxxxa",
            "EnvironmentId": "e-xxxxxjvc",
            "ApplicationName": "xxxx",
            "VersionLabel": "app-xxxx-xxxxx_170739",
            "SolutionStackName": "64bit Amazon Linux 2018.03 v2.8.14 running PHP 5.6",
            "PlatformArn": "arn:aws:elasticbeanstalk:ap-northeast-1::platform/PHP 5.6 running on 64bit Amazon Linux/2.8.14",
            "Description": "Environment cloned from xxx-env-xxxxxa from the EB CLI using \"eb clone\"",
            "EndpointURL": "awseb-e-w-AWSEBLoa-xxxxxxxxx-1248087954.ap-northeast-1.elb.amazonaws.com",
            "CNAME": "xxx-env.elasticbeanstalk.com",
            "DateCreated": "2019-10-02T08:04:01.469Z",
            "DateUpdated": "2019-10-10T02:15:31.146Z",
            "Status": "Ready",
            "AbortableOperationInProgress": false,
            "Health": "Green",
            "HealthStatus": "Ok",
            "Tier": {
                "Name": "WebServer",
                "Type": "Standard",
                "Version": "1.0"
            },
            "EnvironmentLinks": [],
            "EnvironmentArn": "arn:aws:elasticbeanstalk:ap-northeast-1:xxxxxxxx396:environment/xxx/xxx-env-xxxxxa"
        }
    ]
}
```
【Ruby】Zlibを使用して文字列を圧縮・展開する

## 事前準備

特に必要なし。

## サンプルコード

```ruby
# frozen_string_literal: true

require 'zlib'

# 圧縮前の文字列
str = 'Hello World' * 10_000

# 圧縮レベルを指定
# level = Zlib::NO_COMPRESSION # 圧縮しない
# level = Zlib::BEST_SPEED     # 速度優先で圧縮率は低い
level = Zlib::BEST_COMPRESSION # 圧縮率優先で速度は遅い

# 圧縮
deflated_str = Zlib::Deflate.deflate(str, level)

# 展開
inflated_str = Zlib::Inflate.inflate(deflated_str)

puts str.bytesize          # => 110000
puts deflated_str.bytesize # => 252
puts inflated_str.bytesize # => 110000

puts str == inflated_str # => true
```

## 参考

- [標準添付ライブラリ紹介 【第 11 回】 zlib](https://magazine.rubyist.net/articles/0018/0018-BundledLibraries.html)
- [library zlib \(Ruby 2\.6\.0\)](https://docs.ruby-lang.org/ja/latest/library/zlib.html)
【RDB】正規化について5分で理解する

リレーショナル・データベースにおいて、必須技術である**正規化**について、例を用いて簡単に説明します。

#1.正規化とは

>
RDBの正規化とは、RDBにおいて、正規形と呼ばれる形式に関係（リレーション）を準拠させることにより、データの一貫性の維持と効率的なデータアクセスを可能にする関係設計を導くための方法である。[(Wikipediaより)](https://ja.wikipedia.org/wiki/%E9%96%A2%E4%BF%82%E3%81%AE%E6%AD%A3%E8%A6%8F%E5%8C%96)
>

要は、正規形と呼ばれる形式に基づいてデータ群を整理していこうって話です。
正規化の段階には、第1～第5正規形およびボイスコッド正規形がありますが、今回は、データベースを設計する際に一般的に用いられる第1～第3正規形までを説明します。


#2.具体例
##初期状態
<img width="672" alt="スクリーンショット 2019-06-26 13.18.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270696/f67434de-5ed8-48db-90bb-c0a7fed35aae.png">
このような、よくある発注先テーブルを元に考えます。
上記のテーブルの場合、一つの発注先に対して異なる商品の項目が存在しています。
このような(正規化が全く行われていない)テーブルを**非正規形**と言います。

##第1正規形
***第1正規形とは、非正規形なテーブルをデータベースに保存できる形にすること***

データベースに保存するためには、繰り返し項目のある部分を別レコードとして独立させなければいけません。また、「合計金額」の列は、それぞれのレコードに表示できないので、削除します。

初期状態の表を、下記のようにすればOKです。
<img width="674" alt="スクリーンショット 2019-06-26 13.26.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270696/7f25604d-8388-ee94-e816-7b61c035351b.png">

##第2正規形
***第2正規形とは、関連従属性のあるカラムを別テーブルとして分離すること***
※関連従属性とは、主キー(Primary Key)であるカラムを決定すると、それに紐付く他のカラムが導き出せる関係を表す
※主キーとは、テーブル内のレコードを一意に特定できるカラムのこと

今回、「発注番号」と「商品」を主キーとします。
<img width="674" alt="スクリーンショット 2019-06-26 15.16.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270696/d0fa3966-8772-8ccf-677a-c87e21608f66.png">
主キーに選ばれたカラムを元にテーブルを分離します。
<img width="599" alt="スクリーンショット 2019-06-29 13.53.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270696/67a29e73-0fa5-6b6a-d209-882f2a0c2634.png">

##第3正規形
***第3正規形とは、推移従属性のあるカラムを別テーブルとして分離すること***
※推移従属性とは、主キー(Primary Key)でないカラムを決定すると、それに紐付く他のカラムが導き出せる関係を表す
今回の場合、
<img width="396" alt="スクリーンショット 2019-06-26 15.32.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270696/a24fbc91-ab75-d70e-e9ff-699cb3d418cd.png">
ここが該当しますね。ここを分離します。
よって、第３正規形は、下記のようになります。
<img width="938" alt="スクリーンショット 2019-06-26 15.38.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270696/8eea6c0a-eb41-ed70-2ed5-dfacc95db7c0.png">

以上になります。
UE4で任意のコンパイラ（ビルドツール）を選択する方法

# 経緯
Visual Studio 2019 での開発中、突如不具合を引き起こした。

![q01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512539/7612d048-83c8-b547-d4c3-eb6cfa9c7e99.jpeg)


画像左が正常な挙動、右が不具合が起きたときの挙動。
等高線のような黒い帯が出て、遠景の山がおかしな形になっているのがわかる。
このとき、地形に関するコードやマテリアル等は一切弄っていなかった。

これの原因は、時折行われるIDEのアップデートを何気なくしていた行為でした。
一般的なプログラマーなら「特定の環境から変えない」のが一番安全だが、やってしまったものは仕方がない。戻せばよい。そう思っていた。

しかし、Visual Studio のアップデートは（原則）元に戻せないという事実が発覚。 Visual Studio Installer でもマイナーバージョンレベルでは戻せるようだがビルド番号までは戻せなかった。

調べていくと、UE4のツールチェイン（ビルドに必要なコンパイラやリンカ一式を扱うもの）の選択で固定できれば、突然挙動不審になることもない、ということがわかった。

# 本題
ということで、ツールチェイン（※）を明示的に指定してコンパイラのバージョンを固定させる方法を紹介します。
※ Visual Studio では「ビルドツール」という名称になります。以降ビルドツールと呼びます。

上記経緯と同等のバグ報告と、回避策が下記リンクに記載されていますが、補足を含め、別の回避策も合わせて紹介します。
https://developercommunity.visualstudio.com/content/problem/734585/msvc-142328019-compilation-bug.html

## 基本説明と主旨
UE4 での（Windows 上での）C++開発(UBT)では、Visual Studio (以降VS) 2017、VS2019、VSCode のいずれかを利用しますが、執筆現在、 VS2017 と VSCode はビルドツールは VS2017 用のもの（UE4 で決まったバージョン）を使用し、 VS2019 では、原則最新のビルドツールを使用します。

最新版のものを使用している場合、執筆時点でのビルドツールのバージョンは 14.23.28105 でした。
このバージョンで不具合が起きているので、インストール可能な前のバージョン、 14.22.27905 を使用します。
また、UE4.22.3での内容です。

## 手順
### 1.使用するビルドツールのインストール
Visual Studio Installer を起動し、個別のコンポーネントから「MSVC v142 - VS 2019 C++ x64/x86 ビルド ツール (v14.22)」を選択し、インストールします。

![q02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512539/bc751912-b575-589e-576f-7d675c3c5196.jpeg)

インストールが終わると、 `C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC` （※）に、ディレクトリ名がバージョンの名前（執筆時点で 14.22.27905）でビルドツール一式が配置されます。ビルドツールの選択には~~このバージョン名を使用します~~（以下追記参照）。最新のバージョンの方も置かれていて複数あるはずなのでよく確認してください。

※ Visual Studio のエディションでパスが若干異なるはずなので適時読みかえてください。
#### 1.a （追記）ビルドツールのバージョンについて
UE4.24（4.23は未確認）では、ディレクトリ名ではなく実際のツールにあるバージョンを参照するらしく、ディレクトリ名のバージョン表記と異なります（リビジョン番号がほんのちょっと違う）。
確認方法は対象ディレクトリ内にある bin フォルダ内以下のいずれかにある実行ファイルのツールチップに記載されたファイルバージョン、もしくはプロパティを開いて詳細タブ内で確認できます。

### 2.使用するビルドツールの指定
指定方法は２種類あります。

#### 2.a.環境（ユーザー）ごとに指定する
プロジェクト内のファイルをいじらずにデフォルトのビルドツールとして指定する場合です。
`%AppData%\Roaming\Unreal Engine\UnrealBuildTool` に、 BuildConfiguration.xml という、初期状態では内容が特に記載されていない xml ファイルがあります。
これを以下のように書き加えます。

```xml:BuildConfiguration.xml
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
	<WindowsPlatform>
		<Compiler>VisualStudio2019</Compiler>
		<CompilerVersion>14.22.27905</CompilerVersion>
	</WindowsPlatform>
</Configuration>
```

`Compiler` タグには使用するIDE名を半角スペースなしで記入してください。`CompilerVersion` タグには使用するビルドツールのフルバージョン名を半角で記入してください。

`Compiler` タグがないと VS2019 上でビルドする際、v14.22は古いバージョンである＝VS2017用と認識されてしまい、「VS2017のプロジェクトファイルじゃないとダメ」的なエラーを吐かれてしまいます。

#### 2.b.プロジェクトごとに指定する
Target.cs ファイルに記述することでビルドツールを指定する方法があります。
複数人で開発するプロジェクトで有効な方法です。

```csharp:ProjectName.Target.cs
using UnrealBuildTool;
using System.Collections.Generic;

public class ProjectNameTarget : TargetRules
{
	public ProjectNameTarget(TargetInfo Target) : base(Target)
	{
		// - 中略 - //

		WindowsPlatform.CompilerVersion = "14.22.27905";
	}
}
```

※(ProjectName).Target.cs 、(ProjectName)Editor.Target.cs 双方に記述する必要があります。

### 3.リビルドする
後はリビルドするだけで、指定したビルドツールで実行されます。
以降はこの設定が有効である間は使われ続けます。