OmniAICreator/Qiita-1.07M huggingface dataset:
初めてウェビナーやってみて得られた知見

コロナウィルス対応で、いままでオフライン＋補完的にオンラインで配信していたOffice365の社内向け勉強会を、フルオンラインで開催することになった。

説明する側で一番気になるのは、参加者の反応。表情、目線、キーボードをタッチしている手。ウェビナーだとこれが全くない！


直近で参加した[第29回 Office 365 勉強会](https://jpo365ug.connpass.com/event/170202/)に、オンラインで参加者したんだけど、参加者の反応や意見（チャットや声）を聴きながら進めるスタイルをとても気に入った&参考になったので、思い出しながら準備・開催してみた。


#事前アンケート
開催前にアンケートをしてみた。全員に知ってほしい「〇〇やってますか」に対して、はい/いいえの2択を何問か。
参加者のスキルを把握して、説明会のレベル感や重点ポイントを押さえるのに役になった。

事前アンケートがあると、参加する方も「アンケート項目にどう答えたか」に対して課題持ってくれるし、これがあると説明会中の話題としても使える。

#開催前
時間の少し前にスライドを一枚。参加するにあたってのお願いを記載しておいて、それから冒頭でも確認を促した。

マイクはミュート、チャットウィンドウオン、可能ならカメラをオン、という3つだけ。それだけ！？という感じだけどやってほしいこと試してもらうのには、ちょうどいい。
あと、開催前に事前アンケートまだの方は回答お願いします！と案内しつつ、チャットでもURLを案内。それから何かあれば途中でもチャットで質問くださいね、と案内。

参加者の表情が見えるわけでもないし、マイクミュートだから声もない。フィードバックをもらうにはチャットなので、チャットウィンドウを開いておいてもらう。事前にやっておけば、打つだけだし。ほんのワンクッションだけど、これは今後も使いたい。

#説明会中

途中で、事前アンケートの結果を画面に表示しつつ、アンケートの項目について質問を振ってみる。

「これ、みなさんしってますか？やってますでも、わからないでもいいです、チャットに書いてみてください」

と話したら滝のように流れてくる。時々、コメントを読み上げたり、いいね！をつけたり。感覚的には参加者の半数はチャットで回答してくれた。


この質問を振って、チャットに書いてもらうように促すまでと、促した後ではガラッと変わった。いままでは質問が1つも出なかったのに、これ以降は質問してくれる人が出てきた。いきなり質問は難しいけど、一度チャットで書いてもらうとハードルが下がるんだと思う。

説明会冒頭にチャットで書いてもらうハードルを下げるために、一言書いてもらう（おつかれさまですー、でもいい）と早い段階で引き出せたかも。これが次回はやる。

#説明会後
説明会の最後に、出欠確認兼ねてアンケート。Office365ならもちろんFormsで。アンケートかいてもらったら退出OKと話しして、質問ある方チャットでどうぞ、と案内。

Formsはライブで結果が集計されるので、結果を画面共有しつつ、アンケート結果を見ながらコメントする。参加された方にも結果URLをみえるようにしているけど、やっぱりその場で一緒に見ていただけるのは大きい。

その横でアンケート回答終わったら方から挨拶や、質問が。チャットを読み上げたり、質問に回答したり。質問に、いいね！がつくとそれを読み上げたり。普段のオフラインの説明会よりも質問が多く出た。意外な効果だった。


#次回にやってみたいこと

Office365勉強会もそうだけど、私が参加している勉強会ではSli.doを使っているケースが多い。匿名で質問をあげられるので自由に質問できるし、事前に質問もできれば説明会最中にも質問できる。でもって、いいね！をつけられるので、「誰かの質問」ではなく「みんなの質問」になる。

Office365だけで似たようなこと実現できないかな・・・と考えてみたけど、質問者の名前が見えていいならカスタムリストで、いいね！の数順でソートすればいけそう。
質問者を匿名化したいなら、Formsを匿名で回答するにして、カスタムリストに転記するPower Automateつくればいけそう。これは次回までに準備して試してみる。


#まとめ

参加してもらう方の理解を深めるために、参加してる！という意識を持ってもらう仕掛けは大事。
説明する側もきちんと伝えるために参加者の反応をみえるように工夫することも大事。

フィードバックしやすい雰囲気を作るために、チャットを促すというのは、両方を満たす良い仕掛けだと思う。

ノンバーバルな反応が見えにくいけど、工夫次第で双方向性を多少なりとも出せそう。こういった仕掛けはOffice365の機能組み合わせればいろいろできるので、積極的に試していきたい。

もしも社内や社外でウェビナーする方の参考になれば幸いです。
IntelliJ IDEA で JFrame が実行できない

# 何の記事？
IntelliJでJFrameのアプリケーションを実行できないときの一例

# どんな状態？
実行すると見慣れないエラーメッセージが出てきて実行できない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287607/2455950e-9a70-61f2-0f20-e99d2e7e67c3.png)

どんな簡単なアプリケーションでも駄目です。

```Java

import javax.swing.*;

public class Temp {

    JFrame frame;
    
    public Temp(String title){
        frame = new JFrame(title);
        frame.setVisible(true);
    }

    public static void main(String[] args){
        new Temp("title");
    }
}
```

こんな簡単なのでも駄目です。

# どうすればいいの？
原因はJDKのバージョンです。
自分が見た限り、少なくとも11では動きません。
これを1.8にすると動きます。

ただし今から途中でいろいろいじって1.8にしても、コンパイル時点のバージョンと変わってしまうのでどのみち実行はできません。

新たに1.8でプロジェクトを作り直して実行しましょう。
OpenModelica　バージョン違いインストール

# はじめに
OpenModelica(以下、OM)は新しいバージョンをインストールする際に既にインストールされているバージョンをアンインストールするかどうか選択を迫られる。
そのまま実行すると既存のOMをアンインストールしなければ別のバージョンをインストール出来ない。
ただし、裏技的に別バージョンをインストールする方法が紹介されていたので以下に示す。

# 事前準備

以下のサイトから別バージョンのインストーラをダウンロードしておく。  
https://openmodelica.org/download/download-windows

一つのバージョンをインストールしておく。  

# バージョン違いインストール

## 1. 既存のOMのインストール先のフォルダ名を変更

以下は既存のOMが1.13の場合  

``` 
変更前
C:\OpenModelica1.13.264bit

変更後(変更名は何でも良い)
C:\OpenModelica1.13.264bit_
```

## 2. 別バージョンのインストール  

### OM1.13以前の場合  

インストーラの指示に沿ってインストールする。

### OM1.14以降の場合  

OM1.14以降の場合、デフォルトだとC:\Program Files直下にインストールされる。
「Program Files」内に含まれる空白スペースがこの後の工程で問題になる。  
空白スペースが含まれないフォルダにインストールすれば問題を回避できるが、以下ではデフォルトの設定のまま空白スペースの問題を回避する方法を示す。

## 3. 既存のOMのインストール先のフォルダ名を元の名前に戻す  

以下は既存のOMが1.13の場合 

```
C:\OpenModelica1.13.264bit
```


## 4. 起動バッチファイルの作成　　

このままではパスがおかしいのでパスを設定する起動バッチファイルを作成する。
以下をテキストファイルに貼り付けて、拡張子をbatに変更し、ファイルをダブルクリックすればOMが起動する。

2020/06/09追記  
setxの行のコマンドが無いとOpenModelicaShellで計算がエラーとなってしまうため追記しました。  

```OM1.12用の起動バッチ
set OPENMODELICAHOME=C:\OpenModelica1.12.0-64bit
setx OPENMODELICAHOME C:\OpenModelica1.12.0-64bit 
set OPENMODELICALIBRARY=C:\OpenModelica1.12.0-64bit\lib\omlibrary
setx OPENMODELICALIBRARY C:\OpenModelica1.12.0-64bit\lib\omlibrary
%OPENMODELICAHOME%\bin\OMEdit
```

```OM1.13用の起動バッチ
set OPENMODELICAHOME=C:\OpenModelica1.13.264bit
setx OPENMODELICAHOME C:\OpenModelica1.13.264bit
set OPENMODELICALIBRARY=C:\OpenModelica1.13.264bit\lib\omlibrary
setx OPENMODELICALIBRARY C:\OpenModelica1.13.264bit\lib\omlibrary
%OPENMODELICAHOME%\bin\OMEdit
```  


「Program Files」のパスは問題が起こるので以下のように短縮名で記述する。  


