OmniAICreator/Qiita-1.07M huggingface dataset:
[Blender]辺の自由な箇所に点を追加する

#概要
サンプルとして平面の四角形を用意した。この一つの辺の自由な箇所に点を追加する
#本文
![スクリーンショット_(195).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/76520f2a-84c4-00e8-c94d-69fea7c0a17f.png)
・一つの辺を選択する
・右クリックで出てくるメニューから「細分化」を選ぶ
![スクリーンショット_(196).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/c22f92ae-77e1-d70f-767b-c7be429a61c0.png)
このままだと、辺の等分割された位置に点ができる。
![スクリーンショット_(197).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/b0c17252-8b48-55a2-a68f-151b1276b724.png)
・分割された点を選択する。
・「Ｇ」キーを2回押すと辺の上で好きな場所に移動できる。
t._1 は読みにくい... タプルの要素のアクセスの可読性を上げる方法 【Scala】

```scala
val t = (1, "Mike", 1000)
val name = t._2

println(name) // Mike
```
ここでの `t._2` のような要素のアクセスは読みにくい.
この程度のコード量なら問題ないかもしれないが, タプルの種類が増えたり, 要素が増えると読むのが辛くなるのでどうにかしたい.

## 要約
パターンマッチを駆使しよう.

## パターンマッチを使った代入で可読性を上げる
つまりこういうこと.

```scala
val t = (1, "Mike", 1000)
// val name = t._2
val (_, name, _) = t

println(name) // Mike
```
使わない部分はアンダースコアで捨てるとよい.

## タプルのシーケンスの場合
素直に書くとこうなるだろう.

```scala
val data = Seq((1, "Mike", 1000), (2, "Harvey", 1500), (3, "Louis", 2000))

data.foreach(t => println(t._2)) // Mike Harvey Louis
```
これをパターンマッチを使って読みやすくしてみる.

```scala
val data = Seq((1, "Mike", 1000), (2, "Harvey", 1500), (3, "Louis", 2000))

data.foreach { case (_, name, _) => println(name) } // Mike Harvey Louis
```
Pattern Matching Anonymous Function というものらしい. (たぶん)

もちろん for-yield の中でも以下のようにできる.

```scala
val data = Seq((1, "Mike", 1000), (2, "Harvey", 1500), (3, "Louis", 2000))

val names = for { (_, name, _) <- data } yield name // names: Seq[String] = List(Mike, Harvey, Louis)
```

## Slick での例
筆者は ORM の Slick を用いるときにこのテクニックをよく使う.

```scala
// Dramas, Episodes, Comments は slick-codegen で DB のスキーマから生成された TableQuery
val query = for {
  ((drama, episode), comment) <-
      Dramas
        .filter(_.title === "Suits")
        .join(Episodes)
        .join(Comments)
        .on {
          case ((drama, episode), comments) =>
            drama.id === episode.dramaId && episode.id === comments.episodeId
        }
        .sortBy { case ((_, episode), _) => episode.season }
} yield (drama, episode, character)
```
例えばソートするところは

```scala
.sortBy(_._1._2.season)
```
と同じだが, どちらが読みやすいかは明白だろう.

## 補足
### タプルが何かしらのまとまりならクラスを使う
そもそもそのタプルが「意味のあるかたまり」ならクラスでまとめておいた方がいい.

```scala
case class Character(id: Int, name: String, asset: Int)

val c = Character(1, "Mike", 1000)
println(c.name) // Mike

val data = Seq(Character(1, "Mike", 1000), Character(2, "Harvey", 1500), Character(3, "Louis", 2000))
data.foreach(c => println(c.name)) // Mike Harvey Louis
```


## 参考
- https://docs.scala-lang.org/ja/tour/tuples.html
CSSの新しいカラーシンタックス(カンマ無し)

