OmniAICreator/Qiita-1.07M huggingface dataset:
テストでのSQL実行後のパターン分け

# 概要

SQL実行で値を取得した時に、値がどうなっているかを条件に分岐処理をすることがあります。
その箇所のテストパターンを考えていると、ややこしくなったのであらためて整理したいと思います。

## 使用する「user_info」テーブル

| id | name | age | email_address |
|:--:|:----:|:---:|:-------------:|
| 1 | Asann  | 15 | ```A@A.com``` |
| 2 | Bsann  | 20 | ```B@B.com``` |
| 3 | Csann  | 25 | NULL          |


## テストパターン
４パターン考えられる。

### 1. SQL実行後ヒットし、値が存在している

```SQL:
select email_address from user_info where age = 15;
```
実行結果
| email_address |
|:-------------:|
| ```A@A.com``` |

1 row in set (0.00 sec)

1件は取得できている。


### 2. SQL実行後ヒットし、値が存在していない

```SQL:
select email_address from user_info where age = 25;
```

実行結果
| email_address |
|:-------------:|
|   NULL        |

1 row in set (0.00 sec)

1件は取得できているが、値はNULLであり存在していない。


### 3. SQL実行後ヒットしない(0件)

```SQL:
select email_address from user_info where age = 30;
```

実行結果
Empty set (0.00 sec)

該当するレコードが存在しない。

### 4. SQL実行途中でエラーが発生
例外処理で```catch```する。
Visual Studio デバッガ起動方法まとめ

Visual Studio にはデバッガという機能が搭載されています。
デバッガでは実行中のプログラムの流れを追っかけたり、変数の状態を監視したりできます。

![debugger](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/39ba719d-0726-9dab-01e5-554dba3a6565.png)

簡単なプログラムなら単純にF5を押すだけでいいのですが、少し複雑になると起動方法すらわからなくなったりします。
自分への備忘録も兼ねて、デバッガの起動方法をまとめます。

# .exe での起動方法
単純にデバッグありで開始するだけです。
F5を押すか、このボタンをクリックしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/511c312a-3850-10b0-10d9-3f45b24e43f7.png)

# .dll/.lib での起動方法
.dll/.lib は単体では起動できないため、.exeが必須です。
.exeのプロジェクトを一緒に開発しているかそうでないかで起動方法が変わります。

## .exeのプロジェクトが手元にある場合
利用側の.exe を起動するだけです。
.exe のプロジェクトを「スタートアッププロジェクト」に設定してF5を押しましょう。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/444bef0d-5232-b3cc-f67f-8ff93299b3bf.png)

## .exeのプロジェクトが手元にない場合
ほぼプラグインの.dll開発用です。というかこれ以外で起動方法に困ったことがない...
特に記載がない場合、C#(.NET 6.0)を前提にした設定手順です。

プロジェクトのプロパティからデバッグ → デバッグ起動プロファイルの編集
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/90d426d6-879e-9db7-cf2b-e0b74fbe0888.png)

~~邪魔でしかない~~プロファイルがあるので削除。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/f6350b2c-0d5f-4c6c-4ff0-13f624744ef2.png)

プロファイルを新規作成 → 実行可能ファイル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/c2504750-fb96-e5ee-a821-ed33e3b7ac1c.png)

実行したいプログラムのフルパスを入力する。
作業ディレクトリを入力する。
大抵のプログラムはpluginの検索とかでカレントディレクトリ(作業ディレクトリ)が自分自身がいるディレクトリであることを前提としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/8cef8abb-3ed0-09f7-3a4d-72d63f0e0c57.png)

C++の場合、ここで設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/cd98894a-ca19-4063-a4f0-b338878e7d43.png)

C#(.NET Framework)の場合、ここで設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/072829c0-469e-92a9-c3ed-74c06c7e6cb7.png)


プログラム起動するだけの場合は、以上の手順で完了です。
が、プラグインの開発中はプログラムを更新するたびに.dllのコピーをするのが手間になります。
そこでビルドイベントを設定することで.dllのコピーを自動化をします。

ビルド → イベント → ビルド後のイベントに、`xcopy /y /e /i "$(TargetDir)*.*" "<プラグインの置き場所>"`を入力する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/077edd2e-bc10-8743-7fec-2e2a3d9a4167.png)

C++の場合、ここで設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/1375ca6c-6ae4-de16-1855-760f2b3350e3.png)

C#(.NET Framework)の場合、ここで設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185663/d3a95d5a-7341-f768-46d9-6090562080cd.png)
POSIX

POSIXって何？
---
UNIXのAPIの標準の話・・・という程度には知っているものの、具体的にどういうものかっていうのを説明できる人は限られるのではないでしょうか？せっかくなので、少し調べてみましょう。

POSIX STANDARD
---
http://get.posixcertified.ieee.org/

POSIX STARNDARDはUNIXと同様にThe Open Groupによってメンテナンスされていて、しっかりと仕様が決められています。
よくある話として、LinuxはUNIXライクではあるがUNIXではないというのは、UNIXが定めている標準の仕様を一部満たしていないことに起因しています。なお、LinuxはPOSIXの認証を受けていないそうです。こちらの方がそんな話を書いていらっしゃったのでリンクを貼っておきます。
https://qiita.com/ko1nksm/items/c57892d82a669396c48d


What is POSIX ?
---
https://stackoverflow.com/questions/1780599/what-is-the-meaning-of-posix

主な部分、ファイルやディレクトリの記述方法、シェルでのプログラムのリターンコードや記述方法などを含め、どのような仕様を定めているか列挙されているので一度目を通して見ると良いと思います。
【Java初心者】PDFをA4サイズで自動印刷する

# 紙への印刷はビジネスではよく使う

今どきのアプリが行う出力は、画面への表示や、PDF出力などが中心ですが、ビジネスの現場では、まだメール送信や紙への印刷が多くなっています。

しかし、PDFをJavaプログラムから印刷すると、なぜかLetterサイズ(letter 8x11)となり、プリンター側で「そんなサイズの紙はないよ」エラーになってしまいました。

Acrobatなどで開いてから、「用紙に合わせてリサイズ」して印刷すれば、問題ないのですが、できれば、自動でプリンターに出せるようにしたい。