```OM1.14dev用の起動バッチ
set OPENMODELICAHOME=C:\PROGRA~1\OpenModelica1.14.1-64bit
setx OPENMODELICAHOME C:\PROGRA~1\OpenModelica1.14.1-64bit
set OPENMODELICALIBRARY=C:\PROGRA~1\OpenModelica1.14.1-64bit\lib\omlibrary
setx OPENMODELICALIBRARY C:\PROGRA~1\OpenModelica1.14.1-64bit\lib\omlibrary
%OPENMODELICAHOME%\bin\OMEdit
```

```OM1.15dev用の起動バッチ
set OPENMODELICAHOME=C:\PROGRA~1\OpenModelica1.15.0-dev-64bit
setx OPENMODELICAHOME C:\PROGRA~1\OpenModelica1.15.0-dev-64bit
set OPENMODELICALIBRARY=C:\PROGRA~1\OpenModelica1.15.0-dev-64bit\lib\omlibrary
setx OPENMODELICALIBRARY=C:\PROGRA~1\OpenModelica1.15.0-dev-64bit\lib\omlibrary
%OPENMODELICAHOME%\bin\OMEdit
```

上記のように実施すればどのバージョンのOMもインストール出来る。

# 参考サイト
https://trac.openmodelica.org/OpenModelica/ticket/3889
LaTeX初心者によるLaTeX勉強記録 その①（2020/04/17）

#0. 目次
1. はじめに
2. LaTeXを使ってやりたいこと
3. 作業環境
4. LaTeX勉強記録
5. 成果物
6. 感想 
7. 参考にしたWEBページと教科書

#1. はじめに
この記事はLaTeX初心者である私がLaTeXを勉強していく記録です(2020/4/5~現在)。
そして、Qiitaに投稿する初めての記事であり、あくまで個人の勉強記録です(あわよくば読者皆様の発奮材料にして頂けたらと思います)。
誤りがございましたらコメント欄にてご教授いただけると幸甚です。
本稿の最後に勉強材料を記載しています。

#2. LaTeXを使ってやりたいこと
わたしはとある試薬メーカーに勤めており、開発した試薬のデータシートを書くこともあります。
データシートには化学構造式を書いたりすることもあります。
そのなかで、LaTeXを自在に使いこなすことが出来れば、美しいデータシートを作れたりと、仕事にも役立つのではないかなと思ったのがモチベーションです。

#3. 作業環境
LaTeXを使うのにどんなスペックのPCが必要かは分かりませんが、下記リンクのPCを使用しています。 
使ってみて不具合が出たら考えるということで。
https://jp.msi.com/Laptop/GL63-9SX-GTX/Specification

#4. LaTeX勉強記録

１. LaTeXとはなんぞ 
まず、ラテフ(もしくはラテック)と読むらしいです。ずっとラテックスだと思ってました[1]。 
LaTeXは簡単にレポートだとか論文を書くために作られたソフトウェアらしいです。Wordでは化学構造式は書きづらいですもんね。  

２. LaTeXをインストール[2] 
LaTeXの本来の目的、LaTeXで出来ることが私のLaTeX勉強モチベーションと合致しているので、早速インストールしたいと思います。基本的に[2]に沿っていけばインストールできると思います。
[3]に付属しているDVD-ROMからもインストール可能なようです。

３. LaTeXを使ってみる
a. pdfpLaTeXを使えるようにする[4]。
[編集]→[設定]→[タイプセット]→[タイプセットの方法の＋アイコンをクリック]→[下記のように設定]
※ここまで順調にいってれば、プログラムの"ptex2pdf"は"C:/w32tex/bin/ptex2pdf.exe"にあると思います。  

| 設定箇所         |                設定値    |
|:---------------:|:------------------------:|
| 名前：           |pdfpLaTeX                |
| プログラム：     | ptex2pdf                 |
| 引数：           |               -l        |
|                 |               -ot        |
|                 |-kanji=utf8 $synctexoption|
|                 |            $fullname     |
b. 文章を書く[3]。いろいろ載ってます。丁寧で分かりやすい。
c. 数式を書く[3]。いろいろ載ってます。丁寧で分かりやすい。
d. 化学構造式を書く。

- ⅰ. パッケージのインストール[5]  
「chemfig インストール」でググって、あれやこれやしてchemfigというパッケージをインストールしました(ほかにもパッケージがあるのかもしれませんが、勉強中です)。ちなみにLinuxやMacでTeXを使っている人は別途インストールの必要ないみたいです。自分はWindowsユーザーなので。
- ⅱ. 化学構造式の書き方を学ぶ[6]。


４. Overleaf [7]
・オンラインのLaTeXエディター。
・上でやってきたインストール作業などが不要(ガーン)。 
・必要なパッケージがコンプリートされてます。 
・ひとつの文書を複数人共同で編集できる。 
・画面右半分がプレビュー画面です。
・ネットワーク環境が無いと使えません。こればっかりはローカルが優越。
・どんな環境でも使えるのかな？
他にも[8]にメリット・デメリットが挙げられております。ごもっともなご意見。

#5. 成果物
下記、自分が作成した文書です。大したものではありません。お恥ずかしながら。
![suuiki.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338938/1c2dafb6-0ce9-c142-301d-84a1ee2234a7.jpeg)
![chem.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338938/c609bd33-c2bf-6a0c-9816-fe20d3eb53d8.jpeg)


#6. 感想
使いながら慣れていくしかないのでしょう。その中で、改良を重ねていくと。
LaTeX書いて上達して、気が向きましたら、その内容についてまた記事を書こうと思います(Errorメッセージの対応の記事、その記録とか書けたらいいよなあ)。　　
以上、乱文にて失礼いたしました。


#7. 参考にしたWEBページと教科書
1. https://ja.wikipedia.org/wiki/LaTeX
2. https://did2memo.net/2016/04/24/easy-latex-install-windows-10-2016-04/
3. https://www.amazon.co.jp/dp/B01NAW5V3E/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1
4. http://www.yamamo10.jp/yamamoto/comp/latex/texworks/index.php
5. https://hitgot.org/archives/chemfig-instal/
6. https://doratex.hatenablog.jp/entry/20141212/1418393703
7. https://ja.overleaf.com/project
8. https://computational-chemistry.com/top/blog/2018/07/30/overleaf_manuscript/
PowerMockでsuperメソッド呼び出しをモックする方法

#はじめに

MockitoとPowermockを利用したJUnitにおいて、どうしても`super`を利用した親クラスの処理をモックする必要があって結構悩んだので、メモしておきます。調べると`PowerMockito.suppress()`を使えってのは結構出てくるのですが、`suppress()`だとスキップ処理されるだけであり、きちんとこちらの想定するモックオブジェクトを返してくれいとうまくJUnitの後続処理を実行できない状態でした。

#テスト対象クラス
サンプルのコードを以下に記載します。DTOクラスは省略します。

親クラス

```
public class Parent {

	public OutputDto execute (InputDto input) {
		System.out.println("Parent#execute()");
		OutputDto out = new OutputDto();
		out.setText(input.getText());
		return out;
	}
}
```
子クラス

```
public class Child extends Parent {

	public OutputDto execute (InputDto input) {
		System.out.println("Child#execute()");
		OutputDto out = super.execute(input);
		out.setText(out.getText()+" updated in Child.");
		return out;
	}
}
```
子クラスで、`super.execute()`をして戻り値を期待しているところがポイントです。

JUnitテストクラス

```
@RunWith(PowerMockRunner.class)
@PrepareForTest({Parent.class})//親を指定
public class MockSuperTest {

	// テスト対象クラス
	@InjectMocks
	private Child child;

	@Before
	public void setUp() throws Exception {
		MockitoAnnotations.initMocks(this);
	}

	@Test
	public void testExecute1() {
		//入力データ準備
		InputDto input = new InputDto();
		input.setText("hello");
		OutputDto result = new OutputDto();
		result.setText("hello updated in Child.");

		try {
			Method method = child.getClass().getMethod("execute", InputDto.class);
			PowerMockito.replace(method).with(
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("replaced execute()!!");
						return result;
					}
				});
		} catch (Exception e) {
			e.printStackTrace();
			fail();
		}

		OutputDto testOut = child.execute(input);
		assertEquals(result.getText(), testOut.getText());
	}
}
```

#実行結果
上記のJUnitを実行すると、

```
Child#execute()
replaced execute()!!
```
となり、子クラスの`execute()`を呼んだ後、`super.execute()`のところが`PowerMockito.replace()`で指定した内容に置き換わっています。

ちなみに、

```
@PrepareForTest({Child.class})//子を指定
public class MockSuperTest {
```
のところを子クラスの方で指定すると、結果は