現在よく利用されているCSSでの色を指定する構文には、それぞれ透明度有りと透明度無しの二種類が有りました。
<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="css,result" data-user="unotovive" data-slug-hash="dyYdbaW" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="CSS current color syntax">
  <span>See the Pen <a href="https://codepen.io/unotovive/pen/dyYdbaW">
  CSS current color syntax</a> by unotovive (<a href="https://codepen.io/unotovive">@unotovive</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

[W3CのCSS Color Module 4](https://www.w3.org/TR/css-color-4/)は現在WD(草案)になっていますが、その中で色指定の構文をシンプルにする仕様が検討されています。カンマがなくなって透明度が統合されおり、シンプルでインラインな書き方をすることが出来ます。

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="css,result" data-user="unotovive" data-slug-hash="jObZNjR" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="jObZNjR">
  <span>See the Pen <a href="https://codepen.io/unotovive/pen/jObZNjR">
  jObZNjR</a> by unotovive (<a href="https://codepen.io/unotovive">@unotovive</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

現在草案ですが、IE以外の多くのブラウザではすでに利用できるようになっています。（[サポート状況](https://caniuse.com/#feat=mdn-css_types_color_space_separated_functional_notation)）
IEのサポートが切れる環境ではより良い選択肢になるかもしれません。
（IEのサポートはPostCSSとかを通すことでなんとかなるみたいです）
（[Prettierとかも大丈夫そう](https://github.com/prettier/prettier/issues/8154)）
MySQLのレプリケーションを少しだけ深く掘ってみる

MySQLにはレプリケーションの仕組みが存在します。
ここではレプリケーションの方式やもう少し内部的な部分を見ていきたいと思います。

前回レプリケーションについて浅く理解するための記事を書いているので、「レプリケーション？」という方はよろしければ[前回の記事](https://qiita.com/nyankichikun/items/d3fd078e7c15f3de35c4)をご覧ください。

# タイミング
MySQLのレプリケーションによってスレーブ側にデータが転送されますよね。一般的にデータ同期のタイミングとして、「同期」、「非同期」という用語が用いられると思います。

MySQLではデータ転送のタイミングは**「完全同期」**、**「非同期」**、**「準同期」**のどれかになります。ですがこれらを組み合わせたレプリケーションを構築することが可能です。では順番に簡単にですがまとめていきたいと思います。

## 完全同期
マスターがトランザクションをコミットすると、**アプリケーションに応答を返す前にスレーブ側でもトランザクションをコミットする方式**です。

この方式だと**リアルタイムにスレーブ側に最新のデータが反映されている状態**となるため、**耐障害性**はあがります。ですが**トランザクションの完了が遅れる**ため**性能面で影響**が出てくると思われます。

このような処理の流れになるかと思います。(データの書き込みタイミングは間違っているかもしれません。。。)

1. アプリケーションからマスターにコミット
2. バイナリログおよびデータ(ストレージエンジン)に書き込む
3. バイナリログの内容をスレーブに転送
4. スレーブ側でリレーログの内容をデータ(ストレージエンジン)に書き込む
5. スレーブからマスターに応答
6. **マスターからアプリケーションに応答**

## 非同期
完全同期とは異なり、マスターがトランザクションをコミットすると、**スレーブへのデータ反映を待たずにアプリケーション側に応答を返す方式**です。

ここでいうデータ反映とは、スレーブへのバイナリログの転送～スレーブ側へのデータ反映を指しており、マスターは単にバイナリログにイベントを書き込むだけです。後はよしなにスレーブ側が要求することでデータの同期が行われていきます。

この方式ではアプリケーションへの応答時間が短いことがメリットと言えます。ですが、バイナリログの転送が完了していない状態でマスターに障害が発生した場合、「コミットは成功したがデータが存在しない」ことになります。そのためこの方式では**イベントがスレーブに必達することが保証されていない**ことが問題点として挙げられます。

このような流れになるかと思います。

1. アプリケーションからマスターにコミット
2. バイナリログとデータ(ストレージエンジン)に書き込む
3. **マスターからアプリケーションに応答**
4. バイナリログの内容をスレーブに転送
5. スレーブ側でリレーログの内容をデータ(ストレージエンジン)に反映


## 純同期
簡単にいうと完全同期と非同期の中間に位置し、**マスターはコミット後に少なくとも1台のスレーブがバイナリログを受け取るまで待機する方式**です。

この方式では**リレーログの内容反映まで待つ必要がなくなるため、完全同期と比べて応答速度が速く**なります。また**バイナリログの転送まで保証しているため、非同期と比べてデータの完全性も向上**しています。

メリットばかりに見えますよね？実はそうではありません。**バイナリログを転送したことは保証していますが、データに反映されたかは保証されていない**のです。そのためアプリケーション応答時に**まだデータの変更が行われていない可能性**があります。

1. アプリケーションからマスターにコミット
2. バイナリログに書き込む
3. バイナリログの内容をスレーブに転送
4. バイナリログの内容を受け取ったことをマスターに応答
5. データ(ストレージエンジン)に書き込む
6. マスターからアプリケーションに応答
7. スレーブ側でリレーログの内容をデータ(ストレージエンジン)に反映

このような流れになるかと思います。

# バイナリログの形式
マスターからスレーブに転送される際のバイナリログ形式は下記のいづれかになります。

- 変更後の行イメージを記録した「行ベース」(Row Based) -> 5.7以降のデフォルト
- 実行されたSQL文を記録した「文ベース」(Statement Based) -> 5.6までのデフォルト
- 上記の混在(Mixed)

Mixedは混在のためRowおよびStatementを見ていきたいと思います。

## 行イメージ(Row Based)
「行イメージ」は行イメージをバイナリログに記録(エンコード等が走る)し転送する仕様上、**「文ベース」と比較するとサーバ間で渡されるデータ量が大きく**なります。ですが、 **binlog_row_image=minimal**とすることで**主キーと変更された列のみを記録する**ようにできるため、転送するデータ量を抑えることができます。また**行イメージではSQLが実行されないのでスレーブ側でのトリガーを発生させることができない**のは注意点です。

## 文ベース(Statement Based)
「文ベース」ではSQLを実行する仕様上、利用する関数によってデータの不整合が起こりえます。影響がありそうな関数例として、UUID関数(サーバ固有のIDであるUUIDを取得)やSYSDATE(システム日付取得)などはマスターとスレーブで実行されるタイミングによって異なる値が返ってしまうため問題が発生し得るかもしれません。

# GTID
MySQL5.6から加わった機能の一つで、「Global Transaction IDentifier」と言い、**トランザクションを一意に識別するためのID**です。そのためバイナリログにもこのGTIDは記録されます。このことからレプリケーションでも活用されており、一度マスターで割り当てられたGTIDはスレーブに渡されても値は変わりません。

ここでGTIDを利用することでレプリケーションがどう変わったのかを見ていきたいと思います。

GTIDを利用していない場合のレプリケーションでは、スレーブでのレプリケーション開始時にマスターのバイナリログファイル名とバイナリログ内のどのポジションからレプリケーションを開始するかを明示的に指定する必要ありました。

ですが、GTIDを利用している場合のレプリケーションでは、スレーブが持っていないGTIDから自動的にレプリケーションを開始すべきトランザクションを見つけることができるようになります。

また下記のようなことも可能になりました。

- マスター障害時の昇格させる最新のスレーブの自動認識
- 複数台のレプリケーション環境でもトランザクションの追跡/比較が容易になる

便利なことだらけですね。

# まとめ
GTID凄くないですか？
クロックを用いた時間計測

クロックを用いた時間計測のライブラリを作りました。

# サポート対象

C言語規格

* C11

コンパイラ

* Clang
* GCC

OS

* Linux
* macOS

あとは知らん

# ロジック

1. Clang の時は `__builtin_readcyclecounter()` を用いる
2. GCC でかつ x86 アーキテクチャの時には，`__rdtsc()` を用いる
3. GCC でかつ Linux の時には，`timespec_get()` を用いる

あとは知らん

# ソースコード

```c:clockcycle.h
#ifndef CLOCKCYCLE_H
#define CLOCKCYCLE_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

#ifdef __clang__
static inline uint64_t now() {
	return __builtin_readcyclecounter();
}
#elif defined(__GNUC__)
#if defined(__i386__) || defined(__x86_64__) || defined(__amd64__)
#include <x86intrin.h>
static inline uint64_t now() {
	return __rdtsc();
}
#elif defined(__linux__)
#include <time.h>
static inline uint64_t now() {
	struct timespec ts = {0, 0};
	timespec_get(&ts, TIME_UTC);
	return (uint64_t)(ts.tv_sec) * 1000000000 + ts.tv_nsec;
}
#else
#error unsupported architecture
#endif
#endif

#ifdef __cplusplus
}
#endif // __cplusplus

#endif // CLOCKCYCLE_H
```

# おわりに

本当は ARM についても下記を参考にクロックを読み取る命令のコードに書き換えたい。

https://stackoverflow.com/questions/40454157/is-there-an-equivalent-instruction-to-rdtsc-in-arm/40455065
SQLのリファレンスってどこ？

昔データベーススペシャリスト試験を受けたときの疑問のメモ。

「SQLのリファレンスってあるの？」

と思って調べたことがありました。

どこにあるのか良く分からなかったので問い合わせたら公開されてました（恥）

>試験で使用するデータベース言語は，「JIS X 3005 規格群」に
準拠しております。
>
>なお、情報処理技術者試験で使用する情報処理用語、
>プログラム言語等に関する仕様等につきましては、
>以下のURLでご案内しておりますのでご確認ください。
>
>【「試験で使用する情報技術に関する用語・プログラム言語など」Ver 3.1】
　https://www.jitec.ipa.go.jp/1_13download/shiken_yougo_ver3_1.pdf


という訳で普段使ってるDBがこれに準拠してない人は注意しましょう。

例えばMS SQL Serverメインで使ってたら「今日の日付」の回答を間違えます

正解は```CURRENT_DATE```となる訳ですが、MS SQL Server成分多めだと```GETDATE()```としてしまいがち？

改めて調べてみると```GETDATE()```なMS SQL Serverは少数派でした。
（○ ＝ CURRENT_DATE）

|MS SQL Server |Oracle  |PostgreSQL | MySQL|
|---|---|---|---|
| × | ○ | ○ | ○ |

な感じ。
VSCodeでMarkdownの改行をする

# 普通に改行しただけでは改行として表示されない
Markdownの正式な記述方法は、
「半角スペースを2つ行末にいれると改行」らしく、VSCodeもそのようになっている。

Qiitaは改行で改行されるので、半角スペースいれなくても改行されるようにしたい。

# 解決方法
VSCodeの設定で以下を追加する

```
markdown.preview.breaks: true
```

# 手順
ファイル→基本設定→設定をクリック
![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230850/b51acc5c-913e-8537-0a24-9b89c5278d2e.jpeg)

右上の「…」マークからsetting.jsonを開くをクリック。
![002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230850/4f950a12-ec9e-5124-a404-493419f74557.jpeg)

マークダウンの項目から、以下をtrueに変える
![003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230850/78ec2c95-e6e0-3110-77df-3c1531d6db2a.jpeg)


```
"markdown.preview.breaks": false,
```

↓

```
"markdown.preview.breaks": true,
```

これで改行で改行されるようになります。
linuxのコマンドでバイナリを操作するときのTips

仕事でバイナリファイルを使うことが多くなってきて、毎回ググるのもいい加減めんどうになってきたのでQiitaにまとめようと思います。
他にいい方法を知っている方がいれば情報を共有してもらえると嬉しいです！

## 1. バイナリファイル表示方法
私がよく使っているやつです。

### xxdコマンド
```terminal:
$ xxd sample.bin 
00000000: 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f  ................
00000010: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f  ................
```

### odコマンド
* -tx2：2Byte単位で16進数を表示
* -z：ASCII文字表示

```terminal:
$ od -tx2z sample.bin # リトルエンディアン表示です
0000000 0100 0302 0504 0706 0908 0b0a 0d0c 0f0e  >................<
0000020 1110 1312 1514 1716 1918 1b1a 1d1c 1f1e  >................<
0000040
```

### （おまけ）hexdump for VSCode
データ量が多いバイナリファイルがあるときはVSCodeの拡張機能の「hexdump for VSCode」を使っています。
使用方法は、こちらの記事を参考にさせていただきました。

* [バイナリデータを読むのに便利な VSCode の拡張機能「hexdump for VSCode」の紹介](https://tarukosu.hatenablog.com/entry/2018/07/01/094120)

## 2. バイナリファイル作成方法
### echoコマンド + リダイレクトでバイナリファイルを作成
数Byteくらいのバイナリファイルを作成するときにおすすめです。

```terminal:
$ echo -en "\x00\x01\x02\x03" > sample.bin
```

### テキストファイルからバイナリファイルを作成
```terminal:
$ cat sample.txt # 例）1Byte単位
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
```

```terminal:
$ cat sample.txt # 例）2Byte単位
0001 0203 0405 0607 0809 0a0b 0c0d 0e0f
1011 1213 1415 1617 1819 1a1b 1c1d 1e1f
```

xxdコマンドの-r -pで空白と改行は無視されるので、1Byte単位、2Byte単位～（以下略）で区切ったテキストファイルに対応できます。ありがたや。

```terminal:
$ cat sample.txt | xxd -r -p > sample.bin
```

## 3. バイナリファイルからunsigned char配列形式に変換する方法
今回は16を指定しているので、16Byte単位で改行されています。もっと早く知りたかった…

```terminal:
$ xxd -i -c 16 sample.bin 
unsigned char sample_bin[] = {
  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
};
unsigned int sample_bin_len = 32;
```

## 4. バイナリファイル編集方法
ddコマンドの存在は知っていますが、目下vimばかり使っています。

### vim
1. vimを-bオプションをつけて開く
2. コマンドラインモードで「:%!xxd」→「バイナリ編集」→「:%!xxd -r」
3. vimを終了 

## 参考サイト
* [(Linux) ファイルのバイナリダンプとテキスト相互変換](https://netlog.jpn.org/r271-635/2020/01/linux_binary_dump.html)
* [【ワンライナー】バイナリファイルを手作業で作成する](https://qiita.com/chooyan_eng/items/ce1216c947d81d287582)
* [普通の Linux 環境で手軽にバイナリファイルを編集する (dd, vim)](https://qiita.com/albatross/items/a2e3c690875b321096d7)
【ClosedXML】セルに色を付けようとしたらものすごくパフォーマンスが悪くなった話

CSVファイルを読み込んでExcelを作りたい。
その時数値によってセルの色を変えたい。
との要望があり、久々にClosedXMLを触りました。

60*30 の区切られたセル範囲を8つ繰り返すものをサンプルとして渡されました。

#【案１】書式設定で色を付ける
数値はある範囲でのレベルを示すので、書式設定でカラースケールを使用するのが素直な方法かと思います。
しかしこの手法では数値範囲に対して3色しか振ることができない様です。



今回は3色以上の極を持つカラースケールが必要とのことでしたのでこの手段は使えません。

また、この手法を使った場合、色付けのセルが大量にあると描画に時間がかかります。
スクロールするたびにがくがく重くなってしまいちょっと使いものにならない印象。
どうも表示範囲が変わるたびにExcelで再描画処理が走る様です。

#【案２】セルの塗りつぶし色で色を付ける
セルの塗りつぶし色はOpenXMLではForegroundColorとBackGroundColorで色を指定すればOK
こちらの方法で生成したExcelはスクロールしてもスイスイ。

```C#
using (XLWorkbook book = new XLWorkbook(savePath, XLEventTracking.Disabled))
{
    IXLWorksheet sheet = book.AddWorksheet("sheetName");
    for (int i = 0; i < 50; i++)
    {
        for (int j = 0; j < 30; j++)
        {
            var color = XLColor.AliceBlue;
            var cell = sheet.Cell(i,j);
            cell.Style.Fill.SetBackgroundColor(color);
            cell.Style.Font.FontColor = color;
        }
    }

    book.Save();
}
```

#が、しかし生成に時間がかかる
なぜかSave時点でめちゃめちゃ時間がかかります。
色々と調べてみたところ、セルに色を付けるためには、概ね以下の手順が踏まれていました。

+ カラーテーブルに色を登録
+ その色で塗りつぶされたセルフォーマットを登録
+ 各セルにそのセルフォーマットのIDを指定


最初の時点では1024色使う可能性があり、実際に塗ってみたら500色位になっていました。
この色の登録とセルフォーマットの登録に大半の時間を費やされていました。


このことに気づいて、仕様を調整して64色まで減らしました。
そうするとSaveにかかる時間は大幅に短縮することができました。

##気付いたこと
セルの書式設定にある項目をいじると描画に時間がかかるようになります。
+ セルサイズに合わせて文字を縮小
+ 表示形式
などなど

上記に関連してセルフォーマットを大量に作る場合はSave時点でセル数に比例して（？？）時間がかかります。
またClosedXMLのインスタンスも大量に生成されとんでもなくメモリを消費します。
Python基礎(変数,型,演算子,if文,for文)

基本的な変数と型の使い方
変数に型宣言はなく、値が型を持っている

#1.変数と型
```
a = 10             # 整数型（int）
b = 10.123         # 浮動小数点型（float）
c = "Hello"        # 文字列型（str）
d = True           # 論理型（bool）
e = [1, 2, 3]      # リスト型（list）

print(a)
print(b)
print(c)
print(d)
print(e)
```
>[出力]
10
10.123
Hello
True
[1, 2, 3]



#2.リスト、タプル

***
リストは配列と同じ

```
a = [10, 9, 8, 7, 6]     # リストの作成

print(a[0])             # 1番目の要素を表示

a.append(5)             # 末尾に要素を追加する
print(a)

a[0] = 0                # 要素の入れ替え
print(a)
```
>[出力]
10
[10, 9, 8, 7, 6, 5]
[0, 9, 8, 7, 6, 5]

***
タプルもリストと同様に配列だが、要素の追加や削除、入れ替え等はできない

```
a = (5, 4, 3, 2, 1)     # タプルの作成
print(a)
print(a[2])    # 3番目の要素を取得

b = (1,)       #要素が1つだけのタプルは末尾に","が必要
print(b)
```



>[出力]

>(5, 4, 3, 2, 1)
3
(1,)

#3.演算子

```
算術演算子	+	足し算
-	引き算
*	かける
/	割る（小数）
//	割る（整数）
%	余り
**	べき乗
比較演算子	<	小さい
>	大きい
<=	以上
>=	以下
==	等しい
!=	等しくない
論理演算子	and	両者を満たす
or	どちらか片方を満たす
not	満たさない
```

#4.if文

```
a = 5
if a < 10:
    print(" a < 10")
elif a > 100:
    print(" a > 100 ")
```

> [出力]
> a < 10

#5.for文
ループの範囲をrangeやin演算子とともに用います

```
for a in [1, 100, 200]:    # リストを使ったループ
    print(a)
    
for a in range(3):      # rangeを使ったループ
    print(a)
```
>[出力]
1
100
200
0
1
2
gzip圧縮されたファイルのテキスト操作

# はじめに

ディスク容量をおさえるために、ログ・ファイルなどはローテートする際にgzip圧縮されることが多いです。そういったファイルの中身をみるのに、さっと見たいときは解凍するのが面倒です。gzip圧縮したままでやるための小技を整理しました。

# もとのファイル

```
$ cat sample.csv
1,sample1,06
2,sample2,07
3,sample3,08
4,sample4,09
5,sample5,10
6,sample6,11
7,sample7,12
8,sample8,13
9,sample9,14
10,sample10,15
11,sample11,16
12,sample12,17
13,sample13,18
14,sample14,19
15,sample15,20
```

# zcat

`zcat`を一度かませば、標準出力にでるので、awkなどをパイプすれば、たいがいのテキスト操作ができます。

```
$ zcat sample.csv.gz
1,sample1,06
2,sample2,07
3,sample3,08
4,sample4,09
5,sample5,10
6,sample6,11
7,sample7,12
8,sample8,13
9,sample9,14
10,sample10,15
11,sample11,16
12,sample12,17
13,sample13,18
14,sample14,19
15,sample15,20

``` 

# head

```
$ zcat sample.csv.gz | head
1,sample1,06
2,sample2,07
3,sample3,08
4,sample4,09
5,sample5,10
6,sample6,11
7,sample7,12
8,sample8,13
9,sample9,14
10,sample10,15

```

# tail

```
$ zcat sample.csv.gz | tail
6,sample6,11
7,sample7,12
8,sample8,13
9,sample9,14
10,sample10,15
11,sample11,16
12,sample12,17
13,sample13,18
14,sample14,19
15,sample15,20

```

# zless

```
$ zless sample.csv.gz
```

# zdiff

```
$ zdiff sample.csv.gz sample2.csv.gz
1,15c1,3
< 1,sample1,06
< 2,sample2,07
< 3,sample3,08
< 4,sample4,09
< 5,sample5,10
< 6,sample6,11
< 7,sample7,12
< 8,sample8,13
< 9,sample9,14
< 10,sample10,15
< 11,sample11,16
< 12,sample12,17
< 13,sample13,18
< 14,sample14,19
< 15,sample15,20
---
> 1,sample1,1
> 2,sample2,2
> 3,sample3,3

```

# zgrep

```
$ zgrep 'sample3' sample.csv.gz
3,sample3,08
```

# 補足

zcatなど、もとのコマンドにzをつけたものは、もとのコマンドのオプションがつかえます。

# 参考リンク

* https://www.atmarkit.co.jp/ait/articles/1810/18/news014.html
* https://qiita.com/tukiyo3/items/3a527c387ab8a63c92cb
* https://ksmzn.hatenablog.com/entry/2014/02/27/175743
* https://stackoverflow.com/questions/8151380/how-to-get-few-lines-from-a-gz-compressed-file-without-uncompressing
Swift 現在表示中のビューコントローラーを取得

ナビゲーションやタブがある場合でも現在表示中のビューコントローラーを取得したい場合の例

```swift

extension UIViewController {
    var currentTopViewController: UIViewController? {
        if let viewController = self as? UINavigationController {
            return viewController.topViewController?.currentTopViewController
        }
        if let viewController = self as? UITabBarController {
            return viewController.selectedViewController?.currentTopViewController
        }
        if let viewController = self.presentedViewController {
            return viewController.currentTopViewController
        }
        return self
    }
}

extension AppDelegate {
    static func getCurrentController() -> UIViewController? {
        if let rootViewController = UIApplication.shared.keyWindow?.rootViewController {
            var viewController: UIViewController = rootViewController

            while let presentedViewController = viewController.presentedViewController {
                viewController = presentedViewController
            }

            return viewController.currentTopViewController
        }
        return nil
    }
}
```
VirtualBox導入記録

<h2>動機

環境を立て続けに構築しなくてはならない事情があった。
それを機にVagrantとVirtualBoxの併用による環境の構築に興味を持ち、まずはVirtualBoxから導入することにした。

<h2>環境

OS: Windows 10 Enterprize
CPU: Intel Core i7-8700K
Memory: 32.0 GB

<h2>Oracle VM VirtualBox をダウンロード

落とした。私が落としたのはVirtualBox 6.1.6 for Windows。
https://www.oracle.com/virtualization/technologies/vm/downloads/virtualbox-downloads.html

<h2>インストーラー起動

起動直後からなかなかNextが表示されないのは何か検証しているから？内容を確認しながら、Nextを押していく。途中で「インストール中にネットワークが一度使えなくなりますよ！」という警告を受ける。また、Oracle製の何かのインストールについても警告を受けた（忘れた）。

<h2>とりあえず、終わり

カスタマイズは、これから。
【Rails5】CarrierWaveで「rails g uploader Image」ができないときの解決方法

##「rails g uploader Image」でエラー発生

```text:開発環境
ruby > 2.6.5
rails > 5.2.4.2
devise > 4.7.1
carrierwave > 2.1.0
```

`gem 'devise'`のプロフ画像アップロードのために
`gem 'carrierwave'`を設定中、
アップローダーを作成するコマンド`rails g uploader Image`でエラーが出ました。

```text:ターミナル
$ rails g uploader Image
Running via Spring preloader in process 65446
Could not find generator 'uploader'. Maybe you meant 'mailer', 'task' or 'helper'
Run `rails generate --help` for more options.
```

直訳するとこうなりますね
>
プロセス65446のSpringプリローダーを介して実行
ジェネレータ「アップローダー」が見つかりませんでした。多分あなたは「メーラー」、「タスク」または「ヘルパー」を意味しました
その他のオプションについては、'rails generate --help'を実行してください。


`uploader`が使えないということは、CarrierWave自体に問題があるのか、インストールが上手く行っていないのか…


##ググって原因を調査

数記事ヒットしましたが、すべて未解決でした。
[Rails 5, Carrierwave. Could not find generator 'uploader'](https://stackoverflow.com/questions/41000064/rails-5-carrierwave-could-not-find-generator-uploader)
[carrierwave をインストール後、rails g uploader Pictureで「Could not find generator 'uploader'」
](https://ja.stackoverflow.com/questions/43263/carrierwave-%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E5%BE%8C-rails-g-uploader-picture%E3%81%A7-could-not-find-generator-uploade)[rails g uploader～　エラー　対処法](https://teratail.com/questions/193368)

最新のCarrierWaveは不安定という話もあったので、バージョンを下げた。
→ダメ
諸々を再起動してから再インストールしてみたりインストール方法を変えてみたり。
→ダメ
「そもそもCarrierWaveよりActive Storageのほうが良い」という言葉に惑わされる
→そういう問題じゃない

万策尽きました…


##エラーの問題は「Carrierwave」ではなかった！

一呼吸置き、再度エラーに目を向けると

```text:ターミナル
Running via Spring preloader in process 65446
#以下略
```

こんなエラー出てたっけ？（出てました）
この文字列で調べたら一瞬で解決しました。


##「Spring Stop」で解決

`spring`経由で実行していたことが原因だったようです。
`$ spring stop`のコマンドで`spring`を経由せずにコマンドを実行したら行けました。

参考
[Running via Spring preloader in process. Could not find generator 'devise'の原因と解決策](https://qiita.com/peco4107/items/28ed6b445995c551d1d1)


```text:ターミナル
$ spring stop
Spring stopped.
```

あとは、例のコマンドを実行すれば完了です。

```text:ターミナル
$ rails g uploader Image
```


###そもそも「Spring」とは？

参考
[GitHub (rails/spring)](https://github.com/rails/spring)

ざっくり直訳すると
>
アプリケーションのプリローダーです。
アプリケーションをバックグラウンドで実行し続けることで開発をスピードアップし、テスト、rakeタスク、または移行を実行するたびにアプリケーションを起動する必要がなくなります。

つまり、コマンドをスムーズに動かすために裏で動いているプリローダーということのようです。

**便利な機能だけど、たまに悪さをするから、そのときは`spring stop`と解釈しました！**


##まとめ
エラーが出たらググれば良いというわけではないなと痛感しました。
エラー文をよく読んで、なにが問題と言っているのかを把握してググる必要がありますね。

そして`spring stop`の理解はかなり大きな産物でした！
COVID-19チャレンジ（フェーズ3）その3

#概要

signateのCOVID-19チャレンジ（フェーズ3）やってみた。
tensorflow.jsでfitしてみた。

#写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/043f0b48-7686-988f-3946-e36a1cf9c08d.png)

#サンプルコード


```

function predict(x) {
  return tf.tidy(() => {
    return tf.div(tf.exp(tf.mul(tf.mul(x.sub(a), x.sub(a)), tf.neg(b))), c)
  });
}
function loss(pred, label) {
  return tf.losses.meanSquaredError(pred, label).mean();
}
function train(xs, ys, numIterations) {
  for (let iter = 0; iter < numIterations; iter++) 
  {
    optimizer.minimize(() => {
      const pred = predict(xs);
      return loss(pred, ys);
    });
  }
}
const a = tf.variable(tf.scalar(Math.random() + 90));
const b = tf.variable(tf.scalar(Math.random() / 10));
const c = tf.variable(tf.scalar(Math.random() / 10));
const learningRate = 0.005;
const optimizer = tf.train.adamax(learningRate);
const numIterations = 300;
const yy =  [1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 3, 1, 6, 3, 3, 0, 0, 3, 2, 0, 0, 1, 0, 0, 2, 1, 4, 8, 12, 6, 7, 8, 10, 10, 15, 26, 12, 13, 11, 18, 25, 19, 9, 14, 18, 19, 36, 32, 56, 44, 33, 28, 59, 53, 56, 34, 63, 31, 17, 45, 41, 40, 54, 39, 47, 39, 71, 96, 94, 123, 201, 169, 94, 242, 267, 278, 354, 366, 360, 242, 360, 514, 573, 632, 719, 499, 294, 482, 548, 573, 555, 584, 374, 346, 391, 452, 436, 434, 368, 210, 172, 281, 223, 188, 266, 305, 201, 176, 121]
const buffer = tf.buffer([yy.length, 1]);
const buffer2 = tf.buffer([yy.length, 1]);
for (var i = 0; i < yy.length; i++) 
{
    var x = i; 
    var y = yy[i];
    buffer.set(x, i, 0);
    buffer2.set(y, i, 0);
}
const xs = buffer.toTensor();
const ys = buffer2.toTensor();
train(xs, ys, numIterations);
const aa = Number(a.dataSync());
const bb = Number(b.dataSync());
const cc = Number(c.dataSync());
var values = [];
var j = 0;
var out = document.getElementById('out');
for (var i = 0; i < 130; i++)
{
  if (i < yy.length)
  {
    j = i;
  }
  values.push({
    x: i, 
    y: yy[j],
    pred: Math.exp((i - aa) * (i - aa) * - bb) / cc
  });
  out.value += Math.floor(Math.exp((i - aa) * (i - aa) * - bb) / cc);
  out.value += ",";
}
const spec = {
  '$schema': 'https://vega.github.io/schema/vega-lite/v2.json',
  'width': 300,
  'height': 300,
  'data': {
    'values': values
  },
  'layer': [{
    'mark': 'point',
    'encoding': {
      'x': {
        'field': 'x', 
        'type': 'quantitative'
      },
      'y': {
        'field': 'y', 
        'type': 'quantitative'
      }
    }
  }, {
    'mark': 'line',
    'encoding': {
      'x': {
        'field': 'x', 
        'type': 'quantitative'
      },
      'y': {
        'field': 'pred', 
        'type': 'quantitative'
      },
      'color': {
        'value': 'tomato'
      }
    }
  }]
};
vegaEmbed('#vis', spec);

```

#成果物


https://embed.plnkr.co/plunk/2SSoXYro0EHlzdjs


以上。
Python実践100本ノック 第5章の決定木をgraphvizを用いて可視化してみた

# はじめに
「Python実践100本ノック」を用いて勉強しています。この本は実際の状況に近いデータを用いてデータ分析の勉強ができるので、本当にいい本だなぁと思っております（といっても実際はもっともっとひどいデータがたくさんあるのでしょうけれども…）。
そんな本書の第5章にて、scikit-learnで決定木を用いて分析を行う場面があります。そこでモデルを作成するのですが、木構造の可視化はgraphvizを用いて挑戦してみて〜ということなので、今回やってみました。

※ 初心者が投稿しておりますので、間違えている場合はご教授いただければ幸いです。

# 対象としている読者
- Python実践100本ノックを読んでいる方
- scikit-learnで決定木の可視化方法を探している方

# 対象箇所
Python実践100本ノック
　-> 第5章 顧客の退会を予測する10本ノック
　　-> ノック49：モデルの寄与している変数を確認しよう

# 私のPC環境
- macOS Catalina 10.15.3
- Python 3.7.7
- scikit-learn 0.22.2.post1
- Jupyter 1.0.0

# graphvizのインストール
まずはhomebrewを使って本体をインストールします。

~~~
brew install graphviz
~~~

さらにPython用のライブラリをpipを使ってインストールします（anacondaの方はcondaでできるみたいです）。

~~~python
pip install graphviz
~~~

# コード
※ p.127 のコードまで実施している前提で以下記載しています。

### 1. Jupyter notebook 上に表示する方法

といっても、以下のコードを追加するだけです。とっても簡単ですね。

~~~python
from sklearn import tree
import graphviz
dot_data = tree.export_graphviz(model, out_file=None)
graph = graphviz.Source(dot_data)
graph
~~~

<img width="1129" alt="スクリーンショット 2020-05-06 12.03.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227069/7ea44451-8181-0e71-c678-dee2a268f132.png">

### 2. ファイルを作成する方法

最後のコードをちょっと修正するだけで、pdfファイルを作成することができます。この例では「test.pdf」がカレントディレクトリに作成されます。

~~~python
from sklearn import tree
import graphviz
dot_data = tree.export_graphviz(model, out_file=None)
graph = graphviz.Source(dot_data)
graph.render('test')
~~~

![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227069/f0393907-bea9-4add-cae9-bcfe2affc5aa.png)

### 3. ターミナルを使ってファイルを作成する方法（おまけ）

sklearn.treeのexport_graphviz関数を用いてDOT言語形式の決定木ファイルを作成し、Jupyter notebook上でシステムコマンドを走らせています。

~~~python
from sklearn import tree
import graphviz
with open('test.dot', mode='w') as f:
    tree.export_graphviz(model, out_file=f)
!dot -T png test.dot -o test.png
~~~~
 

# 参考文献
こちらの記事は以下の情報を参考にして執筆しました。詳しい情報は以下を参照ください。
[1.10. Decision Trees（公式のドキュメントです）](https://scikit-learn.org/stable/modules/tree.html)
[sklearn.tree.export_graphviz（こちらも公式のドキュメントです）](https://scikit-learn.org/stable/modules/generated/sklearn.tree.export_graphviz.html)
[Python:scikit-learnで決定木（Decision Tree）を試してみる（参考にさせていただきました）](https://blog.amedama.jp/entry/2017/04/25/224406)
Octave メモ

#概要
ちょっとした数値シミュレーションをする必要が発生した。
何度も使うのなら Matlab を手配するんだが、多分単発。
というわけで Octave でやることに。
コマンドの個人的なメモ

#コマンドメモ
## 空行列を作る
```
data =[]
```

## ゼロ行列を作る
```
data =zeros(20,5)
```

## 行列からランダムな要素を出す
```
data = rand(10,4); %サンプルデータ作成（10行4列）
idx = randperm(10,2); %ランダムな行インデックスを作成
data_sub = data(idx,:); %2行分のランダムサンプリング
```

## ファイルからロード
``` sample.m
[X, Y] = meshgrid(-8:.5:8);
R = sqrt(X.^2 + Y.^2) + eps;
Z = sin(R) ./ R;
figure
mesh(X, Y, Z)
```

拡張子が*.m*のものをスクリプトファイルとして読み込む。このサンプルはgnuoplotを呼び出すので、ssh接続した先だと使えないので注意。

```
octave:1> pwd
ans = /home/shakapon
octave:2> ls ./sample.m
./sample.m
octave:3> sample
```

## コマンドラインからの入出力
```
octave:1> a=input("INPUT:a=");
INPUT a= 10 %← 10と入力
a =  10
octave:2> disp(a)
 10
```

単にaと変数と入力した場合とdisp関数を使った場合の違いは式となるかならないか、らしい。

## 条件分岐
```
if (COND)
    ...
elseif (COND)
    ...
else
    ...
end
```

## 繰り返し
```
for x = ベクトル
    ...
end
```

##演算記号一覧

|演算記号 |例 |概要|
|:--------|--------|-------|
|input |input(’n=’) |文字の入力|
|save |save(’ ファイル名’) A; |変数のバックアップ|
|clear |clear A |変数Ａの破壊（clear のみだと全ての変数の破壊）|
|load |load ’ ファイル名’ |修復|
|who |who |定義した変数の確認|
|fopen |a=fopen(’file.txt’,’w+’) |file.txt を w+として開く。|
|fclose |fclose(a) |ファイルを閉じる|
|fprintf |fprintf(txt ファイル,%f, 行列) |行列の出力変換を txt ファイルに出力|

## CPU時間
```
[total, user,system]=cputime();
```
実行中のセッションで使用されたCPUの時間
mod を用いた計算問題

#初めに

AtCoder で以下のような問題が出題された際に全く手が出なかった為、理論とその実装についてまとめてみる。

#### Multiple of 2019 ( AtCoder Beginner Contest 164; Problem D )

問題文
1 から 9 までの数字のみからなる文字列 S が与えられます。
次のような条件を満たす整数の組 (i,j) (1≤i≤j≤|S|) の総数を求めてください。

条件: S の i 文字目から j 文字目までを 10 進法の整数としてみると、この整数は 2019 の倍数である。

制約
1≤|S|≤200000
S は 1 から 9 までの数字のみからなる文字列


# 理論

愚直に for ループを何重にも重ねれば計算は可能であるが、AtCoder の場合は計算時間の上限を超えてしまう為に工夫が必要である。

この手の倍数を計算する問題（もしくは進数を考える問題も？）は mod の計算を上手く利用したアルゴリズムにより効率的なプログラムを書くことが出来る。

### mod の基本公式

```math
a \equiv b \pmod{ 2019 } \\
c \equiv d \pmod{ 2019 }
```

のとき

```math
a + c \equiv b + d \pmod{ 2019 } \\
a - c \equiv b - d \pmod{ 2019 } \\
a * c \equiv b * d \pmod{ 2019 }
```

が成立する。つまり mod の計算にも通常の四則演算における和・差・積の公式が適用できるということである。

因みに商については、以下のルールも成り立つ。

> $ab \equiv ac$ でかつ$a$と$p$が互いに素なら、$b \equiv c$


### 本問題への適用

与えられた文字列$S$が

```math
S = s_n s_{n-1} \dots s_2 s_1
```

であるとする。つまり問題とは逆で$i<j$とする設定で考えていく。問題における条件を満たす組$(i,j)$とは

```math
N_{ij} = 10^{i-j} s_i + 10^{i-j-1} s_{i+1} + \dots + 10 s_{j+1} + s_j
```

が2019の倍数であるもののことである。この条件の組$(i,j)$を数えることが求められている。
まず以下の$r_i$と$t_i$を定義する。

```math
t_i = 10^{i-1} \\
r_i = t_i s_i + t_{i-1} s_{i-1} + \dots + t_1 s_1
```

この$r_i$は以下のような書き方をすることも出来る。

```math
r_i = t_i s_i + r_{i-1}
```

このとき以下の式が成り立つ。
***
```math
r_{i} \equiv r_{j-1} \Rightarrow N_{ij} \equiv 0 \pmod{ 2019 } 
```
***
以下、この証明を示す。$r_i$と$N_{ij}$の間には次のような関係が成り立っている。

```math
r_{i} - r_{j-1} = N_{ij} * 10^{j-1} 
```

もし、$r_{i} \equiv r_{j-1}$である場合

```math
r_{i} - r_{j-1} = N_{ij} * 10^{j-1} \equiv 0 \pmod{ 2019 } 
```

となる為、

```math
N_{ij} \equiv 0 \pmod{ 2019 } 
```

または

```math
10^{j-1} \equiv 0 \pmod{ 2019 } 
```

が成立するはずである。しかし $10^{j-1} = 2^{j-1} * 5^{j-1}$ であるので、$2019$ と $10^{j-1}$ は明らかに互いに素であり、前者の $N_{ij} \equiv 0$ が成り立つことになる。


### アルゴリズム

```math
r_i \equiv R_i \pmod{ 2019 } \\
s_i \equiv S_i \pmod{ 2019 } \\
t_i \equiv T_i \pmod{ 2019 }
```

ただし、$R_i,S_i,T_i$ は余りを表しており $0 \le R_i,S_i,T_i \le 2018$ である。
これらの文字を用いると各 $r_i$ の余りは次のように連続的に計算できる。

```math
\begin{align}
 r_i &= t_i s_i + r_{i-1} \\
& \equiv T_i S_i + R_{i-1} = R_i \pmod{ 2019 } \\
\end{align}
```

この方法を用いて各 $r_i$ の2019に対する余りを計算し、余りが等しい $r_i$ の組み合わせを数え上げることで答えを計算することが出来る。




# 実装

上記のアルゴリズムを用いることで、for ループを重ねずに計算することが出来る。

```python3
s = input()

d = [ int( 0 ) ] * 2019
d[ 0 ] = int( 1 )
r = int( 0 )
t = int( 1 )

for si in reversed( s ):
#    print( si )

    r = int( si ) * t + r
    r = r % 2019

    t = t * 10
    t = t % 2019

    d[ r ] = d[ r ] + 1

ans = int( 0 )
for di in d:
    ans = ans + di * ( di - 1 ) // 2

print( ans )
```
ユドナリウム用にD&Dモンスターのキャラコマ作成した

#概要
D&D5版 SRDのモンスターデータについて、[ユドナリウムのキャラクターデータを自動生成した](https://direboar.github.io/githubpage-test/dist/#/udonarium)のでその覚書。
ほぼ自分向けのメモ。

コマは以下にあるよ。
https://direboar.github.io/githubpage-test/dist/#/udonarium

#この記事書いた人のバックグラウンド
- Javaばっかりやってきた
- 最近は検証用のソースを書くことが多く、ちょこちょこNode.jsで書くようにしていた（がそこまで文法詳しくない）

#使った技術
- Node.js
- TypeScript
- Google Apps Script

#TypeScript
[このへん](https://qiita.com/notakaos/items/3bbd2293e2ff286d9f49)見たりしながら導入してみた。以前仕事で少し使った程度だったがそんなに違和感なく使えた。nullに厳格だったりするあたりは最初ウザイなと思っていたが、慣れてくるとここにnullくる可能性あるのね、と気づくことができて良きってなった。

テストをjestでちょこっとだけ書いたんだけど、[この辺](https://qiita.com/mangano-ito/items/99dedf88d972e7e631b7#import-%E3%81%AE%E3%82%A8%E3%82%A4%E3%83%AA%E3%82%A2%E3%82%B9%E3%82%92%E6%8C%87%E5%AE%9A)参考にしたけどimportする際にエイリアスを設定する方法がうまくいかずハマった。
とりあえずエイリアス使わずにやってるんだがなんでだろこれ？

#XML解析
ユドナリウムはXML形式のファイルなので、XMLのパーサーが必要。また[入力データ](https://gist.github.com/tkfu/9819e4ac6d529e225e9fc58b358c3479)内にHTNLの断片が残っていて、これを解析するためにXMLのライブラリが必要。[libxmljs](https://github.com/libxmljs/libxmljs)が割と使いやすそうだったのでとりあえずこれを使った。

#翻訳APIの呼び出し
英文データの自動翻訳をしてみたかったので遊んでみた。DeepL翻訳はそこそこ課金がかかりそうだったので、[このへん](https://qiita.com/satto_sann/items/be4177360a0bc3691fdf)の記事を参考に、Google Apps Script経由でGoogle翻訳を呼び出して自動翻訳を行った。
これ結構いいね、個人用途で膨大ってわけじゃないデータ量だったら十分さばける。（今回だと１回の変換で、1000回以上は呼び出してそうだけど特に制限かからなかった。）遊びに使うには十分って感じか。

#ユドナリウムのコマに表示する画像ファイルの指定
imageIdentifierに、画像ファイルのSHA256ハッシュを指定するとよい模様。

```xml
<data name="image">
  <data name="imageIdentifier" type="image">5dee937f4839d5c922bdd51ca80502ea3355e1bb29f69b214e78b936bf45f290</data>
</data>
```
iOS 13.4.1でA-Frameのvr-modeでカメラが動かない問題の一時対処方法

**2020/12/08追記**
[A-Frame v1.1.0](https://github.com/aframevr/aframe/releases/tag/v1.1.0) がリリースされましたね。
最新のA-Frameであれば、こちらの対応は不要になります。

**2020/05/18追記**
CardboardVRDisplayに[こちらの修正](https://github.com/immersive-web/cardboard-vr-display/commit/de9678d8f077ceeddf9873bb81ee43b36e9d9651)が入りましたので、1.0.19を使用していれば動作するようになるかと思います。
A-Frameもこちらの[issue](https://github.com/aframevr/aframe/issues/4554)の中で変更されてるようですので、次のバージョンがリリースされればこちらの変更は不要になるかと思います。

# 概要

iOS 13.4.1でA-Frameのvr-modeにしたときに画面に映る映像が変わらない場合の一時対処方法です。
A-FrameというよりもCardboardVRDisplayを使用している場合はこちらが発生しているかと思います。
（A-Frameは[WebVR Polyfill](https://github.com/immersive-web/webvr-polyfill)から[CardboardVRDisplay](https://github.com/immersive-web/cardboard-vr-display/)を使用しています。）

# 再現環境

* iOS 13.4.1
* A-Frame v1.0.4（バージョンはそれほど関係ないかと思います）

# 対処方法

以下のような感じの実装を実行すると（とりあえず）動きます
[vrDisplay](https://github.com/aframevr/aframe/blob/master/src/utils/device.js)が初期化されたあと（a-sceneのrenderstartなど）で実行してください。
（CardboardVRDisplayを取得して、FusionSensorをいじっているだけですので、CardboardVRDisplayをそのまま使用している場合は少し置き換えれば動くかと思われます）
~~私のiPhone 11 Pro(13.4.1)だと動いてますが、動かなかったらすみませんmm~~

```javascript
// iOS 13.4.1の判定については色々とあると思いますので、省略です。
const vrDisplay = AFRAME.utils.device.getVRDisplay()
if (!vrDisplay || !vrDisplay.poseSensor_ || !vrDisplay.poseSensor_.fusionSensor) return
const fusionSensor = vrDisplay.poseSensor_.fusionSensor
fusionSensor.stop()
fusionSensor.isWithoutDeviceMotion = true
fusionSensor.start()
```

# 何が起こっているかのメモ的な何か

## なんで動かないの？

iOS 13.4.1のSafariで[DeviceMotionEvent.rotationRate](https://developer.mozilla.org/ja/docs/Web/API/DeviceMotionEvent/rotationRate)がnullで返ってくるため、CardboardVRDisplayの[FusionPoseSensor.prototype.updateDeviceMotion_](https://github.com/immersive-web/cardboard-vr-display/blob/master/src/sensor-fusion/fusion-pose-sensor.js#L193)で例外が発生していました。
（おそらく次のバージョンのiOS Safariではもとに戻っているかと思われます。https://bugs.webkit.org/show_bug.cgi?id=209831）

## なんでこんな書き方？

FusionPoseSensorのコンストラクタで[DeviceMotionを使用するかの判定](https://github.com/immersive-web/cardboard-vr-display/blob/master/src/sensor-fusion/fusion-pose-sensor.js#L47)が行われて、そのまま[start()](https://github.com/immersive-web/cardboard-vr-display/blob/master/src/sensor-fusion/fusion-pose-sensor.js#L296)でEventListenerが登録されますので、[stop()](https://github.com/immersive-web/cardboard-vr-display/blob/master/src/sensor-fusion/fusion-pose-sensor.js#L303)で削除して、手動でisWithoutDeviceMotionをtrueにして`start()`することで`deviceorientation`で姿勢制御されます。

## vr-modeではないときはなぜ動いているのか

A-Frameは`deviceorientation`を使用しているからです。

* https://github.com/aframevr/aframe/blob/master/src/components/look-controls.js#L57
* https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/DeviceOrientationControls.js
MH-Z19で二酸化炭素濃度を測る (PC/TeraTerm)

#概要
二酸化炭素を測ることが出来るMH-Z19を、組み込み前に動作試験したときの備忘録です。
コマンドとレスポンスで試験結果を確認したかったのでUARTによる取得を行っています。
これを応用することで、電子工作で確実なレスポンスを得られるため、プログラムが組みやすくなります。 (MH-Z19の電圧やパルス信号と比べれば)
私自身はESP32 (Arduino IDE)で実装出来ることを確認しています。

詳細な仕様については[公式のドキュメント](https://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf)をあわせてご覧ください。

#必要なもの
- MH-Z19(B)
- パソコン
- USB-UART変換アダプター
- TeraTerm

#手順
※ 事前にソフトウェアやドライバーのインストール、変換アダプターとセンサーの接続を行ってください。

センサーにはバイナリを送信する必要がありますが、TeraTermではそのまま送ることは出来ません。
マクロファイルを用意した上で、それを読み込むことで実行可能です。以下はマクロファイルのサンプルです。

```console:Command.ttl
/* Set binary display mode. */
setdebug 2

/* Send [Read CO2 concentration] command. */
send $FF$01$86$00$00$00$00$00$79
```

この実行が成功すると、コンソール上には以下のように表示されます。
なお、送信と受信の内容を確認するため、ローカルエコーを有効にしています。

```console:Response
FF 01 86 00 00 00 00 00 79 FF 86 02 C8 42 00 02 00 6C
```

このうち、前半の9バイトは送信したバイナリ、後半9バイトが受信したバイナリです。
受信バイナリの (3バイトめの値) * 256 + (4バイトめの値) で濃度が算出できるので、上記の例では 02(2) * 256 + C8(216) = 728[ppm]となります。

#余談
Python + PySerialでも良いかもしれません。
Python(Django)でwebサービスを作る(html表示編)


#注意
- pythonを使ったことがある人
- djangoを知らない、慣れてない人
- htmlをちょっとでも使える人
- windowsの人


#この記事で使う知識
以下の単語を初めて見る方は先に見てください。
[pip install django](https://www.sejuku.net/blog/50417#pip-2)
[cd　プロジェクト名](https://eng-entrance.com/windows-command-cd)
[django-admin startproject プロジェクト名、python manage.py startapp アプリ名、
python manage.py migrate、python manage.py runserver](https://qiita.com/okoppe8/items/7e3de8a4dd40b48debea)

#準備 
__コマンドプロンプト__でDjangoのインストール

```
pip install django
```





# プロジェクトの作成
Djangoでは、一つのアプリケーションをプロジェクトと呼び、一つのプロジェクトの配下にいくつか
ファイルで構成されています。

引き続き__コマンドプロンプト__で作っていきます。

最初にプロジェクトを作成します

```
django-admin startproject プロジェクト名
```
自分がアプリを作りたいフォルダにプロジェクトを作成するフォルダを作ります。

プロジェクトフォルダに移動します


```
cd　プロジェクト名
```


次にプロジェクトファイルの下にアプリを作ります

```
python manage.py startapp アプリ名
```

最後におまじないをします

```
python manage.py migrate
```
空のファイルを適用しているだけです。大事なのでやりましょう。


#フォルダの追加
🌙のマーク下に**templatesフォルダー**を作成してください。
これによりファイル構成以下になります。
沢山ありますが使うのは★と🌙マークの所だけです。

```
-- 🌙プロジェクトと同じ名前/
    -- プロジェクトと同じ名前/
        -- __init__.py
　　　　 -- asgi.py
        ★-- setting.py
        ★-- urls.py
        -- wsgi.py
　　 -- アプリと同じ名前/
    　　-- migrations
    　　-- __init__.py
    　　-- admin.py
    　　-- apps.py
    　　-- models.py
    　　-- tests.py
    　　★-- views.py
　　 ★-- templates/
        --htmlやcssやjs等
    -- manage.py
```

そして今作った**templatesフォルダー**に**htmlのファイル**を入れてください。



#設定



**setting.py**に変更を加えます

```python:setting.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'アプリと同じ名前',  # ここです
]

```
これによりDjango側が認識できるようになります。

次にその下にも変更を加えます

```python:setting.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates'),#ここ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

```

これでファイルの保管場所を指定します。


#urlsとviewsにプログラミング
**urls.py**に次の文を記入します。

```python:urls.py
from django.conf.urls import path
from django.contrib import admin

import アプリと同じ名前.views as view

urlpatterns = [
    path('admin/', admin.site.urls),#modelsのデータを確認できる
    path('好きなURLの名前/', view.クラス名, name='クラス名')  #ここで呼び出す
]
```
このコードで、入力されたURLに対応した**views.py**のクラスを持ってきます。


**views.py**に次の文を記入します。

```python:views.py
from django.shortcuts import render

def クラス名(self):#呼ばれる
    
    return render(self, '~.html(動かしたいhtmlファイル')#返り値でhtmlを返す

```
このコードで、**urls.py**からの連絡に応じたクラスが動きます。

#htmlを表示
まずは、プロジェクトフォルダに移動します

```
cd　プロジェクト名
```
サーバーを起動させます

```
python manage.py runserver
```
次に**http://127.0.0.1:8000/viewsの時のURL/**を検索エンジンに入力してください
これで完成です
#参考
https://qiita.com/okoppe8/items/7e3de8a4dd40b48debea
https://www.sejuku.net/blog/25952
NVIDIA Jetson Nano Dev Kit B01に TensorFlow をインストールする

## インストール手順
#### 1. HDF5 のインストール
```
$ sudo apt-get install libhdf5-serial-dev hdf5-tools
```
#### 2. pip のインストール
```
$ sudo apt-get install python3-pip
```
#### 3. その他パッケージのインストール

```
$ sudo apt-get install zlib1g-dev zip libjpeg8-dev libhdf5-dev 
```

```
$ sudo pip3 install -U numpy grpcio absl-py py-cpuinfo psutil portpicker grpcio six mock requests gast h5py astor termcolor
```

#### 4. TensorFlow のインストール
```
$ sudo pip3 install --pre --extra-index-url https://developer.download.nvidia.com/compute/redist/jp/v42 tensorflow-gpu
```

#### 5. インストールを確認
```
$ python3
Python 3.6.9 (default, Apr 18 2020, 01:56:04) 
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
>>> print(tf.__version__)
1.13.1
>>> quit()
```

上記で TensorFlow のインストールは完了です。

## TensorFlow チュートリアル・コードを動作させる
```
mkdir logs
gedit mnist.py
```
```python:mnist.py
import tensorflow as tf
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

log_filepath = "./logs/"
tb_cb = tf.keras.callbacks.TensorBoard(log_dir=log_filepath, histogram_freq=1)

model.fit(x_train, y_train, epochs=5, validation_data=(x_test, y_test), callbacks=[tb_cb])
model.evaluate(x_test, y_test)

model.save('mnist.hdf5')
```

TensorBoard起動

```
$ tensorboard --logdir=./logs
```
TensorBorad が起動したら Jetson Nano 上の Chromium ブラウザで localhost:6006 を開きます。

![i](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F384208%2Fe3456430-4cc5-6204-b169-d5a7281fc113.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&s=64ed99854a0a68a5eba30fac8a82e544)
![i2](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F384208%2F29576bc4-c873-5746-3b27-9d0fab89c134.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&w=1400&fit=max&s=70ce66c013b8f8e45d0fadb13652cfb6)

保存したモデルを [Netron ブラウザ・バージョン](https://lutzroeder.github.io/netron/) で確認

![Screenshot from 2020-05-06 13-23-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632066/f5ef59f2-b788-70ce-8261-ccf72fcf453a.png)

以上です。
apt installのトラブルシューティング

# 環境
Vagrant + Ubuntu 16.04.5 LTS

# はじめに
ntpdateをaptでインストールしようとした時に発生したエラーのトラブルシューティングです。

参考
https://kaworu.jpn.org/ubuntu/Ubuntu%E3%81%AE%E4%B8%8D%E8%A6%81%E3%81%AA%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B

# 手順
ntpdateをaptでインストールしてみた。

```
$ sudo apt install ntpdate
```

すると、このようなエラーが出てくる。

```
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:

  ・・・・（不要なパッケージがずらずら表示）

Use 'sudo apt autoremove' to remove them.
```

必要とされていないパッケージが存在していると、インストール時に、このようなメッセージが表示されるようです。不要なパッケージをいつまでも置いておくと、セキュリテイ的に良くないのと、ディスク容量を圧迫する事になるため、削除しなくてはいけません。削除する方法は、エラーメッセージをよく読むと書いてあります。

不要なパッケージが一括削除されます。

```
$ sudo apt autoremove
```

再度、インストールしてみる。

```
$ sudo apt install ntpdate
```

最初のエラーはなくなったが、他のエラーが出てくる。

```
The following NEW packages will be installed:
  ntpdate
0 upgraded, 1 newly installed, 0 to remove and 88 not upgraded.
Need to get 48.6 kB of archives.
After this operation, 173 kB of additional disk space will be used.
Err:1 http://security.ubuntu.com/ubuntu xenial-security/main amd64 ntpdate amd64 1:4.2.8p4+dfsg-3ubuntu5.9
  404  Not Found [IP: 91.189.88.152 80]
Err:1 http://security.ubuntu.com/ubuntu xenial-security/main amd64 ntpdate amd64 1:4.2.8p4+dfsg-3ubuntu5.9
  404  Not Found [IP: 91.189.88.152 80]
E: Failed to fetch http://security.ubuntu.com/ubuntu/pool/main/n/ntp/ntpdate_4.2.8p4+dfsg-3ubuntu5.9_amd64.deb  404  Not Found [IP: 91.189.88.152 80]

E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
```

**apt-get update**か、**apt-get --fix-missing**のどっちかを実行して下さいとある。どう違うのだろうか？

>
**apt-get update**
ローカル環境のインデックスファイルの更新を行う。
ローカル環境のインデックスファイルが、サーバ上のインデックスファイルより古い場合、インストールが上手くいかなくなるため、ローカル環境のインデックスファイルを最新にします。
>
**apt-get --fix-missing**
ローカル環境のインデックスファイルが、サーバ上のインデックスファイルより古くても、無視して最後まで処理を続けるようです。

恐らく、apt-get updateを選択した方が無難だと判断。

```
apt-get update
```

３度目の正直

```
$ sudo apt install ntpdate
```

上手くいったようです。

補足：エラーが出てきてても、ntpdateはインストールされていますとのメッセージが表示されていたが、実際はインストールされていませんでした。
Flutter+Android4.4(Kitkat)でクラッシュする件の対応策

# 現象

Android4.4(Kitkat)の端末にFlutterアプリをビルドしてインストールしたところ、splash後にクラッシュする。


# 環境など

|ツールなど|バージョンなど|
|:--|:--|
| MacBook Air Early2015|macOS Mojave 10.14.5|
|Android Studio |3.6.1|
|Java |1.8.0_131|
|Flutter|1.12.13+hotfix.5|
|Dart |2.7.0|
|Xcode |10.2|

# クラッシュログ

debug起動した際のクラッシュログです

```console
E/flutter (10422): [ERROR:flutter/shell/platform/android/platform_view_android_jni.cc(39)] java.lang.SecurityException: uid 10290 does not have android.permission.UPDATE_DEVICE_STATS.
E/flutter (10422): 	at android.os.Parcel.readException(Parcel.java:1474)
E/flutter (10422): 	at android.os.Parcel.readException(Parcel.java:1427)
E/flutter (10422): 	at android.app.ActivityManagerProxy.reportActivityFullyDrawn(ActivityManagerNative.java:4637)
E/flutter (10422): 	at android.app.Activity.reportFullyDrawn(Activity.java:1475)
```

# 原因

`ERROR:flutter/shell/platform/android/platform_view_android_jni.cc(39)] java.lang.SecurityException: uid 10290 does not have android.permission.UPDATE_DEVICE_STATS.`でググって直ぐに辿り着きました。

https://github.com/flutter/flutter/issues/47073

解決策はこちらにありました。
https://github.com/flutter/flutter/issues/46172

# 対応策

`MainActivity.kt`を開き、以下の記述を追加します。

```MainActivity.kt

import android.os.Build // 追加

class MainActivity : FlutterActivity() {

    ....

    // 追加
    override fun onFlutterUiDisplayed() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            reportFullyDrawn();
        }
    }
}
```

`import`も忘れずに。

ちなみに、`Lollipop`が**5.0**、APIレベル21です。
`Kitkat`は4.4で、APIレベル19です。

ちょうど、19未満は対応する予定無かったのに、MinSDKが16になっていたのでそれも変えておきました。

```app/build.gradle
android {
    compileSdkVersion 28

    ...

    defaultConfig {
        ..
        minSdkVersion 19
        targetSdkVersion 28
```

4.4以下に手持ちがが無いので・・・
4.0.1はなぜか後生大事に持ってますが^^;

# iOS版の最低OSバージョンの設定箇所
ところで、iOSの最低OSバージョンってどこで設定するのかな。
これも手持ちのiPadを最低にしておきたいな・・・
ということで調べました。

こちらが参考になりました。
https://teratail.com/questions/87725#reply-137103

- XcodeでRunnerプロジェクトを開き、[Runner]-右側の[General]タブをタップ
- **Deployment Info**にある[Deployment Target]が該当の箇所

私は手持ちのiPadが9.3.5なので、9.3にしました。(10に上げられないやつw)

そういえば、最新OSに対応してないといけないのって、どこでやるんだろう？

こちらによると、
https://qiita.com/OkamotoHaru/items/0f285e399ed3fc44ea99

Xcodeを最新版に上げないとダメ？ていうかそれだけでいいのかな？

ついにCatlinaに上げるときか・・・


(自宅待機)現場からは以上です。
gnuplotの演算記号<<

gnuplotで記号「$<<$」がどうやら

 $x<<n\to x\times 2^n$

という算術記号になっているようなので、忘備録用にメモ。

##テスト
```
gnuplot> x=10
gnuplot> n=5
gnuplot> print x<<n
320
```

適用できるのはint型限定の模様。
AWS SAA資格取得~EC2編~

この度AWS SAA試験を受けることを決意し試験対策に向けてのアウトプットをさせていただきます！
前日にUdemyの模擬試験を受けまして（11/65問中）解答率16%と逆にハイスコアを叩き出したため、
まずはそろぞれのリソースの概要を徒然とまとめていきます！

#EC2(Elastic Compute Cloud)概要
⇨数分で起動可能な1時間または秒単位で従量課金される仮想サーバー
サーバの削除・変更、マシンスッペックの変更も可能。
自身の環境に合わせて適切なインスタンスタイプを選択できる。
（t２,t3:汎用　c3,c4,c5:コンピューティング最適化）

###AMI(Amazon Machine Image)
⇨オペレーティングシステム、アプリケーションサーバ、アプリケーションなど
EC2の起動に必要な情報をまとめたもの。
パブリックで公開されているもの、自分で作成したもの２つがある。

#####パブリックAMI
ライセンスを含んでいるもの⇨RedHat,Windows
オープンソースのOS⇨Ubuntu,CentOS
などがある。自由に公開できるため作成元を必ず確認する必要がある。

#####自分で作成したAMI
一度自分で作成したAMIを複数展開したり、障害時に復元するためバックアップ用途で使用する。

※オートスケールで負荷状況に合わせてEC2を自動的に増やす際もAMIが元となる！

###インスタンスタイプ
下記の公式サイト参照。
一時的な高負荷があるアプリケーション、開発用途によってなど、CPU/メモリをバランス良く使用するためなど様々。
比較的新しい世代が大容量かつコストを抑えられる。
**ユースケースに合わせて最適なインスタンスを選びコスト最適化できるかが重要！！**

###EC2を利用できるデータセンター拠点###
世界中の20のリージョンにある61のアベイラビリティゾーン（AZ）で運用されている。
EC2は任意のリージョンまたはAZから起動できる。

※リージョン⇨データセンターが存在する独立した地域のこと。
※アベイラビリティゾーン⇨各リージョン位存在するデータセンター。EC2などを配置することで地理冗長化を行うことができる。


###EC2の通信とセキュリティ###
#####Keypair⇨EC2インスタンス上のOSに対する安全な認証を提供する機能
①キーペア作成
②インスタンス起動時に公開鍵をコピー
③公開鍵と秘密鍵が合致するとログイン可能

#####Security Group⇨EC2インスタンスへのトラフィックを制限するファイアウォール機能
・デフォルトでは全トラフィックが閉じられている。
・ルールをひとまとめにしたものをSecurity Groupという。
・必要な受信アクセスに対してアクセスルールを定義
 - プロトコル（TCP/UDP）
 - 宛先ポート
 - アクセス元IP/Security Group

#####ENI(Elastic Network Interfaces)⇨VPC上で実現する仮想ネットワークインターフェース
以下をENIに紐づけることで維持が可能※インスタンスによって割り当て可能な数は変わる
・Elastic IP
・Private IP
・MACアドレス
・セキュリティグループ
ENIは物理的な環境におけるNIC(Network Interface Card)のことと言われていて、
仮想的な環境のネットワーク設定の際に使われるのがENIである。


一旦ここまで！！
引き続きまとめていきます。
Udemyの英語字幕を日本語に翻訳

#はじめに
Udemyの英語字幕を日本語に翻訳する方法を２通り紹介します。

#①右クリックして日本語に変換

<img width="1080" alt="スクリーンショット 2020-05-06 12.05.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/608328/dfd9d513-bb72-95d3-0f34-449c023c1f34.png">
翻訳したいページで右クリックして日本語に変換をクリックします。
手順はこれだけです。

#②Googleの拡張機能で翻訳

もう一つの方法はGoogle翻訳を拡張機能として追加します。

https://chrome.google.com/webstore/detail/google-translate/aapbdbdomjkkjkaonfhkkikfgjllcleb?hl=ja

上記のchromeウェブストアのアドレスから追加します。
そうすると画面の右上にアイコンが追加されるので翻訳したいページで「このページを翻訳」をクリックします。


<img width="505" alt="スクリーンショット 2020-05-06 12.33.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/608328/d9aecf6c-3183-6eeb-b5a6-9d24a52c5e14.png">

#その他
字幕を下に表示する方法も載せておきます。
動画の字幕アイコンからビデオの下に表示を選択するだけです。
<img width="1079" alt="スクリーンショット 2020-05-06 12.52.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/608328/7e895ca8-eaca-cd99-0f3f-f5fa2d13b224.png">



#あとがき
①の方法の方が簡単なので、試してみてできなければ②を行えばいいと思います。
Udemyでは英語の動画が多く、クオリティも高いです。
日本語でないからと敬遠するのは勿体無いので、まずは導入としてこの方法をお試しください。