それを実現するために試行錯誤しました。PDFBoxライブラリー( https://pdfbox.apache.org/ )に依存しています。

```java
package pdfPrint;

import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.printing.PDFPageable;
import org.apache.pdfbox.printing.PDFPrintable;
import org.apache.pdfbox.printing.Scaling;

/**
 * メイン
 */
public class Main {
    public static void main(String[] args) {
         doPrint("印刷したい.pdf");
    }
    
    
    /**
     * PDFをA4縦で印刷する
     * @param filename ファイル名
     * @return 
     */
    static boolean doPrint(String filename) {
        try {
            PDDocument document = PDDocument.load(new File(filename));
            PrinterJob job = PrinterJob.getPrinterJob();
            job.setPageable(new PDFPageable(document));
            // プリンターを指定したい場合はここを有効化。デフォルトプリンターならばコメントアウトのままでいい
            // PrintService myPrintService = findPrintService("XXXXプリンター"); 
            // job.setPrintService(myPrintService);
            
            Paper paper = new Paper();
            paper.setSize(21.0 / 2.54 * 72, 29.7 / 2.54 * 72); // A4
            paper.setImageableArea(0, 0, 612, 792);
            PageFormat pageFormat = new PageFormat();
            pageFormat.setPaper(paper);
            Book book = new Book();
            book.append(new PDFPrintable(document, Scaling.SHRINK_TO_FIT), pageFormat, document.getNumberOfPages());
            job.setPageable(book);
            // if (job.printDialog()) { // プリンターダイアログを出す場合
            job.print();
            //}

            return true;
        } catch (PrinterException | IOException | NullPointerException e) {
            return false;
        }
    }

    /**
     * プリンター一覧を取得し 指定されたプリンターがあればサービスを返す
     * @param printerName プリンター名
     * @return 
     */
    static PrintService findPrintService(String printerName) {
        PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
        for (PrintService printService : printServices) {
            System.out.println(printService.getName().trim());
            if (printService.getName().trim().equals(printerName)) {
                return printService;
            }
        }
        return null;
    }
}
```

PDF生成のときだけでなく、印刷段階でも紙の設定が必要なようです。
FlaskのBlueprintを使ったひな形

# はじめに
大して難しい話ではないけれど、ちょっと時間が経つと忘れちゃうBlueprintのところ。
ひな形を作ってGitHubに置きました。自分用ですがよろしければどうぞ。↓

https://github.com/yo16/simple_flask_view

viewを使わないもっとシンプルなFlaskが欲しければこちら↓をどうぞ。Blueprint版↑は一応こちらをベースにしてます。（フォルダ構成から変えてるだけど）

https://github.com/yo16/simple_flask

以下は簡単な説明・備忘録。


# フォルダ構成
```
src/
  main.py
  app/
    __init__.py
    views/
      top_page.py
      second_page.py
    templates/
      top_page.html
      second_page.html
```
- `top_page.py`と`second_page.py`は、page"s"の方がいいかもしれません。後で説明しますがURL群です。
- `app/`の中に入れてるのは、`app/__init__.py`から`import .views.top_page`とかやってviewの関数を呼び出したくて、パッケージ化してるためです。


# viewの設定
```python:app/__init__.py
from .views.top_page import top_page_views
from .views.second_page import second_page_views

def create_app() -> Flask:
    app = Flask(__name__)
    
    # viewの設定
    # /
    app.register_blueprint(top_page_views, url_prefix='/')
    # /sec
    app.register_blueprint(second_page_views, url_prefix='/sec/<string:id1>')
    
    return app
```
- `app/views/以下`で定義した(これから定義する)viewを取り込んで、URL本体の後ろにくっつける文字列(`url_prefix`)を定義して、「そのURLが来たらこのviewへ行け！」と指定。
- `<string:id1>`とやってるのは、URLとして、http://～～/sec/123 とかあったら、123をid1という変数に入れて使って、という指定。(viewの定義②で改めて説明)


# viewの定義① top_page_views
```python:app/views/top_page.py
from flask import Blueprint, render_template, redirect, url_for

top_page_views = Blueprint('top_pv', __name__)

@top_page_views.route('/', methods=['GET'])
def top_page() -> str:
    """トップページ
    """
    return render_template(
        'top_page/top1.html'
    )

@top_page_views.route('/sample1', methods=['GET'])
def top_page_sample1() -> str:
    """トップへ飛ばすサンプル
    """
    return redirect(url_for('top_pv.top_page'))
```
- `top_page_views = Blueprint('top_pv', __name__)`でviewインスタンスを作って、各関数のところで `@top_page_views.route('/', methods=['GET'])`とやって、URLに対する処理を定義している。
    - viewを使わない場合は、`@app.route('/', methods=['GET'])`とやっていたところ。
- redirectは、`url_for('top_pv.top_page')`とやっている。viewの名前.関数名で、その関数へ飛ばす。
- Blueprintを説明するいろいろなサイトで、ここでいう`top_page_views`、`top_pv`、`top_page()`を同じ名前を使うことが多々あり、どこを指しているのかわからなって理解が深まらないので、あえて違う名前にしてある。

# viewの定義② second_page_views
```python:app/views/second_page.py
from flask import Blueprint, render_template

second_page_views = Blueprint('second_pv', __name__)

@second_page_views.route('/', methods=['GET'])
def second_page(id1:str=None) -> str:
    """secondページ
    """
    return render_template(
        'second_page/top2.html',
        id1=id1
    )
```
- `@second_page_views.route('/', methods=['GET'])`で、`/`に対する処理を定義している。`app/__init__.py`では`app.register_blueprint(second_page_views, url_prefix='/sec/<string:id1>')`と使用していた。組み合わされて、http://～～/sec/123 でアクセスした場合に、この処理が呼び出されることになる。
- 関数の引数のid1は、URLのsec/のあとに書いた123がid1として設定される。
    - 絶対パスとしては`/sec/`なんだけど、このファイルを書く際には`/`は相対パスみたいな感じで書ける。これは各viewの結合度を弱める作用があって、作業を分割できたり、パスの構成変更とかをしやすくなるメリットがある。


# おわりに
viewを使ったページのサンプルの説明でした。
URLが複雑になりそうだったら、Flaskの生の`@app.route`でなく、こちらを使った方が整理しやすいです。
MySQLのJSONのkeyに一致するオブジェクトのvalueを取得したい：EAV

# はじめに

カスタムフィールドみたいな、EAV（エンティティ、アトリビュート、バリュー）形式でデータを持っている JSON のキーでひっかけて、同階層にあるバリューの値を MySQL で取得したいケースがでて、ハマったので備忘録的に残します。

```JSONC
// JSON 型の値に保存されている Rascal の文字列を、`key` = 'name' を条件とした上で取得したい
{
    "fields": [
        {
            "key": "id",
            "value": "1"
        },
        {
            "key": "name",
            "value": "Rascal"
        },
        {
            "key": "category",
            "value": "raccoon"
        }
    ]
}
```

# 結論

これで取得できます。

```sql
SELECT
    JSON_UNQUOTE(
        JSON_EXTRACT(
            `custom_fields`.`custom_field`,
            REPLACE(
                JSON_UNQUOTE(
                    JSON_SEARCH(`custom_fields`.`custom_field`, 'one', 'name')
                ),
                'key',
                'value'
            )
        )
    ) AS 'Name'
FROM
    `custom_fields`
WHERE
    `custom_fields`.`id` = 1;
```

# 手順

Docker の MySQL コンテナで動作確認します。

1. MySQL コンテナの MySQL に入る

    ```bash
    docker pull mysql:8.0
    docker run --name db -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=study_mysql -d -p 3306:3306 mysql:8.0
    docker exec -it db bash
    # MySQL が起動する 20 秒くらい待ってから
    mysql -u root -proot
    ```

2. サンプルデータ作成

    ```sql
    use study_mysql;

    CREATE TABLE IF NOT EXISTS `custom_fields` (
        `id` MEDIUMINT NOT NULL AUTO_INCREMENT COMMENT 'ID',
        `custom_field` json DEFAULT NULL COMMENT 'custom field',
        PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

    INSERT IGNORE INTO `custom_fields` VALUE
        (NULL, '{"fields":[{"key":"id","value":"1"},{"key":"name","value":"Rascal"},{"key":"category","value":"raccoon"}]}');
    ```

3. 目的のコマンド実行（Rascal の文字列を、`key` = 'name' を条件として取得したい）

    ```sql
    SELECT
        -- ダブルクォート除外
        -- e.g. Rascal
        JSON_UNQUOTE(
            -- value カラムの値を取得する
            -- e.g. "Rascal"
            JSON_EXTRACT(
                `custom_fields`.`custom_field`,
                -- value キーの値を取得するため、 JSON パスを value へ置換
                -- e.g. $.fields[1].value
                REPLACE(
                    -- ダブルクォート除外
                    -- e.g. $.items[1].key
                    JSON_UNQUOTE(
                        -- custom_field カラムの値で、最初に name の値を持つ JSON パスを取得
                        -- e.g. "$.fields[1].key"
                        JSON_SEARCH(`custom_fields`.`custom_field`, 'one', 'name')
                    ),
                    'key',
                    'value'
                )
            )
        ) AS 'Name'
    FROM
        `custom_fields`
    WHERE
        `custom_fields`.`id` = 1;
    ```

4. 実行結果

    ```bash
    +--------+
    | Name   |
    +--------+
    | Rascal |
    +--------+
    1 row in set (0.00 sec)
    ```

5. コンテナ破棄（後片付け）

    ```bash
    exit
    exit
    docker stop db
    docker rm db
    ```

# おわりに

今回の SQL は、MySQL 5.7 の VARCHAR に JSON のシリアライズ文字列が入っていた場合でも、同様に取得することができることを確認できています。  
この記事が他のエンジニアの助けになれば幸いです。
hostsについて調べてみた

## 勉強前イメージ

ホストとIPアドレスを設定して名前解決させる

## 調査

### hosts とは

ホスト名とIPアドレスの対応付けを記載したファイルになります。
行単位で記載し、複数行書くことでいくつも書くことが出来ます。

centos7だとデフォルト以下のようになっています。
書き方は `[IPアドレス] [ホスト名] [エイリアス]` になります。

```
[root@localhost ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
```

例えば以下のようにエイリアス付きで記載すると、
`ssh username@sv2` でsshログインすることが可能です。

```
[root@localhost ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

192.168.156.122 local2 sv2
```

### hostsの歴史

元々今のインターネットの原型のARPAnetでは名前解決にHOSTS.TXTを使用していました。
その時のHOSTS.TXTは今とほとんどフォーマットは一緒でした。

APRAnet上のすべてのホストの情報が入ったHOSTS.TXTは管理され、あるサーバに置かれていました。
他のホストと通信するためにはそのサーバからHOSTS.TXTを取得して使用していました。
その時は数百台程度のホストだったのでファイル管理は可能でしたが、
どんどんインターネットが発達していくにつれてファイルも肥大化して事実上HOSTS.TXTでの名前解決が不可能になった経緯があります。

それを解決するためにDNSが誕生しました。
なのでhostsはDNSの前身であったといえます。

## 勉強後イメージ

hostsにエイリアスがあるのも知らなかったし、
DNSの前身であることも知らなかった

## 参考

- [DNSの歴史（第1回 「HOSTSファイルの崩壊」）](https://xtech.nikkei.com/it/members/ITPro/ITARTICLE/20010223/1/)
- [第1回インターネットの先駆け、ARPANETの始まり](https://www.nic.ad.jp/ja/newsletter/No66/0320.html)
- [hostsファイル（HOSTS.TXT）](https://jprs.jp/glossary/index.php?ID=0199)
EmacsのOrgで書いた記事をQiitaにコマンド一発で投稿する org-sync-qiita を作りました


# 概要

EmacsのOrgモードで作成した記事を、Qiitaに直接投稿するコマンドを作りました。

-   [ychubachi/org-sync-qiita: Orgで作成した記事を一瞬でEmacsからQiitaに投稿するコマンド](https://github.com/ychubachi/org-sync-qiita)

インストールすると、 `M-x org-sync-qiita-at-point` というコマンドが使えるようになります。記事はOrgモードで作成します。ヘッドラインにタイトル、それと本文を書きます<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>。公開したい記事のヘッドラインにカーソルを合わせ、コマンドを実行します。すると、サブツリー全体がQiitaに投稿されます。最初は限定公開で投稿されます。

なんなら `org-sync-qiita-at-point` をC-c 9 にでもバインドしてお使いください。


# このコマンドを作成した理由

Orgモードで作成した記事をQiitaに投稿するのであれば、 `qiita_org` という立派なコマンドが既にあります<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup>。

**1つのファイルで1つの記事** を書く場合、このコマンドがあれば十分です。

これに対し、 **1つのファイルに複数の記事** を書けるようにしたいと思いました。そのほうが、Orgモードの真価が発揮されると考えたためです。

そのため、Qiitaの記事のメタ情報（タグ等）をファイルのプロパティではなく、ヘッドラインに付けられたドローワーによるプロパティに格納するようにしました。

```org
* Qiita記事
** 記事のタイトル
:PROPERTIES:
:QIITA-ID: 684fxxxxxd6a9xxxxx3d
:QIITA-PRIVATE: true
:QIITA-TAGS: org
:QIITA-URL: https://qiita.com/ychubachi/private/684fxxxxxd6a9xxxxx3d
:END:

記事の本文です。

** 別な記事のタイトル
:PROPERTIES:
:QIITA-ID: bc8fxxxxx5959xxxxx15
:QIITA-PRIVATE: false
:QIITA-TAGS: emacs,org,qiita
:QIITA-URL: https://qiita.com/ychubachi/items/bc8fxxxxx5959xxxxx15
:END:

別な記事の本文です。

*** サブタイトル
・・・
```

このようにすることで、一つのOrgファイルにTODOやらメモやらQiitaの記事やらを混在させることもできるようになります。

また、Emacsから離れることなく、Emacsのコマンドで投稿できるようにしました。そのため、QiitaのAPIをEmacs lispで叩くためのプログラムを書くことにしました。

なお、このコマンドは ox-qmd に依存しています<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup>。作者さん、ありがとうございました。

不具合がございましたらGitHubのissueか、ここのコメントでお知らせください。


# おまけ

姉妹品 `org-sync-gtasks` もどうぞ。

-   [ychubachi/org-sync-gtasks: Synchronize Org TODO lists and Google Tasks](https://github.com/ychubachi/org-sync-gtasks/tree/main)


# Footnotes

<sup><a id="fn.1" href="#fnr.1">1</a></sup> 本文がカラだと投稿の際エラーになります。

<sup><a id="fn.2" href="#fnr.2">2</a></sup> [org-modeのテキストをqiitaに投稿するgemを作ってみた - Qiita](https://qiita.com/yamatoken/items/858692178d288c40714d)

<sup><a id="fn.3" href="#fnr.3">3</a></sup> [Org-modeからQiita準拠のMarkdownをexportするパッケージを作ってみました - Qiita](https://qiita.com/0x60df/items/3cde67967e3db30d9afe)
MarkdownのプレビューをOneNoteにコピペしたときのメモ

# はじめに

マークダウンでもメモを取ることも多い中、社内ではOneNoteでの情報共有が多い。マークダウンの情報がOneNoteに綺麗にコピーできる嬉しい。
OneNoteがマークダウンに対応してくれていればベスト。以前、OneNoteにマークダウンのアドオンを入れていたのですが、社用PCでは禁止されてしまいました。

そこで、別の手段を探すことにしました。

OneNoteではエディタでの書式が反映されます。エディタのプレビューの書式によってOneNoteにコピーしたときにきれいに表示できたりできなかったりするようです。今回は3つの環境のプレビューからOneNoteにコピーしてみました。
- VSCode
- Typora
- Chrome

個人的にはTyporaからコピーしたときの書式が一番好きです。ほかにもいいツールあれば記載します。


# VSCodeからコピーした場合
 VSCodeの画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/7542cbe9-3815-4fe5-42df-c19b0f790788.png)
OneNoteの画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/edef8e97-9b9e-99a1-57cf-e374c2a0952a.png)

# Typoraからコピーした場合
OneNoteの画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/3812495d-85ac-07b5-890d-b9cc7b195f0e.png)

# Chromeの場合
Chromeの画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/556ca637-a0f9-7f1e-b9d7-3a73bc65907d.png)
OneNoteの画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/cb989c44-49e8-e073-3a03-5183453eb1e9.png)

# おわりに
ほかによさげなツールがあれば更新するかもしれません。
OneNoteがMarkdownに対応してくれたらベストです。
エディタ毎のmermaid記法まとめ

# はじめに

## Mermaid記法とは？
テキストのみで手軽にきれいなダイアグラムを書くことができるツールです。

[【Mermaidの紹介】Qiitaでダイアグラム・チャートが簡単に書けるようになりました！](https://qiita.com/Qiita/items/c07f3262d8f3b25f06c9)
に紹介されているように、Qiitaでも使えるようになったそうです。

## この記事では

自分か使っているマークダウンエディタやメモアプリでのmermaidの使い方についてメモです。個人的によく使うツール、
- VSCode
- PyCharm
- Joplin
について記載しています。

# VSCode
プラグインで「Markdown Preview Mermaid Support」をインストールすれば使えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/2aa255e1-2f6f-7947-9692-fa89e6ece881.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/c94f859d-df50-e7c4-c6ec-f5b33721151f.png)

ガントチャートも表示されます。(そもそも背景色が黒くて見えづらいですが。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/0bc87b19-4953-77b1-4c1f-1db0b88f7c9d.png)

参考：[使ってみよう！VSCode+mermaid](https://www.agent-grow.com/self20percent/2020/03/05/%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86%EF%BC%81vscodemermaid/) 
ほかにもMarkdownをよく使う人は入れておいたほうがいいプラグインなど紹介されていました。

# Pycharm

>ダイアグラムのサポートを有効にする﻿
> 1. Ctrl+Alt+S を押して IDE 設定を開き、言語 & フレームワーク | Markdown を選択します。
> 1. Markdown 拡張機能で Mermaid または PlantUML のいずれかを有効にします。
> 1. IntelliJ IDEA が関連する拡張機能をダウンロードしたら、OK をクリックして変更を適用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/b577a916-5576-a10c-e0b0-2dc11f541e68.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/ea9d2b0f-4820-a23f-05e1-b849d88c9cd6.png)

sequenceDiagramが表示されませんでした。mermaidのバージョン違いに起因するようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/9c7369a5-cc04-cf89-3d73-3a6c6bd7960b.png)


ガントチャートはこのように見えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/259b8374-757f-9e17-0d27-08d7008c009a.png)

参考：[Markdown | IntelliJ IDEA](https://pleiades.io/help/idea/markdown.html)
Mermaidに限らずPyCharmのマークダウンについての説明はこのページに網羅されてます。
# Joplin

普段メモアプリとして使っているJoplinですが、こちらは特にプラグインのインストールなくMermaid記法が使えました。

スタイルのテーマを「暗い」にしていますが、図の背景が白くなってくれて見やすいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/93e7b17d-7f2e-d576-206b-5166f8c92747.png)

ガントチャートはこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/a7126cee-97a0-5318-47e5-3bf0571289f7.png)