```
replaced execute()!!
```
となり子クラスの`execute()`を直接変更します。普通に実行するともちろん

```
Child#execute()
Parent#execute()
```
が期待値です。


以上です。
MATLABのかわりにOctaveかScilab

コロナの影響で研究室出入り禁止になりました。
そのため、研究室で使用していたMATLABのコードを自宅で動かせるようにしろと指令がありました。
そこで検討したのがOctaveとScilabでした。
##環境
Windows 10
## Octaveは楽
.m (MATLABの拡張子)がそのまま使えるのでとても簡単でした。

※[winopen](https://jp.mathworks.com/help/matlab/ref/winopen.html) は実行できませんでした。
画像を表示するなら、imshow()でいい

※MacBook Proを使用していた友人はインストールがなかなか出来ないと言っていたのでmacOSは難しいかも

※一回の実行にかなり時間がかかります。同じファイルの実行時間を測定したところ、Scilabが2秒ほどで完了したのに対し、Octaveは7秒かかりました。
## Scilabもあり
MATLABと似ていましたが、体感2割ほど書き換えました。
画像を扱う場合、モジュール管理からIPCVをインストールする必要がありました。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533114/1a2f2a5d-cd25-944a-3b5c-b3a6984d8e01.png)
- - -
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533114/a72374bd-b275-ed03-78a7-714bcb7753c4.png)
---
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533114/a215e810-83cf-052d-b6b6-6df0794c3769.png)
---

###書き換えたもの
| MATLAB | Scilab |
| ---- | ---- |
| load() | fscanfMat() |
| pi (π), i (虚数) | %pi, %i |
| % (コメントアウト) | // |
※画像保存の際、imshow()を使用した後にxs2png()を実行してできた。

※Macでも問題なく実行できました。
DataRobotでIBMの離職者予測

# 学習データ
データはkaggleのこちらのもの👇
https://www.kaggle.com/pavansubhasht/ibm-hr-analytics-attrition-dataset

特徴は全部で35列

年齢、性別などの基本情報から、残業してたか、給料、勤めてからどのくらいたつかなどもあります。
ターゲットは「**Attrition**」離職したかどうかです。
<img width="1433" alt="スクリーンショット 2020-04-17 20.17.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/5004167c-be30-f575-203d-f887a98cef3b.png">

見るからに不均衡なデータです。
<img width="330" alt="スクリーンショット 2020-04-17 20.17.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/36d560e3-270a-b1dd-9b96-541e9a92c72f.png">

#学習
<img width="1680" alt="スクリーンショット 2020-04-17 20.15.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/e1a11118-83b2-6ca7-f804-085e19f81b34.png">

続々とモデルが作成されていきます。
<img width="1680" alt="スクリーンショット 2020-04-17 20.25.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/347197b7-0be8-8991-c88d-01d6fb11e4fb.png">

#結果
合計41個のモデルが生成されました。
いちばん精度が高かったのはElastic-Net Classifierでした。
ここまでわずか数分
<img width="1428" alt="スクリーンショット 2020-04-17 20.30.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/ccc74542-3968-f119-5f63-9b04d8e1d408.png">

###ブループリント
２番目に精度の高かった、おなじみのLightGBMモデルをみてみましょう。
<img width="1415" alt="スクリーンショット 2020-04-17 20.32.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/a486cfa0-4d44-6d0b-63f8-a9c502f6d571.png">
ブループリントから各特徴に施された処理が確認できます。
この自動特徴量エンジニアリングがAutoMLツールの強みですね。

###精度
<img width="1429" alt="スクリーンショット 2020-04-17 21.16.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/25e8cb1c-1423-98c7-554e-ab8c96d48aa3.png">
混同行列やROCカーブが自動生成されるのはいいですねー
ただ、190件の離職者のうちちゃんと的中できてるのは106件なので、もう少し精度が欲しいところ
このあとさらに精度をあげたいってなった場合は「Advancet Tuning」のところからハイパーパラメータなどの調整ができるっぽいですね

###インサイト
####Feature Importance
<img width="1409" alt="スクリーンショット 2020-04-17 21.24.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/fb86dea3-9959-0a5b-d867-34f27e27534e.png">
予測結果に与える影響度を可視化してくれてる機能
「OverTime」残業してるかどうかがいちばん影響してるとはなんともリアルですね。
こういうデータがあるとモデルの出力する予測結果に説得力がでてきます。

####Prediction Explanations
<img width="1400" alt="スクリーンショット 2020-04-17 21.29.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/5e68030f-d3b6-6587-7935-e850fb32bc9e.png">
予測結果を何件かとってきて、なんで予測結果がそのような値になったのかを説明してくれてます。
いちばん上のID457の予測結果では「残業あり」、「出張が頻繁」、「勤めてまだ１年目」ということで離職する確率が**95.5%**であると予測しています。

#推論
<img width="1421" alt="スクリーンショット 2020-04-17 21.33.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/35d0a0ee-d6c4-0f47-ed97-077057ed4959.png">
今回はこのデータセットが学習データのみだったため推論は省きますが、
学習したモデルを選択して「Prediction」の項目から推論が簡単に実行することができます。

#おわり
たった数分で学習から分析まで自動でやってくれるDataRobotさすがです。
他にもいろいろとデータの可視化やモデル比較など使える機能があるのでそれはまた別の記事で書こうかと思います。
【初心者向け】エラーになったときのストレスにならない解決方法

# エラーになってもストレスにならない思考回路
プログラミングをしているときにエラーになって、自分が思っていた結果にならないときはモチベーションが下がりますし、途中で嫌になってしまうことありますよね。でも考え方を変えるだけで、エラーに対して柔軟に対応することができ作業効率をあげることができます！そんな方法をわたしの経験からご紹介します^_^

## エラーになったときに行うこと
- 英語のエラー文を必ず読む(Google翻訳などを利用する)
- エラー文を検索する
- typo(打ち間違い)の可能性を考える

### 英語のエラー文を必ず読む(Google翻訳などを利用する)
エラーになった場合ターミナルなどに必ずエラーの内容が表示されます。プログラミングを始めたばかりだと、エラーになってしまったら混乱して見落としてしまうことが多いですが、丁寧にエラーの内容が書いていて、ときにはエラーのヒントも表示してくれます。

```
ChisakinoMacBook-Pro:todoproject Chisaki$ git push -u origin master
To https://github.com/(GitHubアカウント名)/todo.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/(GitHubアカウント名)/todo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```
一見して嫌になってしまう英語の羅列ですが翻訳すると

<img width="1440" alt="スクリーンショット 2020-04-17 21.04.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587506/ac5414f7-bf53-ea77-feed-ffe8259f0e55.png">

きちんと現状のエラーの内容とそれを解消するためのヒントが書かれていますのでそれを参考にすると紐解いていけるかと思います！

### エラー文を検索する
エラー文の定型文をそのまま検索することによって解決する手立てなどが見つかります！このときに注意するべきことはきちんと一つ一つ丁寧に解説を読み、面倒臭がらないことです。どうしても面倒臭がって遠回しにしてしまうと検索のループになってしまいますので、自分がどうやってエラーの原因と解消を行えばいいかを整理しながら考えられるとことが大切です！例えば
わたしは今回のエラーの場合、強制的にpushすることを選択しました。

```
git push -f origin master
```
その後にもう一度pushしたら成功しました^_^

### typo(打ち間違い)の可能性を考える
typoつまり打ち間違いの可能性を考えることは非常に大切です。なぜなら初心者のコーディング上のエラーの9割はtypoが原因と言われているそうです。もし開発環境もしっかりしていて構文も間違いなかったとしても、1文字間違えるだけでエラーになってしまうことがあります。そのためスペルチェックは欠かせません！
ただ一つ一つ丁寧にミスを見つけることはすごく大変ですよね...一番いいのはミスをしないことになります！
そのためわたしは**スペルチェッカー**をエディタに導入しています。
<img width="800" alt="スクリーンショット 2020-04-17 21.21.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587506/5880a35b-e936-8665-ae6b-c87befce5fe8.png">
https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker

スペルチェッカーを導入することでケアレスミスをした場合でも下線でミスを知らせてくれますのですごく安心です^_^

## まとめ
いかがだったでしょうか？初心者の方にとってエラーは大敵ですよね。でもそんなエラーもなるべく1人で解決することができたらすごく効率もいいし、個人での開発の成長にも繋がりますよね！ぜひこの記事がお役に立てましたら幸いです^_^
【Vue-Cli】.envの適応を切り替える

#環境ごとの.envファイル
以下のように環境変数のファイルを分ける

