OmniAICreator/Qiita-1.07M huggingface dataset:
MacでストレスなくVRChatを動かしたい

# 経緯
私の所属している、IT系メンバ多めなTRPGコミュニティで、
「リモートでもTRPGをやりたい」
「[VRChat](https://store.steampowered.com/app/438100/VRChat/)（Windowsで動作するVRチャットアプリ）を使ってTRPGをやってみたい」
という話が出ました。

Macしか持っていなかった私は急遽、Macに仮想のWindows環境を整えることにしました。

# この記事のゴール

* [Steam](https://store.steampowered.com/?l=japanese) の [VRChat](https://store.steampowered.com/app/438100/VRChat/) が快適に動作するような仮想Windows環境を、Mac上に構築すること

# 動作環境

## Macのスペック

そこまでいいスペックのMacではありませんが、快適にVRChatが動作するかどうかが今回の大きな検証ポイントでした。

```
Model Name: MacBook Air
Model Identifier: MacBookAir7,2
Processor Name: Intel Core i5
Processor Speed: 1.6 GHz
Number of Processors: 1
Total Number of Cores: 2
Memory: 8 GB
System Version: macOS 10.14.2 (18C54)
```

## 仮想化ツール

* [Parallels Desktop 15 for Mac](https://www.parallels.com/jp/) を使用 <br>今回は動作確認のため、無償トライアル版を利用しました。

## 仮想環境で動作させたOS

* Windows 10 バージョン1903

# 手順

何をやったかだけをメモ書きしておきます。

1. [Parallels Desktop 15 for Mac](https://www.parallels.com/jp/) のダウンロードとインストール
    * ガイドに促されて、ポチポチとクリックして進めるだけでインストール作業は終わりました。
1. Windows 10 OS のダウンロードとインストール
    * Parallelsのインストールが終わると、Windows 10 の OS のダウンロード＆インストールもガイドで引き続き案内されたので、これも促されるままにクリックしてすすめただけでした。
    * Windows 10 のインストールと初期設定が完了すると、こんな感じでMac上でWindows環境が使えるようになります。 <br>![win-on-mac.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132683/70f720fa-f0a6-957e-6f6a-d6f6d28c3586.png)

1. Steam と VRChat のインストール
    * Parallels で起動した Windows 10 上に、[Steam](https://store.steampowered.com/?l=japanese) と [VRChat](https://store.steampowered.com/app/438100/VRChat/) をインストールしました。
    * インストール手順などは各自で調べてみてください。

# 動作確認

VRChat on Windows 10 on Parallels on MacBook Air という動作環境で、特に問題なく快適に動作しました。
マイクやカメラの設定も特に必要なく Parallels がよしなにやってくれており、 Mac のマイクやカメラをそのまま使うことができました。
![vrchat-on-mac.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132683/7845d3c9-f8da-4cc7-64a4-8a7c4c48bc4e.png)

ちなみに、今回の用途に限っては、Mac の容量は 30GB 程空けておけば十分に足りるようでした。
![memory.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132683/09096935-9516-f50f-c11e-3c9722b7d611.png)

# 終わりに

やりたかったことができたので、 Parallels の製品版と Windows のライセンスはちゃんと購入することにします。
【jQuery】youtube動画の表示/非表示

##開始タグ
youtube動画をモーダルで呼び出す機会も増えていると思うのでメモ。

##やりたいこと
・youtube動画のサムネイルをクリックしたらモーダル表示
・モーダル内でyoutube動画を表示
・モーダルを閉じた時、youtube動画の再生をやめる

##方法
```html:sample.html
<figure class="modal_active modal01">
	<img src="http://img.youtube.com/vi/ここに動画IDを入れる/maxresdefault.jpg" alt="">
</figure>
<div class="youtube modal_area modal01">
	<iframe class="modal_box" src=""></iframe>
</div>
```

```javascript:sample.js
$(function() {
	$('.modal_active.modal01').click(function() {
		// オーバーレイ用の要素を追加
		$('body').append('<div class="modal-overlay"></div>');

		// オーバーレイをフェードイン
		$('.modal-overlay').fadeIn('slow');
		$('.modal_area.youtube.modal01')
			.fadeIn(300)
			.addClass('active');

		//　youtube動画表示（動画URLの挿入）
		$('.youtube iframe').attr(
			'src',
			'https://www.youtube.com/embed/ここに動画IDを入れる'
		);

		//モーダル外をクリックしたら閉じる
		$('.modal-overlay').click(function() {
			$('.modal_area.youtube.modal01')
				.fadeOut(300)
				.removeClass('active');

			//　youtube動画停止（動画URLの削除）
			$('.youtube iframe').attr('src', '');

			$('.modal-overlay').fadeOut('slow', function() {
				// オーバーレイを削除
				$('.modal-overlay').remove();
			});
		});
	});
});
```

まず、`sample.html`の`http://img.youtube.com/vi/ここに動画IDを入れる/maxresdefault.jpg`の部分は、対象のyoutube動画のIDを入れてあげれば動画に設定されているサムネイルを自動で表示してくれます。`sample.html`に記述されている書き方だと一番大きい画像サイズで表示してくれるので、CSSによる画像サイズの可変にも結構耐えられます。

`sample.js`に関しては、モーダルに関しては割愛しますが、youtube動画に関してはクリックしたらiframeのsrc属性を操作してあげることで表示・非表示が操作できます。

```javascript:
$('.youtube iframe').attr(
  'src',
  'https://www.youtube.com/embed/ここに動画IDを入れる'
);
```
ここでは、クリックしたら引数に指定したyoutube動画URLをiframeのsrcに与えることで、動画の表示を可能にします。

このままだとモーダルを閉じても動画が流れっぱなしになってしまうので、逆にモーダルを閉じるタイミングでiframeのsrc属性の中身を空にしてあげます。

```javascript:
//　youtube動画停止（動画URLの削除）
$('.youtube iframe').attr('src', '');
```
こうすることで、モーダルを閉じる際に動画を非表示ににして動画を止めたように表現できます。

ただ、この方法だと動画の再生途中でモーダルを閉じた場合、再生位置はリセットされてしまうので、こだわりの強い方はよりよい方法を探してみる方がいいかもしれません。

##閉じタグ
結構無理やりな気がする。
より良い方法をみつけたら修正します。
APIGateway→直接S3にファイルを保存するAPIを作成する方法

# 概要
タイトルそのままです。 **Lambdaを間に挟まず、** エクセルファイルをAPIGateway→S3にアップロードするAPIを作成しました。途中、主にバイナリデータの扱いで時間を消費したので備忘も兼ねてまとめます。

# 1.ベースとなるAPIをつくる
まず[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/integrating-api-with-aws-services-s3.html)にしたがってAPIを作成します。

# 2.認証を設定する
IAM認証周りは[こちらの記事](https://qiita.com/Fujimon_fn/items/5197e2e3db6de9a68401)を参考にしました。

# 3. base64を受け取ってバイナリに変換してもらう設定をする
これは設定にいくつかパターンがありえます。まずはこの[公式ドキュメントの表](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-payload-encodings-workflow.html)を確認しましょう。今回は表で上から２行目の「テキストデータ＋任意のデータ型＋未定義＋CONVERT_TO_BINARY => Base64でデコードされたバイナリBLOB」 にあてはまるように進めていきます。実はこれは最終的にたどり着いた解なので、私がハマったポイントを以下に紹介します。とりあえず作成したいだけの人は4まで飛ばしてください。

## 3-1. プチハマりポイント：FileReader
これはJSのFileReaderのハマりポイントですが、readAsDataURLを使っている場合は、[MDN](https://developer.mozilla.org/ja/docs/Web/API/FileReader/readAsDataURL)にあるように冒頭に `data:*/*;base64,`という文字列が挿入されるのでこれを外してからbodyに設定するようにしましょう。

## 3-2. ハマりポイント：binaryMediaType
実は、3で紹介している表を最初から参考にしていた訳ではありませんでした。初めはこの[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-payload-encodings-configure-with-console.html)にしたがって、まずは統合リクエストのコンテンツの処理を「バイナリに変換」に設定→binaryMediaTypeの設定等を行ったのですが、上の表をみるとわかると通り、今回の場合はbinaryMediaTypeの設定がいらなかったのです。
APIをデプロイするとDLできるSDKからAPIを呼び出すと、200で成功するのですが、いざS3でファイルを開くとbase64からデコードできていない…。しかも**この間なぜかマネジメントコンソール上からのテストは成功(=バイナリに無事変換されてS3に渡されていた)**していて余計に混乱の元となり、エンドポイントからのリクエストの投げ方が悪いのかとしばらく考えてしまいました。その後、この表を見つけてbinaryMediaTypeを消すことで、SDKからのリクエスト経由でもきちんと変換されたファイルがS3に渡るようになりました。

# 4.APIをテストする
マネジメントコンソールのテスト機能からテストしてみましょう。ヘッダーにContent-Typeを設定するのを忘れずに。

# 5.CORSの有効化する
マネジメントコンソールのAPIのページのメニューから、CORSの有効化を選択します。デプロイ前に必ず必要な作業なので忘れないようにしましょう。

# 6.APIをデプロイする
同じくメニューから、APIのデプロイをしましょう。

# まとめ
ざっと見てもお分かりかと思いますが、ハマりポイント以外は **基本的にとっても簡単です。とりあえず公式をちゃんと読んでおけば大丈夫です。** ただし、私の場合バイナリに変換という処理を必要としていて少し時間を溶かした上に、あまり直接S3に置きに行っている事例が公式以外で見当たらなかったのでまとめておきました。公式ドキュメントがちょっと散り散りに配置されている(伝わるだろうか…？)のはつらい気がする。
Pythonでネットワーク分析 -- 中心性の分析を簡単に試してみる --

#１．始めに#
ネットワーク分析のわかりやすい目的の一つに、
コミュニティの中心を明らかにするようなタスクがあります。

networkxで簡単にとっかかりを作れるとのことで、
簡単なサンプルコードで実験をしてみました。

##１．１．固有ベクトル中心性##
より多くの繋がりを持ったノードが有利という前提のもと、
「自身が多くの繋がりを持つ」かつ「多くの繋がりを持つノードと繋がっている」ほど有利であるという考え方に基づいて定義された中心性。

##１．２．媒介中心性##
ある直接の繋がりを持たないノードAとノードBが複数のノードを経由することで繋がりを持つとき、経由されるノードは「情報伝達の際に何らかの役割をもつ」と考えられる。
この時「情報伝達の役割を担っている」ほど有利であるという考え方に基づいて定義された中心性。
 
#２．参照する関数など#
- **networkx.eigenvector_centrality_numpy(グラフ)**：固有ベクトル中心性のリストを返します。
- **networkx.communicability_betweenness_centrality(グラフ)**：媒介中心性のリストを返します。

#３．サンプルコード#
```
# 固有ベクトル中心性が大きいほど頂点を大きくする

import numpy as np
import networkx as nx
import matplotlib.pyplot as plt

G = nx.karate_club_graph()

# 固有ベクトル中心性を求める![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513505/fa4d485e-ba1a-2508-df26-2fbd98c91eb9.png)

eignv_cent = nx.eigenvector_centrality_numpy(G)

# 頂点のサイズを決める
# サンプルでは1000倍にする
node_size = [1000 * size for size in list(eignv_cent.values())]

# 描画
nx.draw_networkx(G, node_size=node_size)
plt.show()
```
#４．サンプルコードの出力結果#
![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513505/2374d199-434c-2cfe-e688-f34c949217b2.png)
【Ruby on Rails】I18nを使っているのに中途半端に翻訳される・全く翻訳されない場合の対処法（キャッシュ対策）

## 今回の問題

- ValidationにI18nで国際化した文字列を使うと、翻訳されたり、たまにされたり、全くされなかったりする

## 解決方法
エラーメッセージをvalidatesメソッドに指定する際、にI18nで国際化した文字列を使用するとキャッシュされてしまうようです。

なので下記のように書いていたのを・・・

```ruby:address.rb
class Address < ApplicationRecord
  validates :zip_code, format: {with: /\A[0-9]{3}-[0-9]{4}\z/, message: I18n.t('addresses.zip_code_validation')}, allow_blank: true
  validates :residence_name, length: { maximum: 250, message: I18n.t('addresses.residence_name_validation') }
end
```

下記のようにProcを用いれば、キャッシュされずにちゃんと翻訳されるようになりました。

```ruby:address.rb
class Address < ApplicationRecord
  validates :zip_code, format: {with: /\A[0-9]{3}-[0-9]{4}\z/, message: Proc.new{ I18n.t('addresses.zip_code_validation') } }, allow_blank: true
  validates :residence_name, length: { maximum: 250, message:  Proc.new{ I18n.t('addresses.residence_name_validation') } }
end

```
シェルの文字列変数に改行を書き入れる方法

こんにちは。
シェルの文字列変数へ改行```\n```を書き入れる方法を調べました。

##### Bash の場合
Bash の場合には、下記の方法を用いて、```\n``` を直接書き入れられます。

```console
$ LF=$'\n'
$ echo "$LF"
```

##### POSIX の場合
POSIX の場合には、```\n``` を直接シンプルに書き入れる方法は無いようです。したがって、下記方法のように工夫する必要があります。printf で出力を確認しました。

```
$ ./hello.sh 
hello
world
```

```hello.sh 
#!/bin/sh
LF="
"
LF=$(printf '\n_');LF=${LF%_} # こちらでもＯＫ（また '\012_' と書いてもよい）
#   LF=$(printf '\n') # これはダメ（なぜならば末尾の \n は全て除去されるので）

helloworld＝"hello${LF}world" # 変数 helloworld の作り方は下記でもＯＫ
helloworld＝$(cat << EOS
hello
world
EOS
)
#   helloworld="hello\nworld" # これはダメ（このように直接シンプルに \n を書き入れることはできない）

printf "%s\n" "$helloworld"
```
【GCE】Debian 9でシステムのタイムゾーンを変更する

#何が問題か
GCEでインスタンスを作成した後、タイムゾーンをUTCからJSTに変更するというのが通常。
しかし、GCPで配布されているDebian 9イメージにはdbusパッケージが含まれていないため、timedatectlコマンドが実行できない。

# 解決法
dbusパッケージをインストールしてからtimedatectlコマンドでタイムゾーンを変更する。

```
$ sudo apt install dbus
$ sudo timedatectl set-timezone Asia/Tokyo
$ sudo shutdown -r now
```
pydocを作成してpythonファイル同士のリンクを結ぶときやったこと

#【初めに】
今回が初投稿となります。

後で自分の成果を見てにやついたり、備忘録のために記事を作成していく予定です。たまに困っているひとの役に立てばいいかなというユルさで、今後よろしくお願いします。

専門用語はあまり使わない方向でいきます。
ご指摘等は大いにwelcomeです。

#【記事の概要】
pydocをhtmlファイル形式で出力するとき各pythonファイル同士のリンクがうまくつながらなかったときにやったことの備忘録です。

batファイルの作成、コマンドプロンプトからpydocを作成する手法などは他の方が記事を上げているため割愛します。

👅自分はこちらの方の記事を参考にさせて頂きました。
https://sinsoku.hatenadiary.org/entry/20091030/1256902342

#【環境】
Windows10
python3.6.4

#【結論】
自分がやった手法は「出力したhtmlファイルを開いてコードを書き換えてリンクを付け直した」です。

パッケージすべてのpythonファイルをhtml出力して、
「__init__.py」のhtmlファイルにスクリプトをリンク付けするという内容です。


#【やったことアレコレ】
１：pydoc.batの作成　→　python.exeと同じフォルダへ移動させる。

２：コマンドプロンプトのcdコマンドで、pydocを書き出したいスクリプトのあるディレクトリへ移動する。
(カレントディレクトリを移動する)。

３：```pydoc -w XXX.py```
と打ち込みEnter。(XXXはスクリプトの名前を入力すべし。)

これでXXX.pyのフォルダ内にXXX.htmlが生成できているかもしれません。XXX.htmlを開くとブラウザが開き、コードの構成を表示します。

それをテキストエディタ等で開くとhtmlファイルを直接いじることができるため、リンクがつながっていない箇所のリンク付けを行って差し上げます。

この辺はhtmlでwebページを試しに作ったことがある人はピンとくると思います。


#最後に
今回はあまり深く掘るつもりはないため、この辺で終えたいと思います。
まだマークダウンの書き方がよく分かったないため、暇なときにきれいに見える書き方でも模索してみます。

今回のドキュメントの生成手法は手間のかかるやり方でした。他のうまいやり方が絶対あったと思います。

まぁ同じ問題で悩んでいる方がいましたらこんなやり方でもリンク繋げますという一つの回答としてとらえて頂けましたら幸いです。



今度はsphinx使ってみようかな、機会があれば。
[Mac]MySQL8 パスワード変更 及びリセット方法 

MySQL８でパスワードを変更しようとするとなぜかうまくできませんでした。
いろんな方法を試した結果ようやくできたので、MySQL8におけるユーザのパスワード変更及びパスワードリセットの方法を紹介します。

一度MySQLを停止する

```bash
mysql.server stop
```

セーフモードで起動する

```bash
mysqld_safe --skip-grant-tables &
```

パスワードなしでログインする

```bash
mysql -u root
```


一度パスワードなしに設定する

```bash
mysql> UPDATE mysql.user SET authentication_string=null WHERE User='root';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0
```

EXIT

```bash
mysql > exit;
```

MySQLを再起動する

```bash
mysql.server restart
```

パスワードなしでログインする

```bash
mysql -u root -p 
```

パスワードを変更する

```bash
mysql > USE mysql;
mysql > ALTER USER 'root'@'localhost' identified BY '（ここは新しいパスワード）'; 
```

もし、エラーメッセージが出たら、パスワード設定ルールを確認してください。

```bash
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements 
```

パスワード設定ルールの変更も可能

```bash
mysql> SHOW VARIABLES LIKE 'validate_password%';
+--------------------------------------+--------+
| Variable_name                        | Value  |
+--------------------------------------+--------+
| validate_password_check_user_name    | OFF    |
| validate_password_dictionary_file    |        |
| validate_password_length             | 8      |
| validate_password_mixed_case_count   | 1      |
| validate_password_number_count       | 1      |
| validate_password_policy             | MEDIUM |
| validate_password_special_char_count | 1      |
+--------------------------------------+--------+
7 rows in set (0.00 sec)
```

パスワードの設定ルールを変更しよう

```bash
mysql> set global validate_password_length=4;
Query OK, 0 rows affected (0.00 sec)

mysql> set global validate_password_policy=LOW;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW VARIABLES LIKE 'validate_password%';
+--------------------------------------+-------+
| Variable_name                        | Value |
+--------------------------------------+-------+
| validate_password_check_user_name    | OFF   |
| validate_password_dictionary_file    |       |
| validate_password_length             | 4     |
| validate_password_mixed_case_count   | 1     |
| validate_password_number_count       | 1     |
| validate_password_policy             | LOW   |
| validate_password_special_char_count | 1     |
+--------------------------------------+-------+
7 rows in set (0.01 sec)
```


注意点：
下記のコマンドは昔よく使っていましたが、MySQL5.7までしか使えません。エラーが発生する時、上記の方法を使ってみてください。

```bash
mysql > update mysql.user set password=password('password') where user = 'root
```
PHPを手軽に実行したい

※完全に自分メモです・・・

#XAMPPだとかいちいちめんどくさい

そんな時、PHPをダウンロードして環境変数の設定後（ここら辺はググって）にコマンドプロンプト起動

以下、ぶち込む。

```sh
 php -S 127.0.0.1:8080
```

すると起動したっぽい画面がでるので、アドレスバーに以下ぶち込む。

```
127.0.0.1:8080
```

ただ、これだけでは画面にPHPファイルは実行されない。

cdコマンドでPHPファイルがあるところまで移動し、起動コマンドの後ろにPHPファイルを書いてから先ほどの手順を踏む。

```sh
php -S 127.0.0.1:8080　●●●●.php
```

ま、こんな感じで。


取り急ぎ。
PowerShell から Backlog API を呼び出して課題を登録する

Backlog を利用していて、複数件の課題を手作業で登録するのが手間だったため、スクリプトとして処理できるようにしました。

#### 環境

``` powershell
PS> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.2.2
PSEdition                      Core
GitCommitId                    6.2.2
OS                             Microsoft Windows 10.0.18362
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
```

## API 仕様を確認

まず、Backlog API のリファレンスを確認します。

- [認証と認可 | Backlog Developer API | Nulab](https://developer.nulab.com/ja/docs/backlog/auth/)
- [課題の追加 | Backlog Developer API | Nulab](https://developer.nulab.com/ja/docs/backlog/api/2/add-issue/)

Backlog ユーザーの認証方法として、ここでは API キーを利用しています。リファレンスに従い、Backlog の個人設定から API キー文字列を発行しておいてください。

## 送信パラメーターの概要

上記リファレンスにより、課題登録のために必須のパラメーターは以下であることがわかります。

|パラメーター名|型|内容|
|---|---|---|
| projectId | 数値 | 課題を登録するプロジェクトのID |
| summary | 文字列 | 課題の件名 |
| issueTypeId | 数値 | 課題の種別のID |
| priorityId | 数値 | 課題の優先度のID |

`projectId` は利用している Backlog スペース内のプロジェクトの ID で、画面上から確認できるプロジェクト名とは異なります。`summary` は課題の件名を表します。

このほか `issueTypeId` は課題のカテゴリーを、`priorityId` は課題の優先度を表しています。`summary` の項目以外は、数値で表される ID を指定するところに注意が必要です。

各 ID は以下の API から確認することができます。

- [プロジェクト一覧の取得 | Backlog Developer API | Nulab](https://developer.nulab.com/ja/docs/backlog/api/2/get-project-list/)
- [種別一覧の取得 | Backlog Developer API | Nulab](https://developer.nulab.com/ja/docs/backlog/api/2/get-issue-type-list/)
- [優先度一覧の取得 | Backlog Developer API | Nulab](https://developer.nulab.com/ja/docs/backlog/api/2/get-priority-list/)

## サンプルコード

これらのパラメーターを設定し、PowerShell から Backlog API へ課題を登録するサンプルが以下になります。

``` powershell
function New-Issue {
  param (
    $Space,
    $ApiKey,
    $ProjectId,
    $IssueTypeId,
    $PriorityId,
    $Summary
  )
​
  $body = @{
    projectId   = $ProjectId;
    summary     = $Summary;
    issueTypeId = $IssueTypeId;
    priorityId  = $PriorityId;
  }
  
  $api = 'issues'
  $url = "https://$Space.backlog.jp/api/v2/$($api)?apiKey=$ApiKey"
​
  # 課題の作成に成功すると 201 (Created) が返ってくる
  (Invoke-WebRequest $url -Method Post -Body $body).StatusCode
}

# 使用例
New-Issue -Space 'myspace' -ApiKey 'xXxXxXx' -ProjectId 123456 -IssueTypeId 999999 -PriorityId 3 -Summary 'test task'
```

`New-Issue` 関数に渡した各種パラメーターをもとに、任意の Backlog プロジェクトへ Post しています。必要に応じて、API リファレンスを参考にパラメーターを追加してください。

SSL 通信のエラーが原因で `Invoke-WebRequest` が失敗する場合は、下記のスクリプトを実行して TLS 1.2 を有効化してみてください。

``` powershell
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
```

#### 参考

- [Backlogの課題追加のAPIで分かりにくい点 - Qiita](https://qiita.com/gam0022/items/404eacf974c406c2c76e)
- [curl/PowerShellでHTTPアクセスいろいろ - Qiita](https://qiita.com/zaki-lknr/items/8950f6acea20961a8afc)
- [Invoke-WebRequest](https://docs.microsoft.com/ja-jp/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-6)
- [SecurityProtocolType Enum (System.Net) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.net.securityprotocoltype)
HTML・CSSコーディング練習まとめ①〜画像の下部分を曲線にする〜

# はじめに
　2019年８月末からHTML・CSSの勉強を開始し、１ヶ月半ほど経った10月半ば、自分でコードを書いてみました。

〜完成したページ〜
<img width="1422" alt="スクリーンショット 2019-10-16 21.45.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515100/23c73626-f694-7396-8dc1-6e3f420f5623.png">

<img width="1185" alt="スクリーンショット 2019-10-16 21.45.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515100/15753f7b-2230-f944-fef6-849d5cfac474.png">
<img width="1330" alt="スクリーンショット 2019-10-16 21.46.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515100/00a3570b-6780-85d6-e780-5a342077c810.png">


今回の練習で難しかったところを備忘として記録していきます。
（数回に分けてアップする予定です。）

＊全体で７時間ほどかかっており、全部難しかったのですが、特に時間がかかった箇所を記載します。
＊なんとか解消したものの、未だ根本的な解決方法が不明なものについても記録します。こちらについては解決方法が分かったらアップデートしたいと思います。

## （CSS)画像の下部を曲線にする方法
（方法）
1.border-bottom-left/right-radiusを使う
　画像の左下・右下にborder-bottom-left/right-radiusを設定する。テキスト等で学習する場合、通常５pxくらいの小さな半径を設定するが、ここでは2000pxという巨大な半円を設定し、下線全体が弧を描くようにした。

2.marginを使用し、端の部分を綺麗にする
　border-bottom-left/right-radiusだけだと、端の部分が変にまるまってしまう。
<img width="1440" alt="スクリーンショット 2019-10-16 22.12.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515100/96cc1c68-f275-14f3-94c5-1631b19bd4ca.png">
この部分を綺麗にするため、margin-left/rightを使用し左右両端を画面上から見えないように設定。(設定する値をマイナスにする事で画面上から削る）

３.paddingを使用し、削りたくない上部を調整
 marginを設定する事で下部は綺麗になるが、上部のページ名称の部分も両端が見えなくなってしまう。
<img width="517" alt="スクリーンショット 2019-10-16 22.26.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515100/dd5e8e78-39e5-98a9-4a74-bb622bbd6e52.png">

これを防ぐため、marginで削った分をpaddingで無理やり戻す。

（実際のコード）
実際に完成したコードがこちら。
<img width="653" alt="スクリーンショット 2019-10-16 22.08.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515100/9f2dee4f-fe13-5e83-c6d0-5456d81606d7.png">
SwiftUIとXcodeのPreviewでオートレイアウトをリアルタイムで確認しながら実装できて感動した

先週くらいにXcode11に上げてようやく触り始めたのですが、感動してしまったので動画に撮りました。


![preview.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166241/95f50b09-6e2c-2346-9cd3-db6930ea93be.gif)

なんかUIViewRepresentableを使えば、SwiftUIでUIKitのViewを使えますよね

``` .swift
struct AutoLayout: UIViewRepresentable {
    func updateUIView(_ view: AutoLayoutView, context: UIViewRepresentableContext<AutoLayout>) {}
    
    func makeUIView(context: UIViewRepresentableContext<AutoLayout>) -> AutoLayoutView {
        AutoLayoutView()
    }
}
```

もちろんPreviewにも表示されるわけです。

``` .swift
struct AutoLayout_Previews: PreviewProvider {
    static var previews: some View {
        AutoLayout()
            .previewLayout(.fixed(width: 414, height: 300))
    }
}
```

Twitterを見ているとベータ版を触られてる人たちがコードレイアウトで書いても良さそうとか言ってたので、
オートレイアウトを試してみようといじってました。
でAutoLayoutViewの内部でコードでオートレイアウトを指定してあげたんですが、なんかpreviewに即反映されたんですよ。

``` .swift
final class AutoLayoutView: UIView {
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        initializeConstraints()
    }

    func initializeConstraints() {
        // label.leftAnchor....
    }
}
```


もしやと思いオートレイアウトをコードで書く用の自作Extensionを追加していじってみると、これも反映されました。
それが冒頭のgifです。


---

勤務先の企業でSwiftUIをメインのアプリで使えるようになるには後２年程かかるのでまだまだオートレイアウトを使わなければいけないのですが、このPreview機能の恩恵は大きそうです。


---

ソースはこんな感じです。
メソッドチェーンの ExtensionはNSLayoutAnchorをラップしているだけです。


``` .swift
final class AutoLayoutView: UIView {
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        initializeView()
        initializeConstraints()
    }
    
    private let iconImageView = UIImageView()
    private let nameLabel = UILabel()

    func initializeView() {
        nameLabel.text = "abouch"
        nameLabel.backgroundColor = .green
        addSubview(nameLabel)

        iconImageView.backgroundColor = .red
        iconImageView.layer.cornerRadius = 20
        addSubview(iconImageView)
    }
    
    func initializeConstraints() {
        iconImageView.chura.layout
            .size(100)
            .left(24)
            .centerY(self)
        
        nameLabel.chura.layout
            .left(iconImageView.rightAnchor + 24)
            .top(iconImageView.topAnchor + 16)
            .right(-24)
            .height(60)
    }
}
```
KotlinでS3 → AWS Lambdaを動かす

S3にアップロード → Lambda起動 → S3内容取得
という流れをKotlinで書いた。

## build.gradle

ライブラリは以下が必要

```gradle
dependencies {
    // AWS
    implementation 'com.amazonaws:aws-lambda-java-core:1.2.0' 
    implementation 'com.amazonaws:aws-lambda-java-events:1.3.0'
    implementation 'com.amazonaws:aws-java-sdk-s3:1.11.647'
```

- aws-lambda-java-core
  - Lambdaから呼び出されるメソッドを作成するために必要
- aws-lambda-java-events
  - LambdaでS3のイベントを受け取れる
- aws-java-sdk-s3
  - S3のオブジェクトにアクセスする

## Lambdaコード

クラスに`RequestHandler`を継承し、Lambdaから呼び出される`handleRequest()`メソッドを追加する。
（詳細は[公式](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/java-programming-model-handler-types.html)を参照すべし）

`handleRequest`の引数に`S3Event`を指定するとS3のイベントを受け取れる。
あとはS3のkey（ファイル名？)を取得し、S3の中身を取り出していく。

```kotlin
class QiitaLambdaHandler : RequestHandler<S3Event, Output> {
    
    override fun handleRequest(event: S3Event, context: Context?): Output {

        // AWSの認証作成
        val credentials: AWSCredentials = BasicAWSCredentials(
            // アクセスキー
            "ACCESS_KEY",
            // シークレットキー
            "SECRET_KEY"
        )
        
        // S3にアクセスするクライアント
        val client = AmazonS3ClientBuilder
            .standard()
            .withCredentials(AWSStaticCredentialsProvider(credentials))
            .withRegion(Regions.US_EAST_1)
            .build()
        
        // S3のキーを取得
        val s3Keys = event.records.map { it.s3.`object`.key }
        
        // 取得したS3のキーでループ
        s3Keys.forEach { key ->
            val request = GetObjectRequest("BUCKET_NAME", key)
            val file = File("/tmp") // 保存したいパス
            try {
                // 取得方法1 - S3をファイルに保存
                client.getObject(request, file) // fileのパスにS3が保存される
                // 取得方法2 - S3を変数に格納
                val data = client.getObjectAsString("BUCKET_NAME", key)

                // あとは取得したS3内容を好きなように処理する

            } catch (e: Exception) {
                return Output(
                    statusCode = 500,
                    message = "Unknown error."
                )
            }
        }
        return Output(
            statusCode = 200,
            message = "Process has been passed through."
        )
    }
}
```

あとはコードを固めてLambdaにアップロードし、Lambda側の設定で呼び出すクラス名を指定する。

<img width="829" alt="スクリーンショット 2019-10-17 8.27.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52227/22f0246a-4e8e-bd6e-9f52-09d6ad848947.png">

これを行わないと「handleRequestが見つからない」というエラーが発生するので注意。

## 参考

### 公式ライブラリ
aws/aws-lambda-java-libs
https://github.com/aws/aws-lambda-java-libs

### Lambdaドキュメント
- [Java による Lambda 関数のビルド - AWS Lambda](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/java-programming-model.html)

### S3ドキュメント
- [Amazon S3 バケットの作成、一覧表示、削除](https://docs.aws.amazon.com/ja_jp/sdk-for-java/v2/developer-guide/examples-s3-buckets.html#list-buckets)
- [Amazon S3 オブジェクトに対するオペレーションの実行](https://docs.aws.amazon.com/ja_jp/sdk-for-java/v1/developer-guide/examples-s3-objects.html#download-object)

## Todo
GitHubにコードを載せる
エンジニアなら転職する気がなくても転職活動をしてみよう！？

# 目的

- 転職活動真っ最中の自分が感じたことや思ったことをまとめる。

# 現在の自分の状況

- 自らのスキルアップのための転職活動を実施中である。
- カジュアル面談を3社受けた。
- 未経験からオンラインプログラミング勉強サービスのProgateやドットインストールを使用して勉強中である。
- kiitokキャリアというキャリアアドバイスサービスを使用している。

# 筆者の考える転職活動と転職の違い

### 転職活動

- 職を変えるための活動の事を指すが、結果として転職をする、しないは自由である。
- その業界の雰囲気や将来性、などをより具体的に知れる。

### 転職

- 転職活動の結果に応じて職を変えることを指す。

# なぜ転職活動を進めるのか

- 転職活動することにたくさんメリットがあると感じた頑張って
- 下記に筆者が感じたメリットを記載する。
  1. 知らない業界を深く知れる。
  1. 知らない技術に触れるいい機会になる。
  1. 客観的に自分の技術力を見れるようになる。
  1. 初対面の方と話すことに慣れる。
  1. 新しいやりたいことを見つけることができる。
  1. 転職活動そのものに慣れることができる。
- しかし少なからずデメリットもある。
- 筆者が感じたデメリットを記載する。
  1. 現職を続けながらの転職活動をすることは心身ともにつらい。

# 転職活動をすることのメリットを深掘る

  1. 知らない業界を深く知れる。  
  星の数ほどある企業や業界を調査することにより自分の考え方や価値観が良い方向に変化することが多々ある。
  1. 知らない技術に触れるいい機会になる。  
  どうしても今仕事で使用している言語やツールに長けてしまうが、外部の技術的内容を自分に取り入れることにより、トレンドなどをよりキャッチしやすくなる。
  1. 客観的に自分の技術力を見れるようになる。  
  市場価値が分からなく困っていた自分にはこれが一番大きかった。現在の自分はどんな企業にモテるのか、自分が働きたい企業にモテるにはどんな技術を付ける必要があるのかなどが実感できる。
  1. 初対面の方と話すことに慣れる。  
  カジュアル面接を受けたときに限るが、転職活動をすると企業の方とお話する機会が少なからず発生する。「自分の伝えたいことや考え、どんな技術に興味があるか、などを短時間で伝えるための工夫」が自然と身につく。
  1. 新しいやりたいことを見つけることができる。  
  企業や業界を知ることにより広い視野でものを見ることができる。新たなビジネスチャンスや、目標などがン見つかる場合が多い。
  1. 転職活動そのものに慣れることができる。  
  このメリットは一番大きいメリットだと考える。転職を見据えた本気の転職活動をする際に慣れているので、落ち着いて行うことができる。

# おすすめの転職活動

- カジュアル面接に行く
  1. 筆者が最もおすすめしたい転職活動方法である。
  1. 広報の一環としてカジュアル面接を受け付けている企業さんも多数ある。
  1. webで公開されている内容よりも深い内容のお話を聞くことができる。
  1. 転職をするかしないか決めかねているような方も歓迎されている。
  1. 企業側は自社サービスの説明などの広報活動が行え、カジュアル面談を受ける側は本気の転職活動をする際に応募する企業の案を絞ることができる。
物知りLINE BOTを作ろうとしたらfugaしか答えない残念な奴になった話


## はじめに

[あるQiita記事](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d)を参考にLINE Botを作りました。
でも、どうせだったらオリジナルのLINE Botに改造しようと挑戦したところ、残念なBotができた話です。


※2019/11/12追記:
物知りBotになりました ↓
[fugaしか答えない残念なBotに8万語の辞書を持たせてインテリBotにした話](https://qiita.com/zgw426/items/5e9d9ed7c40d976d3055)



## 作りたかったもの

なんでも知ってて質問すると教えてくれる物知りLINE Botを作るつもりでした。
例えば、「山？」と質問すると、山に関するWikipediaの簡易版みたいな情報を返してくれる、そんなBotが作りたかったんです。




## 考えた仕組み

物知りLINE Botは、『言葉の意味を教えてくれるAPI』と『LINE Bot』の2つをつなぎ合わせれば、作れそうと考えました。「これくらいならできるかな」と、軽く考えたのは甘かった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/791144cc-948b-7af8-6f0e-c1b79c812256.png)


## 結果

完成した残念なBOTを紹介します。このように、何を聞いても `fuga` しか答えません。

<img width="375" alt="IMG_0400.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/e8b59df0-003d-c571-45d9-45b01b0bf75e.png">

`fuga`しか答えない原因は、②のAPIにフィルタの機能がないから。フィルタ機能を実装することができなかった。あぁ～


## 作り方

誰も興味がないと思いますが作り方を紹介します（ほぼリンク集です）

#### ①LINE BOTを作成

- [1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d)

こちらの記事を参考にさせて頂きました。この時点で、オウム返ししてくれるBOTをゲット！

#### ②API作成

`fuga`しか答えない残念なAPIを作ります。APIは、ラズパイ上に構築するのでラズパイのセットアップも必要です。

#### ②-1 ラズパイにOSをインストール

- [モニタ/キーボードを接続しないでラズパイにOSをインストールする](https://note.mu/agw/n/n22ee9c4f6edc?magazine_key=mc40e905e6d42)

今回は、`Raspberry Pi 3 Model B`を使いました。OSバージョンはこれです。

```
$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 10 (buster)
Release:        10
Codename:       buster

$ uname -a
Linux raspi100 4.19.79-v7+ #1273 SMP Fri Oct 11 18:13:16 BST 2019 armv7l GNU/Linux
```

#### ②-2 ラズパイOSの初期設定

- [ラズパイOSの初期設定がしたい!](https://note.mu/agw/n/nb17b9a9d6989?magazine_key=mc40e905e6d42)

ロケールの設定とかはこちらを参考にしました。

#### ②-3 DjangoでAPIを作る

- [Django REST frameworkチュートリアル その１](https://qiita.com/Gattaca/items/419e2a2cf23b6a9f1028)

Djangoを使ってAPIサーバーを作りました。ただし若干変更しました。

- コマンド変更
 - `pip` -> `pip3`
 - `python` -> `python3`

- `tutorial2/settings.py` 変更
 - [変更前] ALLOWED_HOSTS = []
 - [変更後] ALLOWED_HOSTS = ["192.168.3.6"]
 - ※ラズパイのIPを登録

- サービス起動コマンド変更
 - [変更前] `python manage.py runserver`
 - [変更後] `python3 manage.py runserver 192.168.3.6:8000`


#### ③APIとLINE Bot連携／④APIからの情報をLINEメッセージで送信

- [補足資料その2](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d#%E8%A3%9C%E8%B6%B3%E8%B3%87%E6%96%99%E3%81%9D%E3%81%AE2)

『①LINE Botを作成』で参考にした記事の補足に、他APIと連携したサンプルもあります。このスクリプトを拝借させていただきました。

## さいごに

オウム返しするBotをバージョンアップしようとしたら、`fuga`しか答えない残念なBotに育ってしまいました。

ただ、APIにフィルタの機能を追加できれば、物知りBotに生まれ変わるかも？！と希望を持っています。というわけで、挑戦はまだ終わってない、劣勢だけど負けてない！　　たぶん

※追記※
少し賢くなりました →[fugaしか答えなかったLINE BOTが少し物知りになりました](https://qiita.com/zgw426/items/10a94a80bacecb83b73e)
JavaScriptの基本箇所についての復習②(引数)

#はじめに

[前回の記事](https://qiita.com/Moon1126Snow/items/cc71950a1a2c824bedd8)に引き続き、復習を兼ねてjsの基本をまとめていきます。

#内容
関数についての基礎についてひと通り解説したいと思います。

#実行

[前回の記事](https://qiita.com/Moon1126Snow/items/cc71950a1a2c824bedd8)にて、関数の基本形を下記のように示しました。

```js
function 関数名(引数){
  処理名;
}
```

しかし、例で載せていた"Hello"という関数には、引数を使用していなかったため、今回は引数を使用した関数を書いていこうと思います。

```js
function Say(Hello){
  console.log(Hello);
}

var word = 'Hello.world';
Say(word);
```

引数を使用した関数の中では、これが一番簡単かつ基本的な部類に入ると思います。
一つ一つ解説していきます。

```js
function Say(Hello){
  console.log(Hello);
}
```
前回までと違い、引数の部分の部分に'Hello'という文字を記入し、さらに```console.log()```の中にも同じ'Hello'という文字を記入してます。
この関数の意味する所は、「Helloに代入されていた文字を出力する」となります。

しかしこの書き方では、'Hello'に何も代入されていないため、関数を実行しても何も起きません。
この関数を使用するためには、まず変数を定義しなければいけません。

```js
var word = 'Hello.world';
Say(word);
```

[前回の記事](https://qiita.com/Moon1126Snow/items/cc71950a1a2c824bedd8)にて変数の定義の仕方について書きましたが、基本は同じです。
異なる部分は、前回```console.log(word)```となっていた部分が```Say(word)```という所です。
この　```Say```というのは、先ほど定義した関数のことで、「Sayという関数を実行する」という意味合いになります。
また、今回は引数として'word'を記入しているので、「関数Sayに変数wordを引数として渡し、実行する」ということになります。

変数wordを引数として渡して実行すると、関数SayのHelloにwordが代入され、それを文字列として表示します。
前回までの知識では、違う文を表示したい場合、関数の中身を書き換えなければいけませんでしたが、今回の書き方であれば変数の中身を変えるだけで違う文を表示できるようになります。

#終わりに

記事を書いていくと、「本当にそうか？」とか「もっと良い書き方があるんじゃないのか？」とか「この部分は理解できてない」と思う部分が色々見つかります。
今後も学習を進めていって、jsへの理解を深めていくと共に、良い記事が書けるようになればなと思います。
Query Stringについて

備忘録

#Query String
URLの後ろにくっついている情報を指す。「Key=Value」の形式で「&」で区切っていくつかの値が渡される。

サンプル画像｜
YahooのFXページの一部。dというKeyは「date」を意味し、Valueとして「20191108」という日付が設定されている。サーバーはこのQuery Stringの情報に応じてデータを返したりしている。

![スクリーンショット 2019-10-16 22.26.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374557/ad4ef817-c8b6-e32a-a55f-c6e8141d85de.png)
datimepicker適用で、カレンダーから日付を入力する。

##0. 事前に読み込んでいたもの
BootStrap3.3.7をGemに入れてbundle installしています。
▶︎[【RubyonRails入門】Gemfileを用いてBootostrapを導入する方法](https://qiita.com/puripuri_corgy/items/84c36cd183f57dd7b4f6)

##1. scriptの読み込み

```erb:app/views/layouts/application.html.erb
<!-- daytimepicker -->
<script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/moment-with-locales.js"></script>
<script src="http://cdn.rawgit.com/Eonasdan/bootstrap-datetimepicker/v4.0.0/src/js/bootstrap-datetimepicker.js"></script>
```

##2. JSの書き込み

```js:app/assets/javascripts/application.js
// datimepicker
$(function () {
  $('.date').datetimepicker({
    locale: 'ja',
    format : 'YYYY-MM-DD'
  });
});
```

##3. erbファイルに書き込み

```erb:app/views/reservations/edit.html.erb
<div class="form-group col-sm-8">
	<%= reservation.label :reserved_at, class:"left-border" %>
	<span class="required_mark">*</span>
    <div class="input-group">
        <%= reservation.text_field :reserved_at, class:"form-control date" %>
        <span class="input-group-addon">
        	<span class="glyphicon glyphicon-calendar"></span>
        </span>
    </div>
</div>
```
Thunderbirdで下書きを削除してしまったと泣く前に

明日までにメールでレポートを提出、なんてことで前日の夜中に意識朦朧としながらメールを書くときってありますよね。

そんな時に4年に1度訪れるのが、そう、下書き中の大作を削除してしまう、という例の祭りです。

最初は「やべっ、途中で送信してしまったか」と送信済みトレイを確認するのですが、もちろんそんなことはなく、「そういやさっき受信トレイのメール確認したし返事も不要だから削除したような。。」と、そう、それ、下書き中のメールですから！

ちょっと汗が出てくる中、とりあえず Ctrl+Z を試しますが、そんなことでは何も起きません。

ツールバーなりなんなり、開けそうなメニューを、それこそ今まで見たことない、今見ても何言ってるかわからない設定画面を開きに開いても、下書きを復元できそうな操作は出てきません。

いったんここで半べそになって、コーヒーを飲んで眠気を覚ましま、いえ、もうとっくに覚めてます。

冷静になって本題です。

Thunderbird のメールはすべてファイルシステムに保存されているので、アプリ上からは無理でも、直接ファイルを探し出して、ごにょごにょする手段はありました。

Thunderbird のデータは、CentOS-7 だと、ホームディレクトリ配下の .thunderbird ディレクトリに存在します。

Thunderbird のアプリは終了させてから、この中を探っていきます。

```
$ cd ~/.thunderbird
$ tree -d
.
`-- 5iq670lw.default
    |-- ImapMail
    |   `-- [メールアカウント名のフォルダ]
    |       `-- INBOX.sbd
    |           `-- Archives.sbd
    |-- Mail
    |   `-- Local\ Folders
    |-- blocklists
    |-- calendar-data
    |-- datareporting
    |-- extensions
    `-- gmp
        `-- Linux_x86_64-gcc3
```

私が間違って削除した下書きは、IMAPのほうなので、そっちを探検します。

```
$ cd 5iq670lw.default/ImapMail/[メールアカウント名のフォルダ]
$ $ tree
.
|-- Archives.msf
|-- Drafts.msf
|-- INBOX
|-- INBOX.msf
|-- INBOX.sbd
|   |-- &MF0wbk7W-.msf
|   |-- &U8KAA4zHZZk-
|   |-- &U8KAA4zHZZk-.msf
|   |-- Archives.msf
|   |-- Archives.sbd
|   |   |-- 2017
|   |   |-- 2017.msf
|   |   |-- 2018
|   |   |-- 2018.msf
|   |   |-- 2019
|   |   `-- 2019.msf
|   |-- Drafts
|   |-- Drafts.msf
|   |-- Junk.msf
|   |-- Sent
|   |-- Sent.msf
|   |-- TODO
|   |-- TODO.msf
|   `-- Templates.msf
|-- Sent.msf
|-- Templates.msf
`-- msgFilterRules.dat
```
この中で、拡張子が msf のものは、Mail Summary File の略だそうで、Thunderbird はこ msf を一覧表示などに利用する要約データとして利用しているそうです。

今回は、生データを探しているので、msf でないファイルで下書きぽいやつを探すと、Drafts という拡張子なしのファイルが１つ確認できます。

これを除いてみると、これまで下書き保存したことがあるメールが時系列に収められています。さっきまで書いていた下書きということで、下から見ていくと、

```
--------------1B2C36E3FFC35B3F134A036F--^M
From: XXXXXXXXX <XXXXXXXXXXXXXXXXX>^M
Message-ID: <97336315-a7ab-1952-f3af-988e395e7413@XXXXXXXXXXXX>^M
Date: Wed, 16 Oct 2019 21:37:11 +0900^M
X-Mozilla-Draft-Info: internal/draft; vcard=0; receipt=0; DSN=0; uuencode=0;^M
 attachmentreminder=0; deliveryformat=4^M
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101^M
 Thunderbird/60.9.0^M
MIME-Version: 1.0^M
Content-Type: text/html; charset=utf-8^M
Content-Language: en-US^M
Content-Transfer-Encoding: 8bit^M
^M
<html>^M
  <head>^M
^M
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">^M
  </head>^M
  <body text="#000000" bgcolor="#FFFFFF">^M
    下書きテスト<br>^M
  </body>^M
</html>^M
...
...

```
うおおお、なんかそれっぽいのがある！

で、ここからは結論を。。

このファイルの中に X-Mozilla-Status という行が何か所かあります。

```
X-Mozilla-Status: 0001
X-Mozilla-Status2: 00000000
```

といった具合に。

削除前の状態に戻すには、このステータス値をすべて 0 にすると復活するそうです。http://forums.mozillazine.org/viewtopic.php?f=39&t=1971971

例えば、上記のように 0001 だったら 0000 にします。そして要約である Drafts.msf を削除します。たぶん要約ファイルがなければ次回起動時に自動的に作成されるものと思われます。
ありがとう、先にしくじってくれた人に感謝です。

このファイルを直接操作する作業は、メールを圧縮してしまうともうできなくなるので、事故ったたら早めに対処が必要です。
備忘録：WindowsUpdate対策(Windows10Pro1903)

#Windows10Pro ver1903のWindowsUpdate設定について

~~既に二番煎じ・・煎じ飽きてる話の可能性もありますが~~

今まで、Windows10Proを利用してきた人は、
「設定」->「更新とセキュリティ」->「WindowsUpdate」->「詳細のオプション」から機能の更新(大型アップデート)を延期する画面がありました。

Windows ver1909からは上記の設定画面が消えていますorz

## では、どう設定するか。

「Windowsロゴ」 + 「r」
-> 「gpedit.msc」と入力してエンターキー

次に、
「コンピューターの構成」->「管理用テンプレート」->「Windowsコンポーネント」->「WindowsUpdate」->「Windows Update for Business」と進んでいきます。
![LGP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67358/9d2ac8bc-d2bd-2df2-4163-8015e68e4edc.png)


そして画面右側の
「プレビュービルドや機能更新プログラムをいつ受信するかを選択してください」
をダブルクリック

下の画面が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67358/29d09ba7-b694-8944-0d56-cc26bb4760fe.png)

半期チャンネルと記載されている箇所については、以下の選択肢があります。
半期チャンネルを選択する場合のみ、機能更新プログラムの受信を最大で365日延期できるようになります。
![LGP2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67358/04c3224c-ca52-d03e-ed82-1775d5fb0011.png)

以上です。
デスクトップPCを上げていないので、備忘録ですが、
他の人の役に立てたならば幸いです。ここまで読んでいただきありがとうございます。
Python embeddableへのTkinterの導入方法

#はじめに
Pythonに標準搭載されているGUIライブラリ「Tkinter」を
Python embeddableへの導入方法に四苦八苦したので記載します。

参考：https://stackoverflow.com/questions/37710205/python-embeddable-zip-install-tkinter

#環境
Windows10 64bit
Python embeddable 3.6.7
Python 3.6.9

(※Embeddable pythonとは別にPython環境が必要です。)

#概要

ざっくりとした手順は
Python embeddableのフォルダにPythonのフォルダからTkinterを持ってくる
というものになります。

#手順

1.Pythonフォルダより下記2フォルダを持ってくる。
・「tcl」フォルダ
(python-3.6.7-embed-amd64/tcl　と配置)

・Lib配下に存在する「tkinter」フォルダ
(python-3.6.7-embed-amd64/Lib/tkinter　と配置)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515098/1be28e25-4e91-46fb-099e-76e13ed3864a.png)

2.Pythonフォルダより下記3ファイルを持ってくる。
(全てpython-3.6.7-embed-amd64/DLLs　配下に格納)
・_tkinter.pyd
・tcl86t.dll
・tk86t.dll

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515098/6be411be-405d-2359-a631-a6453f80c15b.png)

3.python36._pthに.\DLLsを書き加える。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515098/fd1591ef-6374-4975-e2b2-048b83965bc4.png)


以上です。
Raspberry PiのIPを同じネットワーク内から探す

MacからRaspberry PiにSSHで接続したいが、アドレスが分からない。

アドレスを探し方を調べたら３つの方法を見つけた。

## 方法1. arp

Macには最初から入ってるはず

```
$ arp -a
? (192.168.0.1) at 6c:e4:da:e8:c9:59 on en0 ifscope [ethernet]
? (192.168.0.2) at 40:9f:38:7d:2f:29 on en0 ifscope [ethernet]
? (192.168.0.3) at d8:6c:63:46:39:da on en0 ifscope [ethernet]
? (192.168.0.4) at b0:72:bf:dc:63:45 on en0 ifscope [ethernet]
? (192.168.0.5) at c:96:e6:c:c9:71 on en0 ifscope [ethernet]
? (192.168.0.7) at 58:2f:40:92:18:3a on en0 ifscope [ethernet]
? (192.168.0.9) at e4:f0:42:35:e7:be on en0 ifscope [ethernet]
? (192.168.0.10) at 3c:8d:20:ee:5c:99 on en0 ifscope [ethernet]
? (192.168.0.11) at 50:dc:e7:be:c1:35 on en0 ifscope [ethernet]
? (192.168.0.12) at b8:27:eb:90:c:a1 on en0 ifscope [ethernet]
? (192.168.56.1) at a:0:27:0:0:0 on vboxnet0 ifscope permanent [ethernet]
? (239.255.255.250) at 1:0:5e:7f:ff:fa on en0 ifscope permanent [ethernet]
```

うーん、結果を見てもどれがRaspberry Piか分からない。
微妙！

## 方法2. arp-scan

https://github.com/royhills/arp-scan

これはLinux/Macのみかな。
Macならbrewでインストールできる。

```
$ brew install arp-scan
```
これでインストール完了

検索実行するコマンド

```
$ sudo arp-scan -l
Interface: en0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.9.5 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.0.1	6c:e4:da:e8:c9:59	(Unknown)
192.168.0.2	40:9f:38:7d:2f:29	(Unknown)
192.168.0.11	50:dc:e7:be:c1:35	(Unknown)
192.168.0.9	e4:f0:42:35:e7:be	(Unknown)
192.168.0.7	58:2f:40:92:18:3a	(Unknown)
192.168.0.12	b8:27:eb:90:0c:a1	Raspberry Pi Foundation
192.168.0.10	3c:8d:20:ee:5c:99	(Unknown)
192.168.0.5	0c:96:e6:0c:c9:71	(Unknown)
192.168.0.3	d8:6c:63:46:39:da	(Unknown)
192.168.0.4	b0:72:bf:dc:63:45	Murata Manufacturing Co., Ltd.
```
おお、素晴らしい！
`192.168.0.12	b8:27:eb:90:0c:a1	Raspberry Pi Foundation`
この行が目的のIPだね、Raspberry Piと出てるし。

arp-scan はベンダー名まで表示してくれるようだ、いいね！

## 方法3. Angry IP Scanner

こちらはコマンドラインではなく、GUIアプリ

**Angry IP Scanner**
https://angryip.org/

Windows, Mac, Linux と対応しているようだ。

Macならbrewでインストールできる。

```
$ brew cask install angry-ip-scanner
```

画面はこんな感じ
<img width="832" alt="スクリーンショット 2019-10-16 17.10.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52227/ef291086-1a50-8251-3996-e2933685642b.png">

GUI派には良さそう。
印刷用のShade3Dデータをthree.jsで表示する

印刷用に作成されたShade3Dデータをthree.jsで表示させるために変換してみた時のメモ

#出力形式
Shade3Dの対応出力ファイル形式のなかからthree.jsに対応しているFBX,Wavefront OBJ(OBJ)あたりを出力してみてサイズが大きかったので、出力されたFBXをBlenderで開き、glTFに変換

Shade3DでglTFをインポート/エクスポートするプラグインがあるのだが、Standard/Professional版でしか使用できない。（Basic版では使用不可）

[BlenderでFBX形式をglTF形式に変換してThree.jsでアニメーションさせる （1/2）](https://ryo620.org/2018/02/to-gltf-from-fbx-by-blender/)

#FBXに変換する時に行った作業
1. 形状名をすべて日本語→半角の英字または数字に変更
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283262/46e8024f-d3c8-9142-4983-bc10733b479a.png)
2. レンダリングブーリアンをしている所はShade3D特有の機能なので、ブール演算をする
[ブーリアンとは](https://knowledge.shade3d.jp/knowledgebase/%e3%83%96%e3%83%bc%e3%83%aa%e3%82%a2%e3%83%b3%e3%81%a8%e3%81%af)
3. 法線を反転する
面の裏返りがある場合、印刷用のレンダリングは問題ないのだが、FBX方式で書き出すと面が抜けてしまう。
これがかなりあったので、表示オプションの「両面（裏面カラー）」で確認し、色のついた部分を自由曲面などからポリゴンメッシュに変換し、法線の反転の作業をしてゆく（裏返りがあるところがブルーで表示される）
[ポリゴンメッシュの法線を反転する](https://knowledge.shade3d.jp/knowledgebase/ポリゴンメッシュの法線を反転する)
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283262/4022e934-c366-16d5-5ca2-513e5930ad35.png)


4. 形状はポリゴンメッシュにする
自由曲面でもFBXエクスポート時に自動的にポリゴンメッシュに変換されるが、細かすぎたり無駄が多くなることもあるので、Shade3D上でポリゴンメッシュに変換し、あらかじめ最適化

5. 表面材質はマスターサーフェス化する
これはデータの方で材質がマスターサーフェス化されていたのでそのまま


[fbx形式でエクスポートする時に注意する点](https://knowledge.shade3d.jp/knowledgebase/fbx%E5%BD%A2%E5%BC%8F%E3%81%A7%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%E6%99%82%E3%81%AB%E6%B3%A8%E6%84%8F%E3%81%99%E3%82%8B%E7%82%B9)


上記の作業で最初書き出しで面が抜けた部分が表示されるようになった。

#three.jsで表示
three.js examplesの中のwebgl_loader_gltf.htmlのソースを参照
[three.js examples](https://github.com/mrdoob/three.js/tree/dev/examples)

#これから
変換したデータのサイズはobjやfbxのサイズよりは小さくなったものの、glTF+binファイルでかなりの大きさだったためタブレットでは表示できなかった。
より、サイズを小さくする方策を考えたい。

変換した元データが細かいデータだったので、ポリゴンメッシュを粗くするのは表示がかなりに劣化するものの劇的にサイズが減るわけではなかった。DRACO圧縮もためしたものの、objファイルは劇的にサイズが減ったが、mtlファイルを圧縮ファイルに適用する方法がわからなかった。また、glTF 2.0 拡張仕様のDraco拡張もためしたものの、なぜか容量が増えることに。。これはやり方が悪いのか。このあたりももっと調べてみたい。
[劇的に3Dデータ容量を削減するDRACO圧縮のデータを自前描画する方法](https://qiita.com/kioku/items/bbb672d287792a987faa)
PythonでOpenCVを使って画像から顔だけを切り取る方法

OpenCVを使って画像から顔の部分だけを切り取り保存するコードを書いたので備忘録として残しておきます。

# 環境

今回はPythonを使います。

* MacOS Mojave バージョン10.14.6
* Python 3.6.8
* opencv-python 4.1.1.26

# 準備

OpenCVのcascade分類器を使います。[こちら](https://github.com/opencv/opencv)からOpenCVをcloneしてきて、`data/haarcascades`をコピーするのが早いと思います。今回は以下のような構造を想定します。

```
root/
  ┣ haarcascades/(opencvからコピーしてきたディレクトリ)
  ┣ target.jpg
  ┗ imgcut.py
```

画像は[PAKUTASO](https://www.pakutaso.com/20190923247post-23057.html)から拾ってきたこちらのフリー画像を使用します。

![鬱憤がたまる男](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263052/8695ee36-a0fb-a417-862d-f215c4461155.jpeg)


# コード

コードの全体は以下の通りです。一枚の画像から顔を切り出す処理になっています。複数の画像に対応させ少し使いやすくしたものを[GitHub](https://github.com/FukumotoRyota/face-cutter/blob/master/face-cutter.py)に置いていますのでこちらも参考にしてください。

```python
import cv2

cascade = cv2.CascadeClassifier("./haarcascades/haarcascade_frontalface_default.xml")
img = cv2.imread("target.jpg")
face_pos = cascade.detectMultiScale(img)
for x,y,w,h in face_pos:
  face = img[y:y+h, x:x+w]
  cv2.imwrite("result.jpg", face)
```

# コードの説明

OpenCVをインポートします。

```python
import cv2
```

cascade分類器を読み込みます。今回は顔が正面を向いているので`haarcascade_frontalface_default.xml`を使用します。

```python
haarcascade_frontalface_default.xml
```

画像をndarrayに変換します。

```python
img = cv2.imread("target.jpg")
```

cascade分類器を用いて顔の座標を特定します。

```python
face_pos = cascade.detectMultiScale(img)
```

顔部分を切り取ります。座標は`[[1003  135  196  196]]`のようになっており、左からx座標、y座標、幅、高さが入っています。複数の顔が見つかることもあります。

```python
for x,y,w,h in face_pos:
  face = img[y:y+h, x:x+w]
```

最後に画像を保存します。

```python
cv2.imwrite("result.jpg", face)
```

# 実行結果

以下のコマンドで実行すると、result.jpgが生成されます。

```python
python imgcut.py
```

![鬱憤がたまる男の顔](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263052/44df8804-8767-48f9-affe-f8f1f677d256.jpeg)

上手くできたようです。なんとも言えない表情をしていますね。

# 感想・考察

今回はOpenCVを使って画像から顔だけを切り取る方法を書きました。モデルの学習など色々な場面で使えると思います。OpenCVすごいなと思いました。
Nimでイテラブルなオブジェクトを定義

# for文でぶん回せるオブジェクトを定義したい
こんなかんじの。

```nim:
for s in fizzbuzz:                                                    
  echo s 
```

# itemsイテレータを定義するとできた。
こんなかんじで。

```nim:
type FizzBuzz = ref object of RootObj                                           
  max: int                                                                      
                                                                                
iterator items(self: FizzBuzz): string =                                        
  for n in 1..self.max:                                                         
    var str: string                                                             
    if n mod 3 == 0: str = "fizz"                                               
    if n mod 5 == 0: str &= "buzz"                                              
    if str.len == 0: str = $n                                                   
    yield str                                                                   
                                                                                
when isMainModule:                                                              
  let fizzbuzz = FizzBuzz(max:15)                                               
  for s in fizzbuzz:                                                            
    echo s
```

実行結果

```
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
```

以上〜。
踏み台サーバーを経由してSSH接続する設定を~/.ssh/configに書く

# 注意
Macで踏み台サーバーを経由してSSH接続する方法です。
以下の記事もあわせてご参照ください。
[公開鍵認証を使ってリモートサーバーにSSH接続する](https://qiita.com/FukumotoRyota/items/1e994b16d389044e76b0)
[SSH接続の設定を~/.ssh/configに書いておくと接続する際に長いコマンドを打つ必要がなくなる](https://qiita.com/FukumotoRyota/items/627c938e50d7793e8fbd)

# やり方

ProxyCommandを使うと踏み台サーバーを経由してSSH接続することができます。

例えば、`user@hoge.com`を踏み台にして`user@piyo.com`にSSH接続する場合、`~/.ssh/config`には以下のように書きます。

```bash
Host hoge # ここは好きな名前でよい
User user
HostName hoge.com
IdentityFile ~/.ssh/hoge/id_rsa # user@hoge.comの秘密鍵までのパス

Host piyo # ここは好きな名前でよい
User user
HostName piyo.com
IdentityFile ~/.ssh/piyo/id_rsa # user@piyo.comの秘密鍵までのパス
ProxyCommand ssh hoge -W %h:%p # hogeは上でつけた名前
```

上記のように書くと以下のコマンドで踏み台サーバーを経由したSSH接続ができます。

```bash
ssh piyo
```

# 補足
ProxyCommandの`%h`は目的のサーバーである`user@piyo.com`に置換され、`%p`はデフォルトの22に置換されます。
OAuth2とOpenID Connectの概要図

OAuth2（OpenID Connect）の概要を説明するために、シーケンスと画面遷移を合わせて記述した図を作成した。最も典型的な利用シーンであるWebアプリでのAuthorization Code Grant (Flow) の流れを説明している。

![oauth2_oidc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186068/dbd619df-9d58-972c-b594-56cf354c1fa1.png)
Gitのよくわかんない単語はこう読み替えろ！

# 概要
「コミット」がローカルセーブ
「プッシュ」がグローバルセーブ
「チェックアウト」がロード
「リポジトリ」がメモリーカード
「ブランチ」がセーブデータ

ざっくりとした例えですが平たく言いかえればこうなります。
これだけでも覚えて帰ってくれよな！

# 細かい対応表

|Git用語|英語|読み替え後|
|---|---|---|
|コミット|commit|ローカルセーブ|
|プッシュ|push|グローバルセーブ|
|クローン|clone|初回グローバルロード|
|プル|pull|グローバルロード(2回目以降)|
|チェックアウト|checkout|(ローカル)ロード|
|リポジトリ|repository|メモリーカード|
|ブランチ|branch|セーブデータ|
|マージ|merge|こんなたとえ話を読んでいる人が気軽には使ってはいけない禁忌の機能|
|タグ|tag|セーブデータに名前をつけるやつ|
Jupyter NotebookにNbExtensionsを悪戦苦闘の末インストール成功


NbExtensionsをJupyternotebookに入れると超便利という記事を見つけて
早速インストールを試みたが、Nbextensionsのタブがホームページに出てこない
悪戦苦闘の末、クロヤギクンのページを見つけ
インストール時の名前を大文字と小文字交じりの NbExtensions
としたら、インストール出来て、タブも出るようになった。
色々な機能が使えるということだったが、
notebookを6.0にVer.upしたら、変数のリストアップができなくなった。
nomのパースエラー表示を改善する: nom-greedyerror

# はじめに
Rustのパーサコンビネータライブラリnomで詳細なパースエラーを出す方法と、その表示を改善するクレート[nom-greedyerror](https://github.com/dalance/nom-greedyerror)について解説します。

# nomのエラー型
nomに実装済みのエラー型は2種類あります。`I`をパーサの入力型とすると`(I, ErrorKind)`と`VerboseError<I>`です。パーサが返す`IResult`のエラー型はデフォルトでは`(I, ErrorKind)`となっていて、これは最も直近で失敗したパーサの情報しか返すことができません。それに対し、`VerboseError`は失敗したパーサの履歴を保持しているので、最終的に失敗するまでにどのような失敗を経てきたのかを知ることができます。

# `VerboseError`の使用方法

例えば

```rust
    alt((
        tuple((alpha1, digit1, alpha1)),
        tuple((digit1, alpha1, digit1)),
    ))(input)
```

というパーサを考えます。これは「アルファベット+数値+アルファベット」か「数値+アルファベット+数値」を受理するパーサで、例えば`123abc123`や`abc123abc`を受理します。
このパーサに`VerboseError`を適用したいときは以下のようにします。

```rust
fn parser<'a, E: ParseError<&'a str>>(
    input: &'a str,
) -> IResult<&'a str, (&'a str, &'a str, &'a str), E> {
    alt((
        tuple((alpha1, digit1, alpha1)),
        tuple((digit1, alpha1, digit1)),
    ))(input)
}
```

型変数`E:  ParseError<&'a str>>`を使うことで、`(I, ErrorKind)`でも`VerboseError`でもどちらでも使えるパーサができます。（入力型`I`も変数にできますが省略します）

```rust
let error = parser::<(&str, ErrorKind)>>("abc012:::");
let error = parser::<VerboseError<&str>>("abc012:::");
```

使うときはこのようにします。また`VerboseError`の場合は、エラーを分かりやすく表示してくれる`convert_error`という関数が提供されています。

```rust
match error {
    Err(nom::Err::Error(e)) => println!("{}", convert_error("abc012:::", e)),
    _ => (),
};
```

これによってどのパーサがどこで失敗したかが分かるようになっています。

```
0: at line 0, in Digit:
abc012:::
^

1: at line 0, in Alt:
abc012:::
^

```

# エラー表示の問題点

`VerboseError`の表示は一見良さそうなのですが、少し気になる点があります。
感覚的には`123abc:::`の`:::`でエラーが出てほしいです。

```
0: at line 0, in Digit:
abc012:::
      ^     <--- ここでエラーでは？

1: at line 0, in Alt:
abc012:::
^

```

`VerboseError`が`:::`でエラーを出せないのは`alt`コンビネータにおけるエラー選択方法によります。
`alt`では子パーサ`tuple((alpha1, digit1, alpha1))`と`tuple((digit1, alpha1, digit1))`をそれぞれ試して両方失敗した場合`alt`自体も失敗とします。その際`VerboseError`の実装では最後に試したパーサのエラーを返すことになっています。
なので`tuple((digit1, alpha1, digit1))`を最後に試して「先頭が数値でない」というエラーになります。
しかし実際には`tuple((alpha1, digit1, alpha1))`を試した際にかなり長く受理出来ていて、最後の`alpha1`だけ失敗している状態なので、こちらのエラーを返す方がエラーメッセージとしては良くなりそうです。

# `GreedyError`
これを改善するために`VerboseError`のうち`alt`でのエラー選択方法を変更して`GreedyError`を実装しました。

https://github.com/dalance/nom-greedyerror

`GreedyError`では`alt`で複数のエラーが検知されたときに、最も長く受理されたエラーを選択します。
使い方は`VerboseError`とほぼ同じですが、「最も長い」ことを判定するために入力型から現在位置を取得できる必要があります。
そのため入力型を[nom_locate](https://github.com/fflorent/nom_locate)の`LocatedSpan`などに変更します。

```rust
type Span<'a> = LocatedSpan<&'a str>;
let error = parser::<GreedyError<Span>>("abc012:::");
```

これにより先ほどのエラーは

```
0: at line 0, in Alpha:
abc012:::
      ^

1: at line 0, in Alt:
abc012:::
^

```

となって、`:::`が`alpha1`に失敗したことが分かります。