個人的にマークダウンだけであればJoplinが一番使いやすいです。タグ付け、クラウド同期、GUIがほかのツールに比べて使いやすいです。Evernoteユーザーだったので、ノートやタグのつけ方が似ているのも好きな理由の一つです。

# 最後に

探り探りなので、他のツールに移行したら追記します。
アジャイル開発を始めるのにおすすめの書籍

これからアジャイル開発に取り組みたいと思っている方におすすめの本を下記の記事で紹介しています。

スクラムチームの組み方などわかりやすく解説している良書です！
https://barablog.org/recommendation-books4/
CapacitorとCreate React AppでiOSアプリを作り実機実行するまで

 CapacitorとCreate React AppでiOSアプリを作り実機実行するまでの手順。

## 環境

- MacBook Pro (16-inch 2019)
- macOS Monterey 12.3.1
- Xcode 13.3.1
- Node.js v14.17.1

## 手順
### 準備

まずcocoapodsをインストールする。

```sh
sudo gem install cocoapods
```

### プロジェクトの作成

```sh
npx create-react-app my-app --template typescript # TypeScriptを使うかどうかは好みで
cd my-app
npm install @capacitor/core
npm install @capacitor/cli --save-dev
npx cap init # アプリ名等をここで質問されるので決める。後から変更もできる
npm install @capacitor/ios
npx cap add ios
```