- `.env`
- `.env.local`
- `.env.development`


# vueに適応する
```javascript:package.json
  "scripts": {
    // .env.localが適応される
    "local-serve": "vue-cli-service serve --mode local",
    // .env.developmentが適応される
    "local-serve": "vue-cli-service serve --mode development",
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "test:unit": "vue-cli-service test:unit",
    "lint": "vue-cli-service lint"
  },
```
C# 基礎プログラミング100本ノック～1-5本目～

#こんばんは
今日もはじめて行きますよ！
前回→[0本目](https://qiita.com/K_Hisui/items/5929354c36c2084382a5)
次回→ストックないです！


#1本目！

>12345+23456を計算して結果を表示するプログラムを作成せよ

さて、ではやっていきましょう。


~~~sample.cs
Console.WriteLine("12345 + 23456 = " + (12345+23456));
~~~

#2本目！
>12345を7で割った余りを表示するプログラムを作成せよ。

~~~sample.cs
const int X = 12345;
const int Y = 7;

int result = X % Y;

Console.WriteLine(X + "を" + Y + "で割った余りは" + result + "です。");
~~~

#3本目！
>整数値を入力させ、その入力値を表示するプログラムを作成せよ。

~~~sample.cs
Console.WriteLine("整数値を入力してください。");
int inputNum =  int.Parse(Console.ReadLine());
Console.WriteLine("入力された値：" + inputNum);
~~~

普段javaを書く機会が多いので

~~~sample.cs
Integer.Valueof(Console.ReadLine());
~~~

とか書いてましたがParseを使うんですね。

#4本目
>整数値を入力させ、その入力値を3倍した計算結果を表示するプログラムを作成せよ。

~~~sample.cs
const int X = 3;

Console.WriteLine("整数値を入力してください。");
int inputNum =  int.Parse(Console.ReadLine());
Console.WriteLine("入力された値の" + X + "倍は：" + inputNum*X);
~~~

#5本目！
>整数値を2つ入力させ、それらの値の和、差、積、商と余りを求めるプログラムを作成せよ。なお、差と商は1つ目の値から2つ目の値を引いた、あるいは割った結果とする。余りは無い場合も0と表示するのでよい。

~~~sample.cs
Console.Write("1st input num：");
int inputNumX =  int.Parse(Console.ReadLine());
Console.Write("\r\n"+"2nd input num：");
int inputNumY = int.Parse(Console.ReadLine());
Console.Write("\r\n");

Console.WriteLine("和：" + (inputNumX + inputNumY));
Console.WriteLine("差：" + (inputNumX - inputNumY));
Console.WriteLine("積：" + (inputNumX * inputNumY));
Console.Write("商：" + (inputNumX / inputNumY));
Console.WriteLine("余り：" + (inputNumX % inputNumY));
~~~

入力値を保存しておくとき変数ではなく配列の方が応用しやすくていい気がしますね...
スパゲティのもとになりそう...
一先ず今日はこの辺で！

#リンク
[基礎プロI 100本ノック 基礎編](http://www.cc.kyoto-su.ac.jp/~mmina/bp1/hundredKnocksBasic.html)
【GAS】Google Apps Script 始め方と簡単なスプレッドシート操作

# はじめに
GAS(Google Apps Script)というJavascriptライクなプログラミング言語があります。
Google drive上に保存されて、google calendarやgoogle spreadsheet等々と連携することができます。
実行環境を整える必要はないのでその点ではとても便利かと思います。
今回は、ファイルの作り方から簡単なスプレッドシートの操作まで解説しようと思います。

# ファイルの作り方
## 1. スプレッドシートと紐づいたファイルを作るとき
新しいスプレッドシートを開いて、「ツール」メニューから「スクリプトエディタ」を選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426354/0e3ab18a-8606-1064-a901-efb1c03f6b77.png)



## 2.スプレッドシートと紐づかないファイルを作るとき
Googleドライブ上で右クリック⇒その他⇒Google Apps Scriptを選んでください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426354/51352e80-ec43-278b-7e2d-933846bb7fba.png)


1も2もこんな感じでエディタが出てきていれば完了です。(左上のファイル名はなんでも大丈夫です)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426354/7bd33b6f-b9f2-cb36-3852-19390ff3161f.png)



# ファイルの編集
ここからは、スプレッドシートと紐づいたGASファイルの説明をします。
エディタがダークモードにもできるので好みに合わせて設定してください。
https://chrome.google.com/webstore/detail/appsscript-color/ciggahcpieccaejjdpkllokejakhkome/related

プログラムを編集しましょう！以下のようにJavascriptのようになります。
※Logger.logとconsole.logの違いについては[こちら](https://tanuhack.com/gas-log/)

```JavaScript
function myFunction() {
  Logger.log("Hello world!");
  
  var num1 = 1;
  var num2 = 9;
  
  Logger.log(num1+num2);
}

```

# 実行、ログの確認
実行方法ですが、メニューの三角ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426354/2f9c4022-a964-2839-8fd6-f9bb6e511982.png)

その後、「Ctrl」+「Enter」または「表示」メニューのログからログを見ることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426354/46d9e896-645f-568d-8dbb-720767869300.png)



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426354/00b47505-6cbf-9a57-df0a-ddea5fa307a2.png)

# スプレッドシートの編集
## 値の代入
スプレッドシートを操作するときは以下の3つのオブジェクトで操作します。
・スプレッドシート：Spreadsheetオブジェクト
・シート：Sheetオブジェクト
・セル範囲：Rangeオブジェクト

それぞれに色々なメソッドがあります。今回は下に示すようなプログラムで説明します。
`SpreadsheetApp.getActiveSheet()`でシートを取得、`sheet.getRange("A1:B2")`でA1セルからB2セルを取得しています。
また、Rangeオブジェクトの`setValue`メソッドでセルに値を代入しています。

```Javascript
function myFunction() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var range = sheet.getRange("A1:B2");
  
  range.setValue(1);
}
```

以下のようにコード補完と説明が出てきてくれるので実装中になんとなくわかるかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426354/bebb72fd-08ce-50ba-27e3-624ec0f293b9.png)

これを実行しようとすると以下のような承認画面が出てきますので許可をしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426354/bacc9085-8db7-839d-7209-f9cdcb2d112f.png)

一番最初に作ったスプレッドシートのA1からB2セルに1が入っていたら成功です！

## 値の取得
次にスプレッドシート上の値の取得をしてみましょう。
コードは以下になります。
Rangeオブジェクトの`getValues`メソッドでセルの値(配列として)を取得しています。

```Javascript
function myFunction() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var range = sheet.getRange("A1:B2");
  
  Logger.log(range.getValues());
}
```
以下のように2次元配列になっていますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426354/aafd29f5-850f-56cc-f482-29d9316b370b.png)


# おわりに
今回は以上です！
GASはgoogle calendarの予定をとってきたりもできるのでその方法も後日紹介したいと思います！

また、●曜日の〇時に実行のようにトリガーを設定できるのでSlackやGmailなどと連携させればリマインドとしても使えますね。
ぜひ活用してみてください！
Pythonでファイルのツリー構造を出力する

# 概要

コマンドのtreeみたいな感じで、Python上でファイルやディレクトリのツリー構造をいい感じに出力する関数を作ったのでメモ。

# 結論

下記の関数にツリーで表示したいディレクトリのパスを与えれば良い。Mac用に実装しているので、パスがスラッシュで区切られないような場合は非対応。

```python
import pathlib
import glob
import os

def tree(path, layer=0, is_last=False, indent_current='　'):
    if not pathlib.Path(path).is_absolute():
        path = str(pathlib.Path(path).resolve())
    
    # カレントディレクトリの表示
    current = path.split('/')[::-1][0]
    if layer == 0:
        print('<'+current+'>')
    else:
        branch = '└' if is_last else '├'
        print('{indent}{branch}<{dirname}>'.format(indent=indent_current, branch=branch, dirname=current))
    
    # 下の階層のパスを取得
    paths = [p for p in glob.glob(path+'/*') if os.path.isdir(p) or os.path.isfile(p)]
    def is_last_path(i):
        return i == len(paths)-1
    
    # 再帰的に表示
    for i, p in enumerate(paths):
        
        indent_lower = indent_current
        if layer != 0:
            indent_lower += '　　' if is_last else '│　'
            
        if os.path.isfile(p):
            branch = '└' if is_last_path(i) else '├'
            print('{indent}{branch}{filename}'.format(indent=indent_lower, branch=branch, filename=p.split('/')[::-1][0]))
        if os.path.isdir(p):
            tree(p, layer=layer+1, is_last=is_last_path(i), indent_current=indent_lower)
```

例えば、Testというディレクトリが以下のように構成されている場合を考える。

 - Test
    - Test_01
        - bbbbb.txt
        - ccccc.txt
    - Test_02
    - Test_03
    - aaaaa.txt

この時treeを実行するとこんな感じ。

```python
tree('/hogehoge/Test')
```

```text:出力結果
<Test>
　├<Test_01>
　│　├ccccc.txt
　│　└bbbbb.txt
　├<Test_02>
　├<Test_03>
　└aaaaa.txt
```

相対パスで指定しても結果は同じ。

```python
tree('./') # /hogehoge/Test で実行
```

```text:出力結果
<Test>
　├<Test_01>
　│　├ccccc.txt
　│　└bbbbb.txt
　├<Test_02>
　├<Test_03>
　└aaaaa.txt
```
Zeit Now + Next.js のページにGoogle AnalyticsをGTM(Google Tag Managerで導入したメモ

## 概要
* Zeit Now + Next.jsの開発環境ができた([*1][*1])([*2][*2])ので、GTMを導入してみた。
* トリガーを2つ仕込む以外は取り立てて特別なことはしなくてよかった。

## 準備
* Google Analytics を作成。
  * TRACKING_IDをメモ
* Google Tag Managerを作成。
  * トリガーは2つ設定
  * ページビュー（アクセス時用）
  * 履歴を変更（Next.jsのLinkでSSR内のページ遷移をしたとき用）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/be2aa0ac-c90c-9267-7f9b-a0377b20aac1.png)

## ソース修正

```tsx:src/pages/_document.tsx
export default class MyDocument extends Document {
  render() {
    const GA_TRACKING_ID = 'GTM-TFQ27FV'
    const gtmScript = `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','${GA_TRACKING_ID}');`
    const gtmFrame = `<iframe src="https://www.googletagmanager.com/ns.html?id=${GA_TRACKING_ID}" height="0" width="0" style="display:none;visibility:hidden"></iframe>`
    return (
      <Html lang="en">
        <Head>
          <script dangerouslySetInnerHTML={{ __html: gtmScript }} />
        </Head>
        <body>
          <noscript dangerouslySetInnerHTML={{ __html: gtmFrame }} />
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}
```


## 環境

- Windows 10 Home
- virtualbox 6.1.6
- Vagrant 2.2.7
- ubuntu 18.04 LTS
- docker-ce Docker version 19.03.5, build 633a0ea838
- docker-compose version 1.25.3, build d4d1b42b
- node 13.13
  - now-cli: 18.0 
  - next: 9.3.4
  - react: 16.13.1
  - react-dom: 16.13.1
  - @reduxjs/toolkit: 1.3.4
  - react-redux: 7.2.0
  - firebase: 7.14.0
  - firebase-admin: 8.10.0
  - react-firebaseui: 4.1.0
  - typescript: 3.8.3

## 参考

[Docker で zeit nowのデプロイ環境とNext.jsの開発環境を作ったメモ][*1]
[PdfMakeを使ったPDF作成APIをZeit Nowで動かしたメモ][*2]
[gtag manager](https://wacul-ai.com/blog/access-analysis/google-analytics-setting/tag-manager/)
[next.js sample](https://github.com/zeit/next.js/blob/canary/examples/with-google-analytics/lib/gtag.js)
[Next.js のプロジェクトに GTM を組み込む方法](https://qiita.com/seya/items/d4108d28ee5b1773f671)
[*1]:https://qiita.com/hibohiboo/items/e6c30e76e26dde0e8611
[*2]:https://qiita.com/hibohiboo/items/9123fc6ecb546c5820e3
Chankoがproduction環境でもerrorをraiseするようにする

本番でもerrorを出せるようにしたくて調べました。

Chankoとは
---
https://github.com/cookpad/chanko
Cookpadが２０１３年（！）に開発したRailsのgem
便利で大好きなgem。ユースケースやらなんやらは[開発者ブログ](https://techlife.cookpad.com/search?q=Chanko)に詳しいです。

私が使っているのは以下
- 本番環境にdeployしながら、ユーザーには見せない（defaultを出す）

A/Bテストにも使えるのだろうが使っていない。使いたいなー。

何が問題か
---
Chankoはproduction環境ではerrorをraiseせず、握りつぶしてしまう実装になっている。
不完全なものを出してしまった場合であっても、内部でエラーが発生した場合は別途指定してあるdefaultの内容が実行されるため、ユーザーには最低限元の機能を提供できる。
リリース済みの環境で、新たな機能追加や一部変更、デザイナーとの協業などの際、ざっくりした内容でアップしてもユーザーに影響しない形で実装できるので、CIも回しやすい。ありがたやありがたや…

しかし、エラーは握りつぶされ、よし、ユーザーからの評判も上々だ！本番に実装するぞ！とコードを移した際にエラーが発覚する、ということも往々にしてある。
もしくはA/BテストでAの結果が多く出たけど、実際にはBは内部でエラーが発生しており、きちんと考慮した割合で持ってテストできていなかった、というような場合もありうる。
じゃあもう本番でもちゃんとエラーが出るようにするわ、となったときに考えうる選択肢は２つ

#### 1. unit[^unit]単位でerrorをraiseするか指定する
https://github.com/cookpad/chanko/blob/bc20b982df4d22b539f6c08aa2e4414e380ae60d/README.md#raise_error
普通に書いてある。ChankoはReadMeがとってもシンプルでわかりやすくてだいすき。
`rails generate chanko:unit test`
などでgenerateしてもよい。テンプレートが出てくる。便利。

```rb
module ExampleUnit
  include Chanko::Unit
  raise_error
　　：
end
```

これでこのUnitに関してはerrorはraiseされるようになる。



#### 2. productionでもerrorはraiseする設定にしてしまう
https://github.com/cookpad/chanko/blob/bc20b982df4d22b539f6c08aa2e4414e380ae60d/README.md#raise_error
>You can force all units to raise up errors by Config.raise_error = true.

これ、どこにかくのかな、って私なったんですけどとりあえず以下ファイル作ったらうまくいきました

```config/initializers/chanko_initialize.rb
module Chanko
  Config.raise_error = true