### 実行

```sh
npm run build # まずHTMLをビルドしておく

npx cap run ios # 実行。

# 上記で実行できない場合は、以下でワークスペースを開き、そこから実行を試みる。
open ios/App/App.xcworkspace
```

この手順を実行していると、Xcodeを開いた時にCommand Line Toolのインストールが始まることがあるが、それはインストールして、その後手順をやり直すとよい。

## 参考
- Installing Capacitor
    - https://capacitorjs.com/docs/v3/getting-started
- Capacitor iOS Documentation
    - https://capacitorjs.com/docs/ios
久しぶりにDockerを触った

## やりたいこと
M1 MacでDockerを使ってubuntu環境を作る

## やったこと
### その１
Docker Desktopを起動しておく

### その２
Docker Hubでubuntuを調べる
ヒット：https://hub.docker.com/_/ubuntu

### その３
上記のサイトに載っている`docker pull ubuntu` を実行

~~~
$ docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
185e8a4c1005: Pull complete
Digest: sha256:9101220a875cee98b016668342c489ff0674f247f6ca20dfc91b91c0f28581ae
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
~~~

### その４
コマンドを忘れたのでUIの方から`RUN`をクリック
![スクリーンショット 2022-04-20 23.03.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562718/a9ff3fd1-6548-f793-2534-93db8c5b05eb.png)

### その５
`CLI`の部分をクリック
![スクリーンショット 2022-04-20 23.05.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562718/1944d7e1-3c52-1a94-4a1f-5be497759afd.png)

### その６
ターミナルが立ち上がります（完成）
![スクリーンショット 2022-04-20 23.05.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562718/a1841b69-6050-ed34-201b-c649b7a641cf.png)


### ちなみに
~~~
❯❯ docker images
REPOSITORY          TAG       IMAGE ID       CREATED       SIZE
docker101tutorial   latest    6d9a0769931f   4 days ago    27.4MB
ubuntu              latest    b5e8d9885aa9   2 weeks ago   65.6MB
alpine/git          latest    77de14e38fc0   4 weeks ago   37.9MB
❯❯ docker run -it ubuntu
root@88e1ddb8ea5a:/# ls
bin  boot  dev  etc  home  lib  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var


❯❯ docker ps -a
CONTAINER ID   IMAGE           COMMAND                  CREATED          STATUS                          PORTS     NAMES
88e1ddb8ea5a   ubuntu          "bash"                   52 seconds ago   Exited (0) 6 seconds ago                  amazing_tharp
2e1daefb13d0   ubuntu          "bash"                   2 minutes ago    Exited (0) About a minute ago             happy_dewdney
51aeb4d2b23d   ubuntu:latest   "bash"                   7 minutes ago    Up About a minute                         vigorous_lalande
5d9e5aeb5ed5   alpine/git      "git clone https://g…"   4 days ago       Exited (0) 4 days ago                     repo

❯❯ docker stop 88e1ddb8ea5a 2e1daefb13d0 51aeb4d2b23d
88e1ddb8ea5a
2e1daefb13d0
51aeb4d2b23d

// ps は現在起動しているもののみ表示される
❯❯ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
~
~~~

参考
https://qiita.com/kooohei/items/0e788a2ce8c30f9dba53
【C#】指数表記文字列からの数値変換【1.0E-6】

# 結論

下記、ソースコードで変換可能です。

```C#:変換ソース
using System.Globalization;

var parseString = "1.0E-6";

//ここで変換しています。
decimal.TryParse(parseString, NumberStyles.AllowExponent | NumberStyles.Float, CultureInfo.InvariantCulture, out var output);

Console.Write(output);
```

# おわりに

電圧計のコマンドレスポンスが`指数表記`で返ってくるタイプだったので調べました。こんなに簡単に変換できるのは凄いなと。思った次第です。`CultureInfo`を使っているのでWindowsの設定が日本ではない場合に不具合が出る可能性があるかも...。

# 参考

http://bbs.wankuma.com/index.cgi?mode=al2&namber=85832&KLOG=147
TortoiseGitで「fatal: unsafe repository」なエラー

```shell
git.exe checkout master --
fatal: unsafe repository ('//wsl.localhost/Ubuntu/home/user1/my-project' is owned by someone else)
To add an exception for this directory, call:

git config --global --add safe.directory '%(prefix)///wsl.localhost/Ubuntu/home/user1/my-project'

gitは正常に終了しませんでした (終了コード 128) (281 ms @ 2022/04/20 22:30:48)
```

Gitを最新版にアップデートしたところ、TortoiseGitでコミットやブランチ切り替えをしようとすると`exit status 128`エラーが表示されて処理を停止するようになりました。

## 解決方法

https://qiita.com/LemonmanNo39/items/e92ed9e3b9c812238006
まず前提として、上記の記事に書いてあるように、wsl側のホームディレクトリ内にプロジェクトを配置しているということ。ホスト側のエディタで編集するためにDockerのマウント対象にしているような使い方です。wsl本来の使い方に沿っているので、それ自体は問題ないです。でもこの使い方をしている人が今回のエラーに悩まされます。

TottoiseGitとwslを使っているということは、**WindowsとwslそれぞれにGitがインストールされている**ということになります。TortoiseGitはWindows側のGit(git.exe)を使います。Windows側のGitでwsl側のGitリポジトリを操作しようとする。最新のGitでは、こういうことをするとエラーになります。

エラーメッセージに表示されているとおり、

```shell
git config --global --add safe.directory '%(prefix)///wsl.localhost/Ubuntu/home/user1/my-project'
```

上記をコピペで実行すれば解決です。ただし**wsl側で実行するとwsl側の.gitconfigを更新してしまうため解決しません。** Windows側で実行する必要があります。普通にPowerShellを開けば「Windows側」です。

これにより.gitconfigファイルに設定が追加されます。気になる人は開いて確認してみてください。

なんでこんなエラーが出るようになったのかというと、セキュリティ上の理由だそうです。

https://gigazine.net/news/20220414-git-security-vulnerability/
(2022-04-22追記)Gigazineに記事が出てた。Windowsとかに限った話ではなく、管理をしっかりやってる環境は影響を受けそうです。でも理屈を理解すると納得という感じです。エラーメッセージに書いてあるとおりにするだけで解決するので、メッセージが英語でも慌てずに読むこと。

## SourceTreeの場合は？

たぶんSourceTreeでも最新版をインストールした場合は同様の状態になると思います。SourceTreeのオプション設定を見たところ、SourceTreeをアップデートしても内蔵のGitはアップデートされないので、2020年4月以前からSourceTreeを使っている場合は影響を受けません。

## Visual Studio Codeの場合 (2022-04-22追記)

そういえばwsl領域内でvscodeのGit関連の機能が動作しなくなってたのを思い出した。さっき見たら解決してました。今回の設定変更のおかげだと思います。

## ChatGPTに聞いてみた (2024-02-14追記)
https://chat.openai.com/share/d4d018c1-c802-4db9-a304-4d5a13815776
当時ChatGPTがあればすぐ解決できた。
Excelの縦セル郵便番号データをカンマ区切り1行テキストにしてデータベースに登録

# やりたいこと
こんな感じのExcelデータを、
![スクリーンショット 2022-04-19 16.09.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1653133/1bef15e1-28cf-95b2-9631-acb88fd9c8e3.png)
ハイフンを抜いて1行カンマ区切りデータにしたい
![スクリーンショット 2022-04-19 16.10.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1653133/aeadaea2-b45a-8b4e-7a40-5522ea936e6a.png)

# データをコピペ
### Excelデータをコピー
![スクリーンショット 2022-04-19 16.12.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1653133/f8325812-530b-ce97-c54e-d2d29a4aa9da.png)
### VSCodeにペースト
```
900-0000
900-0001
900-0002
900-0003
900-0004
```