end
```

以上。
普通にライブラリのmodule上書きしてるだけだけども。
initializerでやるのかどこでやるのかなどが割とぼんやりなので、もっといいやり方があったら教えてほしいです。

[^unit]: 特定の条件をまとめて実行するChanko内の単位
タイムゾーン

# 現在のタイムゾーンの確認
```bash
$ date
Fri Apr 17 11:51:41 UTC 2020
```

# 指定可能なタイムゾーン
`/usr/share/zoneinfo/`以下のファイル。
ディレクトリ構造の場合`地域A/地域B`。たとえば東京の場合は`Asia/Tokyo`。

# タイムゾーンの変更
## 環境変数で一時的に変更

```bash
$ export TZ="Asia/Tokyo"; date
Fri Apr 17 20:53:49 JST 2020
```

## 恒久的に変更
`/usr/share/zoneinfo`以下のファイルを`/etc/localtime`にコピー、またはシンボリックリンクを張る。

```bash
cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
```

```bash
ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
```
# CentOSの場合
`timedatectl`を使用する。

```bash
$ timedatectl set-timezone Asia/Tokyo
```
```bash
$ timedatectl status
```

# 参考
https://eng-entrance.com/linux-time-timezone
オンライン飲み会する前にこれをやろう！簡単ネットワーク速度チェック！

皆さん、オンライン飲み会してますか？最近流行ってますよねー。オンライン飲み会のおかげで普段なかなか合わない旧友と飲み会ができたり、1次回と2次回のメンツをチェンジしたりと、私はこの外出自粛モードをなんとか楽しんでいます！

今回ちょっと気になったのが、「オンライン飲み会をするためのネットワーク要件」です。おそらく Zoom、Teams、Skype、Google Hangouts、LINE あたりを使っているのかと思いますが、それぞれのネットワーク要件を纏めておきます。

#それぞれのネットワーク要件
##Zoom
はやりの Zoom ですがネットワーク要件は以下のようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/c0d5bb44-42fc-5c57-0f35-7feeb93aa771.png)
参考情報 : [帯域幅の要件および参加者の帯域制限について](https://zoom-support.nissho-ele.co.jp/hc/ja/articles/360004830512-%E5%B8%AF%E5%9F%9F%E5%B9%85%E3%81%AE%E8%A6%81%E4%BB%B6%E3%81%8A%E3%82%88%E3%81%B3%E5%8F%82%E5%8A%A0%E8%80%85%E3%81%AE%E5%B8%AF%E5%9F%9F%E5%88%B6%E9%99%90%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

##Teams
Teams はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/f7c85a6f-8da2-2c55-1fc6-92255697cdc6.png)
参考情報 : [Microsoft Teams 用に組織のネットワークを準備する](https://docs.microsoft.com/ja-jp/microsoftteams/prepare-network)

##Skype
Skype はこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/dc6d0c3e-0c53-85b5-12ec-af760d333758.png)
参考情報 : [Skype で必要となる帯域幅を教えてください。](https://support.skype.com/ja/faq/fa1417/skype-debi-yao-tonarudai-yu-fu-wojiao-etekudasai)

##Google Hangouts
Google Hangouts は使っているひとが多くないかと思いますが、こんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/8c4ab4ad-c54a-7e94-4dee-bf0ceb510b1f.png)
参考情報 : [ネットワークを準備する](https://support.google.com/a/answer/1279090?hl=ja)

##LINE
LINE は公開している情報がみつかりませんでした、、もしわかった人いたら教えてください。

#ネットワーク帯域まとめ
纏めるとこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/72107f86-541a-f5d9-7115-c6310d78b10a.png)
速度が遅い状態で快適に通話できるのは Zoom でした。Google Handouts はリッチですね！笑

#オンライン飲み会する前にこれをやろう！
Google が出している超簡易版のネットワーク速度調査です。これで上記のネットワーク制限をクリアできればスムーズに快適にオンライン飲み会が実施できます。Google で検索するだけで可能なので、みなさんやってみてくださいね！

>`Google.com` にアクセスします。
`internet speed test` を検索します。
`速度テストを実行` をタップまたはクリックします。

参考情報 : [インターネットの速度をテストする](https://support.google.com/websearch/answer/6283840?p=speedtest&visit_id=637227194678766597-3143180834&rd=1)

実施例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/7d93162e-e16e-31ab-5412-840218d7f066.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/b9a8022f-f073-5ade-dcd5-0562b3abb537.png)

オンライン飲み会の前には実施して、みなさん快適に楽しく飲みましょう！！
[Blender]基礎知識 

＊レンダリング
３Dで作ったモデルを最終的な画像として書き出す
  
＊テクスチャマッピング
マテリアルによる単純な外装とは違い、画像をモデルに貼り付ける
複雑な構造のモデルは一度平面図にして、そこにテクスチャを貼り付ける（UVマッピング）

＊スカルプト
粘土細工のようにポインタでなぞって加工する

---
３Dカーソルを原点に戻す
Mesh > Snap > Cursor to World Origin
![スクリーンショット (84).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/428ba17e-c58c-bbdd-17da-67b095b68eb9.png)
ロケールについて

# ロケールとはざっくり何か
ざっくりいうと、言語をはじめ、地域の書式ルール（通貨、日付、数値表現）の定義。

# ロケール名
`言語_国.文字セット`で表現される。

|ロケール名|意味|
|---|---|
|ja_JP.utf8|日本語|
|en_US.utf8|米国における英語表記|
|en_GB.utf8|英国における英語表記|
|de_DE.utf8|ドイツのドイツ語表記|
|de_H.utf8|スイスのドイツ語表記|
|zh_CH.utf8|簡体字|
|zh_TW.utf8|繁体字|

# ロケールの調べ方
## localeコマンド

```bash
$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
```

## LANG環境変数
```bash
$ echo $LANG
en_US.UTF-8
```

## locale.conf
```bash
$ cat /etc/locale.conf
en_US.UTF-8
```

# ロケールの設定の仕方
## 環境変数で設定する
```bash
$ export LANG=ja_JP.utf8; echo $LANG
ja_JP.utf8
```

## CentOSの場合
```bash
$ localectl set-locale LANG=en_US.utf8; cat /etc/locale.conf
LANG=en_US.utf8
```

# 参考
https://eng-entrance.com/linux-localization-locale
https://docs.oracle.com/cd/E26924_01/html/E27144/glmbx.html
SwiftUI Localization「Hello, World!」->「こんにちは、世界！」

# ベース

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_01.png)

## Program
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```

## Localizable.strings作成

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_02.png)

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_03.jpg)

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_04.jpg)

<span style="font-weight:bold">Localizationの「Localize...」押下</span>
![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_05.jpg)

## Localizationsに言語追加
<span style="font-weight:bold">例：日本語追加</span>
![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_06.jpg)

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_07.jpg)

<span style="font-weight:bold">Localizable.strings配下にファイルが追加される</span>
![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_08.jpg)

## Localizable.strings (Japanese)編集

```text
"Hello, World!" = "こんにちは、世界！";
```

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_09.jpg)

## 追加した言語を表示させる
<span style="font-weight:bold">「ContentView_Previews」に「.environment(\.locale, .init(identifier: "ja"))」追加</span>

```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environment(\.locale, .init(identifier: "ja"))
    }
}
```

<span style="font-weight:bold">「Edit Scheme...」からでも可能</span>
![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_11.jpg)

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_12.jpg)

# 結果
![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/HelloWorldLocalization_10.jpg)
【AWS】Rails+MySQL+DockerアプリをEC2にデプロイする

ポートフォリオをやっとAWSにデプロイできたんですが、
地獄のような日々だったのでその孤軍奮闘を記します。

#前提
- Rails+MySQL+Dockerアプリがある
- Githubにpushされている
- AWS登録済