# VSCodeでデータ変換
### 置換でハイフンを抜く
VSCode＞編集＞置換
![スクリーンショット 2022-04-19 16.18.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1653133/a2a5d4fe-a888-2c5f-783e-10d1edbb8aca.png)
検索窓にハイフンをコピペ
「すべて置換」を実行
![スクリーンショット 2022-04-19 16.18.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1653133/a2c425f4-e601-8fc1-1818-8c2b6e3372fc.png)
```
9000000
9000001
9000002
9000003
9000004
```
### 1行化とカンマ追加
二行目文末にカーソルを配置
```
9000000
9000001|
9000002
9000003
9000004
```
Option + cmnd + ↓
最終行文末までマルチカーソル
```
9000000
9000001|
9000002|
9000003|
9000004|
```
←でカーソルを文頭に移動
```
9000000
|9000001
|9000002
|9000003
|9000004
```
Deleteすると1行になる
```
9000000|9000001|9000002|9000003|9000004
```
カーソルが点滅している間に「,」を1回入力
```
9000000,9000001,9000002,9000003,9000004
```
カンマ区切りの1行データが完成

***
# 参考記事
`https://qiita.com/NT90957869/items/d76329a12d00721c6e85`
FastAPIでホットリロードを有効にする方法(2パターン)

## 1. 起動オプションから指定

FastAPIでホットリロードを有効にする方法を調べると、大体こんな感じで起動オプションを設定する方法が出てきます。

~~~
$ uvicorn main:app --reload
~~~

## 2. uvicorn.run()で指定
コマンドラインからではなく、コード上でホットリロードを指定するには以下のように`reload=True`を追記します。

~~~ruby:main.py
if __name__ == '__main__':
    uvicorn.run("main:app", port=8000, reload=True)
~~~
ちなみにアクセスログの設定は`access_log=True/False`とすれば良いそうです。


そのまま立ち上げればOKです。
~~~
$ python main.py
~~~

`uvicorn`パスが通らない環境(windows)等ではこの方法が良いのではないでしょうか。

## 参考文献
https://www.uvicorn.org/settings/
https://zenn.dev/satto_sann/articles/b405ca8961d70fac99ff
NFCとFeliCaについて整理する

# NFCの概要

- 近距離無線通信とも訳される
- Near Field Communicationの略称
- 広義のRFIDの一種
- 機器を近づけ、かざすことで通信を行うことを特徴としている
- 通信速度が速く、故障率も低い
- 13.56MHzの周波数帯で動作する
- 既存の非接触ICカードの通信規格(FeliCaやMIFARE等)を国際的な規格として標準化し、統一する目的で策定された
    - ※ ソニーのFeliCaは日本を含むアジア圏、NPXセミコンダクターズ(旧フィリップスコンダクターズ)のMIFAREは欧米圏で普及している
- また、形状の自由を確保する目的もある

# NFCフォーラムとは

- NFCの関連規格の策定やNFCフォーラム認定プログラムによる認定、NFCの普及のための活動等を行う組織
- NPXセミコンダクターズとノキア、ソニーによって2004年に発足

# NFCの規格

- ECMA-340
    - 2002年12月にECMA Internationalによって標準化された規格
- ISO/IEC 18092(NFC IP-1)
    - 2003年に12月にISO/IEC合同委員会によって標準化された規格
    - IPはInterface Protocolを表している
    - ISO/IEC 14443 Type AやJIS X 6319-4(いずれも通信部分のみ)の規格が包含されている
- ISO/IEC 21481(NFC IP-2)
    - 2005年1月にISO/IEC合同委員会によって標準化された規格
    - ISO/IEC 14443 Type BとISO/IEC 15693に対応した

# 非接触ICカードの規格

- ISO/IEC 10536
    - 密着型(2mm程度)の通信が可能
- ISO/IEC 14443
    - 近接型(10cm程度)の通信が可能
    - Type A
        - MIFARE
        - NTTのICテレホンカードやtaspoにも採用されている
    - Type B
        - モトローラが開発を主導
        - マイナンバーカードや住民基本台帳カード、自動車運転免許証、在留カード、パスポートにも採用されている
- ISO/IEC 15693
    - 近傍型(70cm程度)の通信が可能
    - 入退室管理や物流管理用途に策定された
- ISO/IEC 18000
    - 遠隔型(70cm以上)の通信が可能
- JIS X 6319-4
    - FeliCa
    - EdyやFeliCaに採用されている

# NFCのType

- Typeでは通信規格の種類を示している
    - つまり変調方式や符号化方式、伝送速度等
- Type-A
    - ISO/IEC 14443 Type A
- Type-B
    - ISO/IEC 14443 Type B
- Type-F
    - JIS X 6319-4
- Type-V
    - ISO/IEC 15693

# NFCデバイスの種類

- NFCのデバイスは3種類存在している
- (狭義の)NFCデバイス(NFCフォーラムユニバーサルデバイス)
- NFCリーダー(NFCフォーラムリーダーデバイス)
- NFCタグ(NFCフォーラムタグデバイス)

# NFCのモード

- モードではNFCデバイスで提供できる機能について示している
- Reader/Writer
    - NFCデバイス/リーダーデバイスに必須の機能
    - NFCカード/タグの読み書き
- Peer-to-Peer
    - NFCデバイスに必須の機能(?)
    - NFCデバイス間のデータのやり取り
    - ハンドオーバー
        - 大容量のデータのやり取りを行う場合にペアリングと認証のみをNFCで行い、データの転送自体はより高速なBluetoothやWi-Fiで行う方式
- Card Emulation
    - 非接触型ICカードやNFCタグのエミュレート
    - NFCデバイスであってもFeliCaを使用できないスマホが存在するのは、FeliCaをエミュレート(Card Emulation)するには通信規格以外の部分も実装する必要があるため
    - FeliCaをエミュレートする場合はセキュアエレメント(SE)と呼ばれるICチップを別途積むか、HCE(Host-based Card Emulation)と呼ばれるソフトウェア的にCard Emulationを利用できる仕組みを実装する必要がある
- Wireless Charging
    - 1Wまでの電力供給

# NDEFのType

- NDEF(NFC Data Exchange Format)
    - つまり中身、データフォーマット
- Type-1
    - Topaz
- Type-2
    - MIFARE Ultralight
- Type-3
    - JIS X 6319-4
- Type-4
    - ISO/IEC14443 Type A
- Type-5
    - ISO/IEC 15693

# 参考

- https://www.infraexpert.com/study/wireless47.html
- https://www.sony.co.jp/Products/felica/NFC/
- https://xtech.nikkei.com/dm/article/FEATURE/20110420/191254/
SpringBootでRedisのクラスターに対応する

 # TL;DR
- Redisへのセッション情報はapplication.yml に `spring.session.store-type: redis`、`spring.redis.cluster.node: 接続先`を設定するのみ
- 上記のみの場合、クラスターのスケールアップ・スケールアウトに対応できない
- スケールアップ・スケールアウトに対応するためにはapplication.ymlに`spring.redis.lettuce.cluster.refresh.apaptive: true` の設定が必要

# 背景・モチベーション
EC2 複数台で稼働しているSpringBootアプリケーションのセッションを各EC2上のTomcatで管理している。
各ユーザのセッション保持はALBのスティッキーセッションをONにして維持している。
頻回のデプロイのタイミングで各EC2がALBから切り離されるため、デプロイごとに全ユーザのセッションが途切れてしまう。
セッションを個別KVS(Redis)化することでユーザの利便性向上を図る

# アーキテクト
※ あとで図を書く
- AWS上で稼働しているサービス
- いわゆる三層アプリケーション
- CDN → WAF → ALB → EC2 → DB
- apache httpd/Tomcat/SpringBoot

# KVSについて
AWS上で稼働しているので、Elasticache for Redisを採用。
DynamoDB/Elasticache for Memcachedもありだが、レスポンスなどを優先してRedisとした。バックアップも取れるし。
スケールアップ・スケールアウトを含めて、冗長化・可用性のためにクラスター構成。

:::note info
作成方法は[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AmazonElastiCache/latest/red-ug/set-up.html)を参照のこと
:::

# Redisにつないでみる
application.ymlに下記を設定するだけで、セッション情報をElasticache for Redisに移行可能。
```application.yml
spring
  session:
    store-type: redis
    redis:
      configure-action: none
  redis:
    cluster:
      nodes: xxxxxx.yyyyyy.clustercfg.apne1.cache.amazonaws.com:6379 # AWS構築したElasticache for Redis Clusterのエンドポイント。portは6379でよいはず
```

# 負荷を掛けてみる
検証のために高負荷を掛けてみる。特定ノードの負荷が上がり、一部ユーザがログインできない状況になる。
ここで、シャード追加。あれ？効果がない。。
ならば、インスタンスタイプを変更して、スケールアウト。あれ？あれれ？？？レスポンスが帰ってこない？？？？
画面真っ白？？
**アプリケーション完全接続不可..!!**
Tomcat再起動.. なんとかサービス復旧.. 検証環境でよかった..
シャード追加後、Tomcatで1/シャード数くらいの確率で下記Eceptionが発生していた。
`Caused by: io.lettuce.core.RedisException: java.io.IOException: `
インスタンスタイプ変更後は一切Redisに接続できていなかった。

# 解決方法
どうやら、最初の設定ではRedisクラスターへの接続は可能だが、シャード追加・インスタンスタイプ変更によるクラスター内部の構成変更時にエンドポイントの後ろの実際の接続先への再接続が行われない模様。
SpringSessionでRedis設定を行うとデフォルトでlettuceというクライアントが利用される。
lettuceではクラスターへのrefresh設定がデフォルトでOFFになっていた。
applicatin.ymlに下記設定を追加することによる、lettuceのrefresh設定が必要だった。
```application.yml
spring
  session:
    lettuce:
      cluster:
        refresh:
          adaptive: true
          period: 60s # 60sでとりあえずよさそう。要チューニング
```

# 現状
上記設定により、インスタンスタイプ変更、シャード追加、シャード削除を実施後もTomcat再起動なしでアプリケーション側でのエラー発生しなくなった。
現在、本番切換えに向けて追加の負荷試験中。
なりすましやPhishing対策としてのPlus Addressingのススメ

## Plus Addressingとは

日本語では「プラスアドレス」と言ったりするようです。
簡単に説明すると、メールアドレスの自分のローカルパートに「+好きな文字列」を追加しても、元のメールアドレスにメールが届くような仕組みです。

例えば、

```
hirano@example.jp
```
というメールアドレスを持っている場合、

```
hirano+hogehoge@example.jp
```
にメールを送っても、+以降が無視され、`hirano@example.jp`にメールが届きます。

gmailやM365などが、これに対応しています。

qmailがextension addressesという名前で「-」を使った同じ機能を前世紀から提供していますので、プロバイダによっては「+」ではない場合もあるかも知れません。

個人的には、かれこれ25年ほどこの技術を愛用しています。

## Phishing・なりすまし対策

さて、これがどうやってなりすまし対策に使えるのか。

当たり前ですが、自分のメールアドレスを誰にも教えなければ、誰からもメールが来ることはありません。Qiitaからメールが送られてくるのは、Qiitaの会員になるときに、自分のメールアドレスをQiitaに登録したからです。

そこで、Qiitaにメールアドレスを登録するときに、例えば、
```
hirano+qiita@example.jp
```
のように、登録先のサービス名や会社名を「+」の後に追加します。

これで、Qiitaからメールが届くときは、

```email
From: Qiita <なんたら@qiita.com>
To: hirano+qiita@example.jp
Subject: お知らせですよ
```

のように届きます。
フィルタリング機能か何かで、`+qiita`はQiitaフォルダに振り分けられるように設定しておけば、Qiitaからのメールは全てQiitaフォルダに溜まります。

では、なりすましの場合はどうでしょうか。

```email
From: 実は偽者 <なんたら@qiita.com>
To: hirano@example.jp
Subject: お知らせですよ
```

あるいは、

```email
From: 実は偽者 <なんたら@qiita.com>
To: hirano+foobar-shop@example.jp
Subject: お知らせですよ
```

のようになると思います。

このメールがなりすましかどうか。
Fromのドメインを見て、DNSを引いて、DMARCを調べて、SPFも調べて・・・気が遠くなります。

Plus Addressingを使った、この方法なら、Toを見れば一目瞭然です。
`+qiita`がToに入っていないので、Qiitaに登録したメールアドレスではありません。
つまり、Qiita以外のところから来たメールだとわかります。
自動的にフォルダに振り分けられるようにしていたのであれば、調べるまでもなく、見る機会さえないかも知れません。

もうひとつ、わかることがあります。
もし、`hirano+foobar-shop@example.jp` からQiitaを装ったメールが来たなら、foobar-shopはメールアドレスを漏洩させたのでしょう。
25年間もこの方式を使っていると、実際にいくつか見たことがあります。

## なりすましの人が+qiitaを付けてきたら?

ま、そこまでしてこないと思いますが、心配なら+以降は別に連番でも適当な文字列でも構いませんので、わかりにくいものにしておけばいいですね。
振り分けルールでQiitaに入るようにさえ書いておけばいいだけですね。

## まとめ

SPFやDKIM、DMARCをはじめとする、Fromドメインを中心とした送信ドメイン認証もすばらしいのですが、Plus Addressingを使用することで、もっとお手軽になりすましから身を守ることが出きます。
ぜひ、お試しください。
よく書くmetaのviewportについてざっくり読み解く【備忘録】

headのtitleタグ付近に書いている以下のコードがなんなのか改めてざっくり読み解いていく。
```
<meta name="viewport" content="width=device-width,initial-scale=1" />
```

## viewportとは

viewportとは表示領域のことで、ブラウザ上に仮想な画面をサイズを指定
スマートフォン等のPC以外のデバイスに対応するために設定が必要になる。

安直に上記のmetaを設定したもので挙動がどう変わるのか比較

### 例：viewport設定なし

![viewport01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130422/b4c37ba0-3d78-e52a-ce1e-172e6efdcac1.png)

### 例：viewport設定あり(`width=device-width,initial-scale=1`)

![viewport02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130422/f4f4b6ca-f8f0-251d-ade0-896b88e93b57.png)

PCでの表示は変わらないが、スマートフォンでの表示が全然異なる。  
このことからレスポンシブサイトを作る上で必要なことがわかりました！

## 本題： contentの中身を読み解く

### `width`
* 表示領域の幅を指定
* 今回の題材の`device-width`は、使っているデバイスの幅に合わせて設定が可能になります。
* 数値指定の場合、適切にしないとCSSのメディアクエリ設定が適切に動作しないため数値指定することがあまりないのかなと思う。

#### 例：width=375を指定(スマホサイズに合わせる)

![viewport03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130422/f6395684-60b9-2d34-db5d-da409528bc83.png)


### `initial-scale`
* ズーム倍率の初期を指定
* `width=device-width`を指定した場合、デフォルトで1になるため省略しても良さそう
* `maximum-scale`や`minimum-scale`で最大と最小の倍率を指定可能

### `user-scalable`(今回は不使用)
* ユーザー側のズームの操作の許可するかどうかの設定
    * iPhoneのピンチイン/アウトがこの操作にあたる

## 最後に

よく書いているけど、  
なぜこれを毎回書いているのかがざっくり理解できたのでとりあえずよしとする。

## 参考
* [HTML5/ページ全般/meta要素 表示領域を設定する - TAG index](https://www.tagindex.com/html5/page/meta_viewport.html)
* [viewportとは？設定方法やスマホで効かない原因など徹底解説！｜SEOラボ](https://seolaboratory.jp/48581/)
* [コピペで済ませていませんか？改めて学び直したい「Viewport」のすべて｜ferret](https://ferret-plus.com/6033)
海外のガチHTMLコーダーに阿部寛のホームページを見てもらった

(2022/4/28) フォローアップ記事となる、ジェイソンさんの記事の翻訳版を公開いたしました。
「[HTML3.2のどこが「間違って」いるのか、そしてそれを見た目重視のクラスで再現するのがおかしいわけ](https://qiita.com/NagayamaToshiaki/items/4f8fd7773545e4f4c009)」

先日投稿した「[「阿部寛のホームページ」はHTML界のシーラカンスである](https://qiita.com/NagayamaToshiaki/items/dd36acb2658220c04b94)」の続編として、MediumのHTML関連の記事でセマンティックではないHTML・CSS（特にTailwind CSS）に対し舌鋒鋭い批判をしていらっしゃるJason Knightさんに、[英語版の記事](https://medium.com/@toshiakinagayama1990/this-page-might-be-the-sword-of-damocles-for-the-web-ecd4f1e600a5)を[見ていただいた](https://deathshadow.medium.com/its-a-stunning-example-of-why-people-don-t-even-know-what-fast-is-f9b645d7cde9)。しっかりコードを分析されているようで恐縮である。忌憚・忖度の無いセカンドオピニオン的知見としてご覧いただければ幸いである。

(2022/4/22) 上司から会社の名前を載せて書いているのに、表現が過激すぎるのではないかとお達しがあったため、表現をマイルドにして、原文を削除した。大変申し訳ありませんでした。

(2022/4/21) なんと、実際にジェイソンさんがそれっぽい（コンテンツのコピーができないため）ページを作成された。Lighthouseの測定でもSEO以外が100点満点、Speed Indexが1.1秒という爆速ぶりである（海外サーバなのでさすがにロード時間で本家に劣ってしまうが）。ちなみに本家はコードが古すぎたからかパフォーマンスを計れなかった。**なんということでしょう！**　（本当は、こういうのも自分でやらなきゃなと思うんだけど、よわよわデベロッパーだから…）

https://cutcodedown.com/for_others/medium_articles/html3Horrors/rewrite/

ソース一式は[こちら](https://cutcodedown.com/for_others/medium_articles/html3Horrors/rewrite.rar)からどうぞ。

## 以下ジェイソンさんのコメント

みんなが「速い」というのがどういうことか分かっていない、驚くべき例だね。`frameset`を使うと最初のロード時にキャッシュが空で、両方のフレームをフルのハンドシェイクでロードしなくてはならないから3回ハンドシェイクをする必要があるから遅くなるんだよね。これが単一ページとスタイルシートだと2回で済むんだ。

メニューサイドバー自体が全体のホームページメニューのマークアップよりもでかくなるし、コンテンツもそうだよね。ざっと見てこのHTMLは2.5k(B)くらいが妥当だと思うけど、3つのファイルで計7.12kになってる。

正直このサイトのシンプルさから見て、CSSも5kくらいで済むと思うんだよね。

サブページの短所として、膨れ上がって遅くなってしまっている。特にフレームのオーバーヘッドとテーブルが組み合わさっているところがね。もし単一のスタイルシートとマークアップを1/3にすれば、サブページの見た目をキャッシュできてページもさらに速くなるよ。

例えば次のコードを短くしてみよう。

``` html
<table border="0" width="142">
  <tr> 
    <td width="15"> </td>
    <td width="10"> </td>
    <td width="148"> </td>
  </tr>
  <tr> 
    <td width="15"> </td>
    <td width="10"><font color="#FFCCCC">?</font></td>
    <td width="148"> 
      <p><a href="top.htm" target="right">???</a></p>
    </td>
  </tr>
```

``` html
<nav id="mainMenu">
  <ul>
    <li><a href="./">Top</a></li>
```

もうこれで速くなるのは火を見るより明らかだよね。このページが早い唯一の理由は内容が軽量だからだ。それに見合う帯域幅の倍を食っているし、50%は余計なハンドシェイクとサーバーリクエストを要求しちゃってる。

まだユーザビリティとアクセシビリティに対して**NOと言っている**ことは話してなかったよね。

これの代替品を作る記事も書いてみていいかもな。表示中心のマークアップの悪い点を凝縮したようなものだから。「コピーは禁じます」とページにあるから偽のコンテントを作らなきゃならないけど、頑張って順守してみる…可能な限り。

ブラウザサポートに関してはやらない理由が無い。絵的なユーザーエージェント、つまりブラウザはマークアップを気にする必要が無く、ブロック化インラインレベルのタグかどうかだけが重要だ。機能を維持するのはコードや処理のオーバヘッドにとって大きな問題じゃない。だって386を積んだWindows3.1でも動いたわけだし。

でもレガシー機能は新しい`doctype`を書いたらブロックすべきだと思う。だからWHATWGがバージョン表記をやめて「現行ドキュメント」という方式をとったのは残念な判断だ。

2年前に「HTML5」で書いた正しいコードが今不正かもしれないのに、HTML5の「バージョン」が分からない中で今日正しいのが明日だめになってしまうかもしれない？　冗談きついよ。

ユーザーエージェントが「ダメ」と言って、開発者に修正してもらえるように止まるのじゃなくて「検証サービス」が必要なのが馬鹿げているようなものだ。この「問題が無いかのように馬鹿正直な」パーサー動作はひどいと言わざるを得ない。

でもそんな動作になったら80%以上のWebページが壊れてしまうのも確かだ。フレームワークや出来合いのブログプラグインが`<body>`内に`<style>`を入れたりしたらうまくいかなくなるしね。
GitHubにログインできなくなった話【２段認証コード、リカバリーコード紛失】


# 自己紹介
Qiita初投稿なので、軽く経歴を話すと
文系出身で新卒でSES企業に入社し、現在エンジニア4年目になります。
最近は個人のタスクにも余裕ができ、少し成長したかなと実感してます。（とはいってもまだまだ未熟ですが、、）


# 現場から帰還
早速、本題に移りますね。
我が社は客先常駐と請負開発、社内案件などいくつか選択肢がありまして、客先から退場してから次の案件にアサインされるまでの期間は社内ツールの開発をする事が多いです。

とある日のこと、、

私は客先から退場し、次の案件まで社内開発に携わることになりました。その際に今回の事件に遭遇することになりました...

# GitHubにログインできなくなった
以前も社内開発に携わっていたので会社用のメールアドレスでGitHubアカウントは作成済みでした。
今回もGitHubにログインして、早速ソースの確認でもしようかと思っていた矢先、
メールアドレスとパスワードを入力してサインインのボタンを押したら2段階認証コードを入力して下さいと、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1212134/182ce7e5-cbc1-1bc5-1635-f0e81964d42f.png)



前に社内案件に入った時はブラウザ用のAuthenticatorを入れていた記憶が蘇り、そのPCは現場に配属される前にデータ削除して会社に返却しました。

つまりこの段階で2段階認証コードを確認できる手段は
無くなった訳です。**オワタ！**


色々調べているうちに、この方の記事にたどり着きました。
[ヒャッハー！Githubから締め出しくらったぜぇ！](https://zafiel.wingall.com/archives/9732)

どうやらリカバリーコードなるものがあり、それを緊急用パスワードとしてしようできるそう。。
もちろん保存してません。:relaxed:


# GitHubサポートセンターに連絡
https://support.github.com/request

どうあがいても無理そうなので、
サポートセンターにメールすることにしました


**私**：二段階認証のプロセスが突破できないので、GitHubアカウントを削除してもらえませんか？

**サポート**：もう一度github-recovery-codes.txtファイルを探してみてください。
とはいっても、見つからないのであればメールアドレス＆ユーザ名の解放もしくはアカウントの削除はできます。アカウントの削除はセキュリティの観点から数週間お時間かかります。どちらをお望みですか？

**私**：github-recovery-codes.txtファイル探したけど、見つかりませんでした。
できるだけ早い方が助かるので「メールアドレス＆ユーザ名の解放」をお願いします。

**サポート**：メールアドレス＆ユーザ名の解放をしました。これで同ユーザ名で再登録できるようになったので、確認してみてください。

**私**：ご対応ありがとうございました！！助かりました！！


解放まで約３日かかりましたが、再登録できました:clap:

# 今後このような失敗をしないために
リカバリーコードは絶対保存するようにしましょう。
（こんな失態なかなかしないかとは思いますが）
ローカルではなく、Onedriveなどに配置した方が良いですね。。

#### 設定方法

GitHubにログイン後

Setting > Security > save your recovery codesクリック

でダウンロードできます。
皆さんもお気をつけて:skull:
docker:dindは、何で動いている？

今Docker in Dockerを行いたいと思い、調べていました。
```bash
docker run --privileged --name dind -d docker:dind
```
のdocker:dindがコンテナのイメージと分かり、何で動いているのか気になりました。

調べたところAlpine Linux 3.15が、動いていました。


```bash

docker run --privileged --name dind -d docker:dind

/ # ls
bin    dev    home   lib64  mnt    proc   run    srv    tmp    var
certs  etc    lib    media  opt    root   sbin   sys    usr
/ # cat /etc/issue
Welcome to Alpine Linux 3.15
Kernel \r on an \m (\l)

/ # docker -v
Docker version 20.10.14, build a224086
/ # 



```
## docker-compose をインストール
こちらの記事を参考にしました。
https://qiita.com/zono_0/items/55e2e8fd4c6a48f03e32

## デスクトップもあるそうです。
https://wiki.alpinelinux.org/wiki/Xfce

## SSH接続
https://qiita.com/hiraike32/items/140d48165b957fbbbfaf

### 参考記事
https://zenn.dev/karamawanu/articles/df53968213e98e

https://qiita.com/ryuichi1208/items/6020cfabc92bd8153654

https://esakat.github.io/esakat-blog/posts/docker-in-docker/
改行を含まずにコピペする

## はじめに
DeepL ってめちゃくちゃ便利ですよね。私は英語論文を読むとき、しばしばお世話になります。

https://www.deepl.com/translator

ところで **DeepL で訳そうとコピーしても、ペーストすると改行が含まれるせいで、うまく訳されない**ってことありませんか？そこで本記事では改行を含まずにペーストし、DeepL にきれいに翻訳してもらうやり方を述べます。

## 多分、よくあるやり方は
一旦ブラウザのアドレスバーに打ち込むやり方ではないでしょうか。私の知人もこのやり方を実践していました。
↓ アドレスバー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530290/e916f486-d7a3-c2bb-b356-f50fc050b6d2.png "キャプションテキスト")

```:一旦ブラウザのアドレスバーに打ち込むやり方
ctrl + c（ pdf ビューワーにて英文をコピー）
↓
Alt + Tab（アプリをブラウザに切り替え）
↓
ctrl + l（アドレスバー選択）
↓
ctrl + v（ペースト。ここで改行が消える！）
↓
ctrl + x（切り取り）
↓
ctrl + Tab（タブを DeepL に）
↓
ctrl + v（ペースト）
```
みたいな。ずららっとショートカットキーが続きますが、まぁミスを誘発します。

## もっと早いやり方
AutoHotKey を使います。AutoHotKey とは早い話、キースワップができる Windows のマクロと思います。
私は Adobe で pdf を閲覧しており、Adobe で ctrl + c をするとコピーしたテキストに含まれる改行が空白に置き換わるというマクロです。なお、スクリプトのほとんどは、後に挙げる記事を参考にさせて頂きました。

```:translate.ahk
; Adobe で ctrl + c をしたとき、コピーしたテキストから \n を消してやる
; うまく動かないときは Sleep を増やす
#UseHook
#IfWinActive ahk_exe Acrobat.exe
  ^c::
    first_half = %clipboard%
    Send, ^c
    Sleep 100
    target_str = %clipboard%
    ; 改行コードをすべて空白に置換
    StringReplace, replaced_str, target_str, `r`n, %A_Space%, All
    clipboard = %replaced_str% ; クリップボードに代入
#ifWinActive
```
あとはこれをスタートアップのフォルダに入れておしまいです。次回から立ち上げと同時に使えるようになります。通常と同じように ctrl + c をするだけで、改行コードを含まないコピーができるようになりました。

## さらにもっと早いやり方
こちらに紹介してくださっているように、DeepL へのペーストまでも自動化する方法。最初は私もこちらを試していたのですが、私の古い PC ではあまりうまくいかなかったので断念。

https://qiita.com/ymg_aq/items/df8993b297fccd1eaa41

## さらにさらに早いやり方（予想）
pdf を OCR 技術と DeepL の API と併用し、翻訳ファイルを作成するのが最も早いでしょうか… これから勉強していきたいと思います。

## さらにさらにさらに早いやり方
英語を勉強しましょう←
Dockerを使いKaggle環境を構築する方法

# 1 この記事は

Dockerを使い、Kaggle環境をローカルPC上に構築する方法を説明します。


https://marshmallow444.github.io/tech_blog/2021/08/21/build_kaggle_env_on_docker.html

# 2 方法

## 2-1  Docker for windowsをインストールする。

https://qiita.com/NT1123/items/808a18671365c3c9aed6

## 2-2  Kaggleイメージをインストールする

Windowsのpowershellを立ち上げ、下記のコマンドを入力する。

```console:PowerShell
docker run --rm -it kaggle/python
```

## 2-3  Dockerを起動しコンテナを作成する。

```console:PowerShell
  docker run --network aukabu_default -v ${PWD}:/tmp/working -w=/tmp/working -p 8888:8888  --name meigara_ana -it kaggle/python jupyter notebook --no-browser --ip="0.0.0.0" --notebook-dir=/tmp/working --allow-root
```
xxxx:(コンテナの名前を入れる)

## 2-4  コンテナをスタートさせ、ブラウザを立ち上げる

Docker for windowsにてSTRATをクリックし、先に作成したコンテナを起動させる

![332.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/6cd02175-f9f8-91e8-6372-193b15031c08.jpeg)


下記図の赤枠で囲ったアイコンをクリックし、ブラウザを立ち上げる。
![331.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/c85b82d1-d0e2-71d1-38fb-ad14b70d97e1.jpeg)

ブラウザを立ち上げた時に、Paaword or tokenを入力する画面が出た場合、
![333.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/25845033-9cb5-c08d-bf1d-4a76ca76a265.jpeg)

Docker for desctopにてCLIを立ち上げる。
![334.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/2e0997cc-cfc4-f58f-1773-cccd42bdff83.jpeg)

CLIにて jupyter notebook listと入力するとtokenが表示される。「token=」以降の文字をコピーし、jupyterの画面で表示された
Password or token:のボックスに入力する。
![335.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/12a00edf-c415-11ce-80c3-4858e1962652.jpeg)


jupyterのスタート画面が表示される。
![336.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/2a12729c-1f4c-a413-4f22-4d76c5bfd7b6.jpeg)
ディレクトリ内のファイル数の上限【Google Compute Engine】

# TL;DR
10GBの場合、約57万個(575444)ファイルを作成できる。30GBならその3倍作成できる。
![Screenshot from 2022-04-20 07-13-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/88f839c2-5375-6b91-4fcb-fa894b90ca9d.png)
`us-west1`の`e2-micro`で試しました

### `/dev/sda1`の**IFree**で残りのファイル数(**575308**)の上限を確認できる。

```bash
$ df -i
Filesystem     Inodes IUsed  IFree IUse% Mounted on
udev           123900   297 123603    1% /dev
tmpfs          126223   378 125845    1% /run
/dev/sda1      647168 71860 575308   12% /
tmpfs          126223     1 126222    1% /dev/shm
tmpfs          126223     3 126220    1% /run/lock
tmpfs          126223    17 126206    1% /sys/fs/cgroup
/dev/sda15          0     0      0     - /boot/efi
tmpfs          126223    10 126213    1% /run/user/1000
```

### 575444個目までは問題なくファイルを作成できる

2時間ほど実行にかかります

```bash
for i in `seq 575444`; do touch $i; done
```

### ファイル作成後

```bash
$ df -i
Filesystem     Inodes  IUsed  IFree IUse% Mounted on
udev           123900    297 123603    1% /dev
tmpfs          126223    378 125845    1% /run
/dev/sda1      647168 647168      0  100% /
tmpfs          126223      1 126222    1% /dev/shm
tmpfs          126223      3 126220    1% /run/lock
tmpfs          126223     17 126206    1% /sys/fs/cgroup
/dev/sda15          0      0      0     - /boot/efi
tmpfs          126223     10 126213    1% /run/user/1000
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/d424be36-8a75-4471-db46-51984ed150e0.png)


### 575445個目を作成しようとすると`No space left on device`になる

```bash
$ touch 575445
touch: cannot touch '575445': No space left on device
```

SSHで接続に失敗しログインできなくなる
AZ-900　当日漬けでギリギリ合格した話

こんにちは、Hirotakaです。
AZ-900を当日漬けでギリギリ合格した時の話を下記にまとめました。
ちなみに700点以上が合格ラインのところ700点ドンピシャです(；・∀・)
一夜漬け、当日漬けで挑む方の参考になれば幸いです。
（もう少し余裕持って勉強しろよって話ですが）

# 試験結果
![スクリーンショット 2022-04-20 21.38.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1621592/7014bd4d-19a4-942a-1ef7-6b4ea33850a6.png)

# 受験動機
Azureを使う現場に異動になり、職場の先輩からAZ-900は無料で受けれる方法があるのと、合格したら会社から報酬がもらえると聞いたので、お小遣い稼ぎ程度に受けようと思いました。


# 自分の知識レベル
　異動前はAWSの現場におり、AWS SAAは取得済み
　Azureは未経験で、学習もまったくしてないレベル

# 無料で受ける方法
普通に受験すると12,500円の受験料がかかりますが、定期的に開催しているオンライン講習に申し込むと、無料で受験できる割引券がもらえます。
僕の説明よりもずっと詳しくわかりやすいサイト見つけました。リンク貼っておくので、ご参考まで。

・AZ-900を無料で受験する方法
https://jinzai.edifist.co.jp/article/take-the-exam-forfree/
・Microsoft Virtual Training Days
https://www.microsoft.com/ja-jp/events/top/training-days

# 勉強方法
Azure関連の教材は一冊も買ってないです。無料の問題集サイト２つを利用しました。
当日の流れとして、試験は午後4時ぐらいに事前に予約しておき、
午前中から試験開始まで、ひらすら問題サイトを演習してました。
全問演習し、わからないものはテキストに問題と答えをペタペタ貼る学習方法でした。
これでギリギリ合格に滑り込めました。
公式ドキュメントも少し読みましたが、頭に入ってこない＆時間無いので活用できてなかったです。

・利用した問題集サイト
https://studyand.work/list-question-azure-az-900
https://simple-was-best.com/az-900
・公式ドキュメント
https://docs.microsoft.com/ja-jp/learn/certifications/exams/az-900

# 反省点
一夜漬けどころか当日漬けで、教材も買わずに受験した上で得た気づき。
体系的な知識は最初にインプットすべきだと思いました。
問題で使われる用語がわからないのが多々あるのと、どの分野の話をしているのか把握しずらいため。
公式ドキュメントは無料で読めますが、あまり頭に入ってこなかったので本派です。
事前に体系的な知識をインプットしておくことをおすすめします。