#参考サイト
主にこちらのサイトに沿って作業を行いました。
[DockerコンテナをEC2で起動と公開](https://qiita.com/takuyakawaguchi/items/057165b26fac88641ff1)

インスタンスの設定などはこちらも参考にさせていただきました。
[無料！かつ最短？で Ruby on Rails on Docker on AWS のアプリを公開するぞ。](https://qiita.com/at-946/items/1e8acea19cc0b9f31b98)

ぶっちゃけこの2サイトを参考にしていただければ特に問題なくコンテナは立つと思うのですが、
それ以前にも他のいろんなサイトを参考にしすぎて環境がかなりぐちゃぐちゃになっており、
中々デプロイできなかったです。

あんまりググりすぎるのもよくないですね。
似た様な状況の人は以上2つのサイトを参考にしてください。

#特に躓いたところ
ここからは特に時間がかかってしまったところについて記述いたします。
##インスタンスに接続できない
最初の躓きはインスタンスに接続できなくて一生ec2に入れなかったことです。

###原因
考えられる原因は以下です。

- コマンド走らせる場所が違う
- awsで作ったpemファイルが正しい位置に設定されていない

###解決方法
コマンドを走らせる場所なんですが、ちゃんと.sshに移動しないと接続してくれません。

```
cd ~/.ssh
```
サーバー側の知識が乏しいのでいきなりコマンド走らせてしまっていたんですが、接続なのでちゃんと.sshに移動しないといけなかったんですね。

次に確認しておきたいのがpemファイルの場所です。
.sshに移動したらそこにちゃんとawsで作成したpemファイルがあるか確認しましょう。

```
soehina@soehinaMacBook-Air .ssh % ls
known_hosts                awsdep.pem
```
このpemファイルはインスタンスを作成するときに一緒に作ったキーペアのファイルです。
作成時にダウンロードしてるはずですが、ちゃんと.sshにファイルを移動しときましょう。

##git clone ができない
githubにpushしてあるアプリをクローンしようと思ってもクローンできなくて地獄でした。

###原因
- .sshのknown_hostsに余計なものが書かれてる。

###解決方法
known_hostsにgithub以外のssh情報があったら消しときましょう。
余計な書き込みがあるとすぐエラーになるみたいです。

##bundle install ができない
こちらはrailsアプリ作成時点で注意しとかないといけないことなんですが、bundle installするときにGemfileとGemfile.lockとの情報が噛み合ってなかったことでエラーが起きました。

gemの追加・削除が正しく行えてるかちゃんと確認しときましょう。

これのせいでdocker-composeもできなくてしんどかったです。

#学んだこと・得たもの
今回このAWSエラー地獄で学んだことは以下です。

- ssh
- Linuxコマンドの操作にそこそこ慣れた
- インフラが苦手
- 安易にコマンドを打つな


###ssh・インフラが苦手
sshとかインフラとかは正直理解がかなり乏しかったので、今回のことで概要が学べて良かったかなと思います。
しかし、同時に私はインフラが苦手なこともわかりました。

コードを書いて悩むのは結構楽しいのですが、今回の様な接続がどうのこうのみたいな悩みは正直「死ぬんちゃうんか？？？」と思うくらい中々にキツかったです。

なぜ苦手に思うのか考えてみたのですが、おそらく論理構造を考える過程があまり無いからではないかと思いました。

コードを書いてる時は、パズルみたいに組み立て方を模索するのが楽しいのですが、インフラ構築はパースというより既に完成されてる装置を正しく組み立てないといけないイメージなので、考える幅があまり広がらない印象を持ちました。

###安易にコマンドを打つな
これは今回の経験で本当に心から思ったことです。
あまりにもわからなすぎてかなり投げやりになって色んな記事みながらコマンド打ちまくってたのですが、それがさらに混乱を極めてしまいました。

今度からは本当に気をつけたいと思います。

###Linuxコマンドの操作にそこそこ慣れた
Linuxコマンドの操作は現在勉強中なのですが、今回のAWSエラー地獄のおかげでコマンド操作をすることが一気に増えてそこそこ慣れました。

特にviコマンドは使いまくりましたね。

この点については手を動かしながら身に付けられて良かったです。

#まとめ
AWSでのデプロイは中々大変でしたが、とりあえず完走できて良かったです。
良い経験になりました。

人は失敗して学ぶものなので、今回の数々の失敗も学びに変えて次に活かしていきます。

ではでは。
IM-Noticeクライアント for Mac/Linux

公式の intra-mart IM-Notice デスクトップアプリは Windows でしか動作せず、しかも 1 アカウントでしか利用できない制限があるので、Go で作り直してみた。
結局 ZeroMQ で Pub/Sub しているだけっぽかったので簡単に作ることができた。
POST /mq/user で SubscribeID を取得するのがポイント。
通知には [Beeep](https://github.com/gen2brain/beeep) を利用、Mac の場合 OS の通知が利用される。
yaml ファイルにベースURLとアカウントのリストを書いておけば起動時にすべてのURLとアカウントに対して接続/購読処理を行い、以降通知を受け取ることができる。
通知履歴は作ってもいいけどどうせ利用しないので実装しなかった。
もし仮に今作るなら Fyne を使うのが流行なのだろうか。

それにしても Go はマジでイケてる。
本調子ならもっといろいろ作ったり勉強したりしたいのだが・・。
MS には Go の Win32 API を作って欲しい。

実行/コンパイル時には以下が必要

```bash
brew install libsodium
brew install pkg-config
brew install czmq
brew install zeromq
```

![スクリーンショット 2020-04-21 14.31.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131196/98e5e8cb-c3c3-2c17-d0ea-4ddfb923a981.png)

```go:main.go
func main() {
	ctx := context.Background()

	accounts, err := account.ReadFromFile()
	if err != nil {
		beeep.Alert("im_notice(mac)", fmt.Sprintf("%v", err), "assets/warning.png")
		log.Fatal(err)
	}

	endpoints, err := endpoint.NewEndpoints(ctx, accounts)
	if err != nil {
		beeep.Alert("im_notice(mac)", fmt.Sprintf("%v", err), "assets/warning.png")
		log.Fatal(err)
	}

	commaSeparatedEndpoints := endpoint.CommaSeparatedEndpoints(endpoints)
	commaSeparatedSubscribeIDs := endpoint.CommaSeparatedSubscribeIDs(endpoints)
	minTTLSeconds := endpoint.MinTTLSeconds(endpoints)
	ttlSeconds := minTTLSeconds

	for {
		sock, err := goczmq.NewSub(commaSeparatedEndpoints, "ping," + commaSeparatedSubscribeIDs)
		if err != nil {
			beeep.Alert("im_notice(mac)", fmt.Sprintf("%v", err), "assets/warning.png")
			log.Fatal(err)
		}

		defer sock.Destroy()

		for {
			time.Sleep(1 * time.Second)
			ttlSeconds--
			if ttlSeconds < 0 {
				ttlSeconds = minTTLSeconds
				break
			}

			recvs, err := sock.RecvMessageNoWait()
			if err == goczmq.ErrRecvMessage {
				continue
			}
			if err != nil {
				beeep.Alert("im_notice(mac)", fmt.Sprintf("%v", err), "assets/warning.png")
				log.Fatal(err)
			}

			if len(recvs[1]) == 4 && recvs[1][0] == 112 && recvs[1][1] == 105 && recvs[1][2] == 110 && recvs[1][3] == 103 {
				ttlSeconds = minTTLSeconds
				continue
			}

			payload, err := payload.UnmarshalPayload(recvs[1])
			beeep.Notify(payload.Subject, payload.Body, "assets/information.png")
		}
	}
}
```
私はSlackが嫌い

# 適当なまとめ

- 私はslackが嫌い[^1]という話とその理由
- どうしたらslackが嫌いじゃなくなるのかを教えてほしい[^2]

# なぜSlackが嫌いなのか

## 通知がバンバン来る

- ユーザーグループとかに入ってたりすると特に
- スレッド通知がオンになっていると，ユーザーグループメンション→関係ないのにスレ通知によるコンボで通知がガンガン飛ぶ
- 一旦スレッド通知をオフにして対処してるが，そうすると今度は見落としが発生する
    - そもそもスレッド通知がオフにできるということを知らない人もいる（私も知らなかったのでスレッドのときは明示的にメンション飛ばさないようにしていた）

## 優先度がわからない

- 内容を読まないと後回しにしていいのか今すぐリプライすべきなのかわからない
- その瞬間に一旦作業が止まる
    - 後回しでいいやつでも，すぐ返せそうなやつはその場で返すことも多いため，結局時間が取られる
    - 後回しにすることがそもそも脳内リソースを食うので・・・

## じゃあ見なきゃいいのか

- 緊急性が高いメンション等も飛んでくるため，一律に「見ない」というわけには行かない
- 見ない時間を作るのも一つの手だが，そうするとチーム全体で誰も見ない状況が発生する（可能性がある）

# Slackを好きになるためにどうすべきなのか

- パッと思いついたことをつらつら書きます

## 個人の問題として

- slackを見るときのルールを作る
    - 例えば時間帯を決めるとか
    - バンバンミュート！ミュートは正義
    - 全部に目を通そうとしない（個人的に気になっちゃう癖があるのはSNS病なのかもしれません・・・

## チームの問題として

- slackに対するルールというか共通見解をシェアしておく
- 優先度をつけるようにする
    - 緊急用チャンネルなどを明示的に作成し，このチャンネルだけは絶対落としてほしくないというのを作る
- 緊急度が**高くない**投稿に関するルールを明示的にする
    - 見落としを責められない心理的安全性
    - それ以外のチャンネルは極論全ミュートでも良いような状況を作れる

# 皆さんどうやってるんですか？

- ググってみたんですが，意外とslackのネガティブな話ってヒットしなかった
    - 検索能力が低いのかもしれない
- 「私は個人としてこういうふうにしてる」とか「うちのチームではこういうルールにしてる」とか教えてほしいです

[^1]: 誤解のないように書いておきますが，slackというツール自体が悪いという話ではないです。どんなツールも使い方次第では良い結果も悪い結果も生むと思うので（包丁もそうだよね），あくまで使い方に関するポエムだと捉えていただければ

[^2]: [Qiitaのガイドライン](https://help.qiita.com/ja/articles/qiita-community-guideline#%E2%98%9D-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E4%BB%A5%E5%A4%96%E3%81%AE%E5%86%85%E5%AE%B9%E3%81%AF%E6%8A%95%E7%A8%BF%E3%81%97%E3%81%AA%E3%81%84)にある「技術的な内容が記事の主目的である限り」というのに入るのだろうかという不安。ツールの使い方も広い意味では「技術」といえなくもないと思うんだけど，とはいえグレーだよなあという気もしていて・・・
ログインなしでもいいね機能を利用できるようにする

#目的
今回はログインなしでも閲覧者がいいね機能を利用できるように実装します。しかし、大きな注意点が1つあります。それはユーザーが無限回いいねを押せてしまうという点です。これでは正当な評価ができませんよね。ログイン機能があれば、それぞれのログインユーザーがそれぞれのツイートに対していいね1つのみ、という実装ができます。これに近い制限をかける必要性が出てきます。ここでは、例としてIPアドレスで制限する方法を実装します。

**※一通り投稿機能は実装できている前提で話します。上記のようないいね機能をゼロから作っていきます。**

※IPアドレスとは何か？については、以下のページをご覧ください。
https://qiita.com/MandoNarin/items/69f8e3e68ad834b62f6b

#概要
1. Likeモデル(テーブル)を作成する
2. アソシエーション
3. ルーティング
4. 投稿詳細ページ
5. likesコントローラー
6. エラー文
7. まとめ

#1. Likeモデルの作成
以下をターミナルで実行してください

```
rails g model like tweet:references
```
tweet:referenceのおかげで、like.rbにはすでに```belongs_to :tweet```の記述が、likesテーブルにはすでに```tweet_id```が入っています(migrationファイル中には明記されないので注意してください)。次にlikesのmigrationが作成されていると思うので、以下のようにipアドレスのカラム(string型)を追加してください。

```ruby
class CreateLikes < ActiveRecord::Migration[5.1]
  def change
    create_table :likes do |t|
      t.references :tweet, foreign_key: true
      t.string :ip 
      t.timestamps
    end
  end
end
```

この状態で```rails db:migrate```を実行してテーブルを作成しましょう。

#2. アソシエーション
tweet.rbに以下を追加しましょう

```models/tweet.rb
has_many :likes, dependent: :destroy
```

TweetとLikeの1対多の関係を実現しています。

**※参考**
関係データベースとは？
https://qiita.com/MandoNarin/items/7bd624801940c999d667

#3. ルーティング
ルーティングに以下を追加してください。

```config/routes.rb
  resources :tweets do
    resources :likes, only: [:create]
  end
```
それぞれの投稿のURLの中に、いいね機能を入れ子にしています。

#4. 投稿詳細ページ
以下のいいねボタンを任意の場所に置いてください。

```views/show.html.erb
<%= button_to 'いいね', tweet_likes_path(@tweet) %>
```
これにより、@tweetのレコード情報がlikesコントローラーのcreateアクション(後述)に送信されます。

#5. likesコントローラー
まず、likesコントローラーを作成しましょう。
ターミナル(コマンドプロンプト)にて以下を実行して下さい。

```
rails g controller likes
```
次に、likesコントローラーのcreateアクションを以下のように書いてください。

```controllers/likes_controller.rb
def create
  @tweet = Tweet.find(params[:tweet_id])
  @alreadylike = Like.find_by(ip: request.remote_ip, tweet_id: params[:tweet_id])
  if @alreadylike
     redirect_back(fallback_location: root_path)
     flash[:notice] = "すでにいいねしています"
  else
     @like = Like.create(tweet_id: params[:tweet_id], ip: request.remote_ip)
     redirect_back(fallback_location: root_path)
  end
end
```
まず、@tweetに投稿詳細ページのtweetレコードを代入します。また、@alreadylikeには、Likeのレコード中から、送信者のipアドレス(```request_remote.ip```)と、投稿詳細ページのtweet_idの組み合わせを持つものがあれば代入します。
@alreadylikeが存在すれば(そのipアドレスでそのtweetをすでにいいねしていれば)、ただ元のページに戻るだけ、存在しなければ(そのIPアドレスでそのtweetをいいねしていなければ)、新たにいいねを作成する、といった内容になっています。

#6. エラー文
上記において、```flash[:notice] = "すでにいいねしています"```という記述があるかと思います。これは、その名の通り、likeのcreateアクション実行後、すでにいいねしている場合にredirect先のページで表示されるものです。showページの任意の場所に以下のエラー文を追加しましょう。

```views/show.html.erb
<%= flash[:notice] %>
```
#7. まとめ
ここではIPアドレスでいいねを制限するという仕様を作りましたが、IPアドレスでは完全ではないです。しかし少なくとも、1人がその場で無限回いいねが押せてしまうのを防ぐことはできていると言えます。
**※ipアドレスはローカル環境(開発環境)では全てデフォルトの```::1```が取得されるので、注意してください。**
【Next.js】クライアントサイドでルーティングする正しいLinkコンポーネントの使い方

**注: Next9.5.3以降は必要なくなりました！！！hrefのみで正しくルーティングされます。**


Next.jsでのルーティングは`Link`コンポーネントで行うが、正しく使わないとクライアントサイドでルーティングが行われない。
もちろんDocに書いてあるのだが、先日までハマっていたので共有。

## 環境

- Nextjs 9.3.4

## 確認

ChromeやFirefoxの拡張機能、`React Developer Tools`を用いてコンポーネントのレンダリング状況を確認すると、クライアントサイドでルーティングされているかを確認できる。
以下は[自作ブログ](https://ragnar-blog.net/posts)での例。

- クライアントサイドルーティングが正しく行われていない場合。

コンポーネントがすべてアンマウントされ、再レンダリングされてしまっている。
![invalid_link.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508043/70419710-df52-0284-40a8-3baa1adf0672.gif)


- クライアントサイドルーティングが正しく行われている場合

共通部分のコンポーネントはアンマウントされず、ページコンポーネントだけがレンダリングされている。

![valid_link.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508043/ed22eeab-750f-7705-3f80-fce2b76b9773.gif)


## 正しいリンク

### aタグでの遷移

Linkコンポーネントで、aタグをラップする。
aタグにはhrefを指定しない。

Linkコンポーネントは実際にはレンダリングされないので、HTML上ではaタグのみになる。

```tsx
import Link from 'next/link';
import React from 'react';

export const anchorLink: React.FC = () => {
  return (
    <Link href="/">
      <a>To TOP</a>
    </Link>
  );
};
```

### 他タグでの遷移

buttonタグやimgタグでも同様だが、passHrefをtrueにしておく。
`passHref=true`のLinkコンポーネントは、直下のコンポーネントがonClickを受け取る場合、遷移アクションを渡す。

```tsx
import Link from 'next/link';
import React from 'react';

export const buttonLink: React.FC = () => {
  return (
    <Link href="/" passHref>
      <Button>To TOP</Button>
    </Link>
  );
};
```

### 動的URLでの遷移

**ここがハマりやすいポイント。**

Next.jsでは、`pages/post/[id].tsx`とすると、`/post/1`,`/post/2`のような動的ルーティングを行える。
このとき、正しくLinkコンポーネントにPropsを渡さないと、クライアントサイドでのルーティングは行えない。

`pages/post/[id].tsx`のページに遷移する場合、以下ではクライアントサイドでルーティングされない。

```tsx:☓
import Link from 'next/link';
import React from 'react';

export const dynamicLink: React.FC = () => {
  return (
    <Link href="/post/1">
      <a>To Post 1</a>
    </Link>
  );
};
```

以下が正しい例。
hrefには、pagesディレクトリ内の遷移先ファイルと同様に記述し、asで実際の値を渡す。
`pages/post/[postId].tsx`の場合、`href="/post/[postId]"`とする。

```tsx:○
import Link from 'next/link';
import React from 'react';

export const dynamicLink: React.FC = () => {
  return (
    <Link href="/post/[id]" as="/post/1">
      <a>To Post 1</a>
    </Link>
  );
};
```

一部の記事では、「LinkコンポーネントのasはブラウザのURLバーに表示するアドレスを変更できる」旨を記述されているため、
それだけの効果だと思いがちだが、それだけではないようだ。(それだけの効果だと思っていた。)

とりあえず公式Docは目を通しましょう。
Android StudioからNox Playerを利用してアプリケーションを起動する

ここに素晴らしい記事があるので、それをざっくり日本語訳。
https://www.bignox.com/blog/how-to-connect-android-studio-with-nox-app-player-for-android-development-and-debug/

1. NOXの右上の設定のボタン→「root起動」にチェック
2. Androidの「設定」→「タブレット情報」
3. 下のほうにある「ビルド番号」を５回以上クリック
4. Androidの「設定」→「開発者向けオプション」→「USBデバッグ」をオン
5. コマンドプロンプト立ち上げて、以下を入力。ディレクトリは人によって違うかもしれません。

```sh
cd C:\Program Files (x86)\Nox\bin
nox_adb.exe connect 127.0.0.1:62001
```

# 無事に起動できました。
motorora AOSP on Shana (minSdk(API 22))ってところがそうみたい。
実行ボタン（緑の▶）を押すと、NOXで起動してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447423/74dc2347-1270-0383-bbe9-aa6e649682c1.png)


<a href="https://www.amazon.co.jp/%E3%81%AF%E3%81%98%E3%82%81%E3%81%A6%E3%81%AEAndroid%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E7%AC%AC4%E7%89%88-%E9%87%91%E7%94%B0-%E6%B5%A9%E6%98%8E-ebook/dp/B07QW5MHNY/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=Android&qid=1587119707&s=digital-text&sr=1-7&linkCode=li2&tag=gokuseijo-22&linkId=51657b462c7ecf9e183f3ce3b8d5a3c9&language=ja_JP" target="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B07QW5MHNY&Format=_SL160_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=gokuseijo-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=gokuseijo-22&language=ja_JP&l=li2&o=9&a=B07QW5MHNY" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />