OmniAICreator/Qiita-1.07M huggingface dataset:
【Kotlin】更に仕様変更に強い FizzBuzz

記事「[【Kotlin】仕様変更に強い FizzBuzz](https://qiita.com/sdkei/items/55c6cc20c49f6838d66b)」の発展。
さらに仕様変更に強くする。

```Kotlin
/**
 * FizzBuzz を行うためのクラス。
 *
 * [invoke] 関数に数値を与えると対応する文字列を返す。
 */
class FizzBuzz private constructor(
    private val fizzBuzzMap: List<(Int, String) -> String>
) {
    /**
     * [block] 内で [FizzBuzzMapBuilder.to] もしくは
     *  [FizzBuzzMapBuilder.unaryPlus] を呼び出すことで
     *  変換規則を追加できる。
     */
    constructor(
        block: FizzBuzzMapBuilder.() -> Unit
    ) : this(
        FizzBuzzMapBuilder().also {
            it.block()
        }.build()
    )

    /** 与えられた数値に対応する文字列を返す。 */
    operator fun invoke(num: Int): String =
        fizzBuzzMap.asSequence()
            .fold("") { str, entry ->
                entry(num, str)
            }
            .takeUnless { it.isEmpty() }
            ?: num.toString()

    class FizzBuzzMapBuilder {
        private val fizzBuzzMap: MutableList<(Int, String) -> String> = mutableListOf()

        /**
         * 割る数と、それで割り切れたときに出力する文字列を
         * 変換規則に追加する。
         *
         * @receiver 割る数
         * @param str 割り切れたときに出力する文字列
         */
        infix fun Int.to(str: String) {
            fizzBuzzMap += { num: Int, currentStr: String ->
                if (num % this == 0) currentStr + str
                else currentStr
            }
        }

        /**
         * 変換規則を追加する。
         * 
         * @receiver 変換規則。
         *  引数 num: [FizzBuzz.invoke] に与えられた数値。
         *  引数 str: この変換規則より前に処理された変換規則により構築された文字列。
         *  返値: この変換規則を適用した結果の文字列。
         *      この変換規則が適用されない場合は引数 str を返すこと。
         *      空文字列を返すと、この変換規則より前に処理された変換規則が
         *      適用されなかったのと同じになる。
         */
        operator fun ((num: Int, str: String) -> String).unaryPlus() {
            fizzBuzzMap += this
        }

        fun build(): List<(Int, String) -> String> =
            fizzBuzzMap.toList()
    }
}
```

## 普通の FizzBuzz

```Kotlin
/** 変換規則の定義。 */
val fizzBuzz = FizzBuzz {
    3 to "Fizz"
    5 to "Buzz"
}

fun main() {
    (1..15).asSequence()
        .map {
            fizzBuzz(it)
        }.forEach {
            println(it)
        }
}
```

出力

```plaintext
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
```

## 複雑な変換規則

- 2 で割り切れる場合は `Foo` を出力する。
- 3 で割り切れる場合は `Bar` を出力する。
- 2 でも 3 でも割り切れる場合は `FooBar` を出力する。
- ただし 4 で割り切れる場合は `Baz` のみを出力する。
- 上記のいずれでもない場合は数値を `<` `>` で囲って出力する。

```Kotlin
/** 変換規則の定義。 */
val fizzBuzz = FizzBuzz {
    2 to "Foo"
    3 to "Bar"
    +{ num: Int, str: String ->
        if (num % 4 == 0) "Baz"
        else str
    }
    +{ num: Int, str: String ->
        str.takeUnless { str.isEmpty() }
            ?: "<$num>"
    }
}

// main 関数は同じなので省略
```

出力

```plaintext
<1>
Foo
Bar
Baz
<5>
FooBar
<7>
Baz
Bar
Foo
<11>
Baz
<13>
Foo
Bar
```

## 雑感

特殊な変換規則のラムダ式の引数に型を明示しなければいけないのが面倒。

／以上
pulseaudioを使ってWSLで音を出す

タイトルのとおりです
僕の環境は、
OS : Windows 10 Education 64bit
WSL : Ubuntu 20.04

# Windows側の準備
https://www.freedesktop.org/wiki/Software/PulseAudio/Ports/Windows/Support/
ここの「zipfile containing preview binaries」からダウンロードします
適用な場所に解凍して、`bin` にパスを通します

`etc\pulse\default.pa`に以下を追記します

```:default.pa
load-module module-waveout sink_name=output source_name=input record=0
load-module module-native-protocol-tcp auth-anonymous=1
```

`etc\pulse\daemon.conf`に以下を追記します

```
exit-idle-time = -1
```

# WSL側の準備
まずインストールします

```bash
sudo apt update
sudo apt install pulseaudio
```

`/etc/pulseaudio/client.conf`に以下を追記します

```:/etc/pulseaudio/client.conf
default-server = tcp:localhost
```

`/etc/pulse/default.pa`を以下のように編集します

```bash:/etc/pulse/default.pa
load-module module-native-protocol-tcp  # ここをコメントアウト
```
# 再生


Windows側で以下を実行します

```:Windows
pulseaudio
```
WSL側で以下を実行します

```bash:WSL
sudo pulseaudio --system
```

適当な音声ファイルを用意して、別ウインドウで以下を実行します

```bash:WSL
ffplay test.wav
```
正常に再生できれば成功です

これで、firefox等のX11アプリケーションからでも音を出せるようになりました。
SQLのみを用いた集団の集計行の突合比較

#全体の背景
この記事は集計行の比較をどうやってやろうかと考えた結果、アレコレ試行錯誤の結果となります。
一応、成功はしていますがいったん帰宅してから記憶から呼び起こしながら作成している為、精度は確実ではありません。
※確認したら上の内容を修正します。

##注意
この記事はBIツールの都合上、SQL一本で突合比較を行おうとしております。一般的な場合、集計をSQL、比較はPython、Javaなどの手続き型言語で行うことを推奨します。
ホントに推奨かは知らないけど…
比較やったことないからなあ。
やりやすさと引継ぎやすさは後者が上だと思うけど
##再度注意
この投稿主は毎度、後輩から「説明を抜かさないでください」と叱られております。この記事も抜けている箇所がある気がしますのでご指摘お願いします。

##全体的な試行錯誤
1.シンプルだけど排泄物重かった
2.書籍に書いてあった集計行の出力
3.集計行の比較(ここから本題)

###シンプルだけど排泄物重かった
こちらは3秒で脳内却下しました。
やるならもうちょっと上手くやれるでしょう。

パフォーマンスもそうですが、データの過剰集計がないとも言い切れない点が非常に好みじゃないデスね。

```sql

select 
　　集計単位
　　,特徴A
　　,特徴B
　　・
　　・
　　・
　　,特徴z
from
(select 集計単位,sum(特徴A) 
from 巨大テーブルA
group by 集計単位)特徴A

left outer join
(select 集計単位,sum(特徴B) 
from 巨大テーブルb
group by 集計単位)特徴B
・
・
・
```

###書籍に書いてあった集計行の出力
この辺りの書籍をご覧になるのが、早いと思います。一緒にSQL沼に堕ちよう〜
達人に学ぶSQL徹底指南書
https://www.amazon.co.jp/dp/B00DIM6330/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

個人的には、集計のラベル張りさえ間違えなければ、集団のサマリーの関係性が崩れない点がサイコーに好きです。エクセルで言うところのsumifができる点ですね。

```sql
select
　　集計単位
　　,sum(case when 特徴A then 特徴 else 0 end)特徴A
　　,sum(case when 特徴B then 特徴 else 0 end)特徴B
　　・
　　・
　　・
from
　　巨大テーブルA
where
　　いつ時点で有効
```

###集計行の比較
ここから本題、
今回の内容は過去と現在の集計行の比較

可読性が下がるので、
先述した、『書籍に書いてあった集計行の出力』の内容については、ここでは集計SQLと呼称しますね。
では出力するためのフラグとしてdtimeを内部に持たせて、集計単位の増減があるかもしれないので
メインは集計単位のリストとします。

```sql
select
　　集計単位リスト.集計単位
　　--どの時点のデータを出力しているか判断する為出力
　　,dtime
　　,case when dtime='今' then 集計SQL(現在).特徴A
　　　　　 when dtime='過去' then集計SQL(過去).特徴A 
　　end as 特徴A
　　,case when dtime='今' then 集計SQL(現在).特徴B
　　　　　 when dtime='過去' then集計SQL(過去).特徴B 
　　end as 特徴B
　　・
　　・
　　・
from
　　集計単位リスト
left outer join
　　集計SQL(現在)
　　ON 集計単位リスト=集計SQL(現在).集計単位
left outer join
　　集計SQL(過去)
　　ON 集計単位リスト=集計SQL(過去).集計単位

left outer join
--出力する内容をSQLが判断するようの内部種別
(select '今' as dtime
　UNION
 select '過去' as dtime)dtime

where
--特徴量が1種でも違うものがあるレコードを出力
case when 集計SQL(現在).特徴A<>集計SQL(過去).特徴A then 1 else 0 end
+
case when 集計SQL(現在).特徴B<>集計SQL(過去).特徴B then 1 else 0 end
+
・
・
・
<> 0
```

正直、文献探すヒマもWebを漁りにいくヒマもなかったんですよね。多分ある気がする。
あったら教えて下さい。
お願いします。
VSCodeでリモートにある複数のサーバーにファイルを同期して機械学習などの重いタスクを実行する（sync-rsync extension）

#はじめに
機械学習などの手元のPCで出来ないような重い処理が必要な際に，処理を回すサーバーは存在するけど，kubernetesやジョブスケジューラが置いてある規模ではないので，手動でコードを送って実行しなければならないような環境があると思います．
VSCodeを使っていれば，[Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack)というExtensionを使えば，リモートにssh経由でVSCode上でアクセスしてファイルを同期できます．
しかしコードがリモート上で編集されるため，今コードが置いてあるサーバーとは別のサーバーで実行したい際に，サーバー間でのファイルの同期が面倒という問題があります．
そこで，VSCodeの[sync-rsync](https://marketplace.visualstudio.com/items?itemName=vscode-ext.sync-rsync)というExtensionを使って，コードを手元で管理し，必要な際にrsyncでリモートと同期して迅速にコードを同期することでこの問題を解決します．

# How To Set up
1. VSCodeのExtensionsを開き，Sync-RsyncRsyncパッケージをインストールします．
2. VSCodeのSettingsを開き，setting.jsonを開いて編集できる状態にする，もしくは検索欄でsync-rsyncで検索し，sync-rsyncに関するセッティングが出来る状況にします．（以下setting.jsonを開いた状態を想定します．）
ちなみにsettin.jsonは画像で示した赤丸をクリックすると開けます．

![opensetting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213113/f9d2c408-8898-73cc-94ba-27ffdd4dd517.png)


3. 同期したいローカルのフォルダとリモートのフォルダを以下のように指定します．

```json:setting.json
{
"sync-rsync.sites": [
			{
				"name" : "hoge",
				"localPath": "/home/user/project/s1/",
				"remotePath": "user@server:/var/www/s1/"
			},
			{
				"name" : "fuga",
				"localPath": "/home/user/projects/t2/",
				"remotePath": "user@server:/var/www/s2/"
			}
		]
}
```

それぞれの変数の役割は以下の通りです

- name : 設定の名前
- localPath : 手元のマシンの同期したいパス
- remotePath : リモートのマシンの同期したいパス

接続先は複数登録できます．一つ一つ同期する方法や全てを同時に同期する方法もあるので，必要におうじて設定してください．
なお，ssh経由でrsyncを行うことが想定されるので，必要に応じて以下のようにsshのオプションを設定してください．

```json:setting.json
{
"sync-rsync.shell": "ssh -i ~/.ssh/id_rsa"
}
```
これ以外にも，vscode上でssh-agentを設定したりすると，VSCodeでssh接続全般が楽になります
（参考）[[Windows] VSCode で使うssh-agentについて](https://crieit.net/boards/mogya-vsremote/Windows-VSCode-ssh-agent)

4. Ctrl+Shift+P（Macの場合はCommand+Shift+P）を押して，Sync-Rsyncと打つと，以下のようにコマンドが複数出てきます．

![sync-rsync.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213113/fcbc3f4f-8ae4-597d-b0e1-d242a9ee8767.png)

Sync-Rsync: Sync Local to Remote(Single site)を選択した場合は，先ほど"name"で設定した接続先を選び，設定したサーバーと同期します．
Sync-Rsync: Sync Local to Remoteを選択した場合は，設定した全てのサーバーで同期を行います．

また，これと逆にリモートからローカルに共有する，Sync Remote to Localというコマンドも，使うことが出来るようになります．

# おわりに
いかがでしょうか。複数のサーバーがあってそれぞれのサーバーごとにコードを管理しなければいけないのは面倒でしたが，sync-rsyncを使えば手元でコードを一括で管理することが出来ます．
また，Remote Developmentを利用した場合，接続先ごとにvscodeがインストールされてその都度extensionを設定しなければいけなかったり，リモートに繋げなくなった場合にコードに一切アクセス出来なくなる恐れがありますが，このようにローカルでコードを管理しておけばその心配もなくなります．
このように複数のサーバーでコードを動かす必要がある場合，sync-rsyncによるコード共有は強力な手段となります．利用用途に応じて是非ご活用ください．
Node.jsで作る簡単なWebアプリケーション

今回はNode.jsで作成する簡単なアプリケーションの作り方を解説していきます。
※nodeとnpmはインストール済みであることを前提としてます。

##プロジェクト作成

まず、プロジェクトを作成していきます。
今回はsampleという名前のプロジェクトを作成します。

##package.json作成
vacode上で先ほど作成したフォルダを開き、
ターミナルで下記のコマンドを実行し、package.json を作成していきます。

`npm init`

このとき、プロジェクト名などを聞かれまずが、
entrypointのみ"app.js"に変えましょう。

##必要となるパッケージをインストール

必要となるパッケージをインストールしていきます。

今回使うのは下記の3つのパッケージです。
・express
・ejs
・bootstrap

それではインストールしていきましょう。

インストールは以下のコマンドで実行できます。
`npm install express ejs bootstrap --save`

インストールが完了すれば準備OKです。

##必要なディレクトリを準備

次に、必要なディレクトリやファイルを用意します。
<img width="440" alt="スクリーンショット 2020-07-11 18.01.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472442/35f3b8c5-953d-5ce7-d701-dd8e736a0074.png">

このような状態にしましょう。

**bootstrapの中身については、
node_module/bootstrap/distの中をコピーしてください**
 
##app.jsの中身を記述する

まず、必要最低限の中身を書いていきます。

```javascript:app.js
var express = require('express');
var app = express();

app.listen(3000);
```

続いて、テンプレートエンジンの読み込みを行います。

```javascript:app.js
var express = require('express');
var app = express();

app.set("view engine", "ejs" );//テンプレートエンジンの読み込み

app.listen(3000);
```

次に、静的ファイルの配信を行います。

```javascript:app.js
var express = require('express');
var app = express();

app.set("view engine", "ejs" );//テンプレートエンジンの読み込み

app.use('/public', express.static(__dirname + '/public'));//静的ファイルの読み込み

app.listen(3000);
```

最後に、ルーティングを記述したファイルを呼び出します。

```javascript:app.js
var express = require('express');
var app = express();

app.set("view engine", "ejs" );//テンプレートエンジンの読み込み

app.use('/public', express.static(__dirname + '/public'));//静的ファイルの読み込み

app.use('/', require('./routes/index.js'));//ルートにアクセスしてきたときのルートファイル

app.listen(3000);　
```

これで、app.jsの中身はOKです。

##ルーターを作成

次に、routes/index.jsの中身を書いていきます。

```javascript:routes/index.js
var router = require('express').Router();

router.get('/', (req, res) => { //getでルートにアクセスしてきたときの処理
  res.render("index.ejs");
});

module.exports = router;
```

##Viewを作成

最後にアクセスした際に表示されるページのViewを整えます

```HTML:views/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="/public/third_party/bootstrap/css/bootstrap.min.css" />
</head>
<body>
  <div class= "container">
    <h1>サンプル</h1>
    <P>Node.js + Expressで簡単なWebアプリケーションができました</P>
  </div>
</body>
</html>

※注意点
・bootstrapを使用するので"container"を忘れずに
・拡張子はhtmlではなくejs
```

これで全ての準備が整いましたので、以下のコマンドを実行して確認してみましょう。

`node app.js`

ターミナル上では待機状態になっているはずなので、Chromeを立ち上げて[localhost:3000](http://localhost:3000/)にアクセスしてみましょう。

<img width="1261" alt="スクリーンショット 2020-07-11 18.23.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472442/4185bad4-37c0-451c-abc7-017231b81835.png">

うまく表示されたのではないでしょうか。


以上になります。
人と衝突したときに自分を傷つけないようにする思考・方法

# きっかけ
人間は人と関われずに生きることは実質不可能で、社会人になったら尚更人と関わって生きていくことになります。
自分も社会人4年目のエンジニアでチームに所属しながら働いています。
その中で意見が対立したり口論に発展しそうになったり発展してしまったりしているところを何回か経験しました。
その時によく自身のネガティブな思考に囚われ、よく悩んでいる事が多々ありました（アドラーが言った「すべての悩みは対人関係の悩みである」とは本当によく言ったものです）。
そのような思考に陥ってしまいそうなときに自分が良くしている考え方や人と話す時の方法をメモがてら書いておきます。
実際、この方法で自分はとても精神的に楽になりましたし自分だけでなく他の人にも何かの助けになれば幸いです。
（初めに断っておきますがあくまで個人の意見なので万人に有効ではないです。ちょっとしたきっかけ程度に見ていただけると幸いです。）

## 方法
自分が実際に行っているのは以下の3個です。
- 相手の言ったことをとりあえず受け止めて認める
- 相槌を打ってちゃんと聞いている事を示す
- 自分が譲れるところと譲れないところを意識する

一個ずつ説明していきます。

### 1. 相手の言ったことをとりあえず受け止める
相手の言ってきた言葉に対して反発するように打ち返してしまうと相手も躍起になってそのまま口論がエスカレートしていく事が何回かありました。
そうなると人格を否定するような言葉や罵声などが出てくるのも時間の問題です。
なので相手の言ったことを **まず一旦受け止めてその後に自分の意見を言うように** しています。
相手も自分の意見を聞いてくれているというある種の承認欲求を満たすことができ、
不快感を与えることなく更に自分の意見を言うことで口論ではなく議論を行うことができると考えています。
相手のいった言葉に対してワンクッション置いて、そこから話し始めるイメージです。
この辺は実際に「Yes and法」というテクニックに関連してくるものなので興味ある方は一度見てみると良いかもしれません。

### 2. 相槌を打ってちゃんと聞いている事を示す
話をしているときに相手がノーリアクションだと気まずくなった経験はあったりしませんか？
そうなってくるとその場の雰囲気がぎくしゃくしたものになってしまうし「なんかうまく話せなかったなぁ」という心残りを抱えることが自分にもありました。
まずは **自分から相手の言っていることに対して何かしらリアクションを取ってみる** と良いと思います。
そうすることで「ちゃんと話を聞いてくれている」というのが伝わり相手がもっと話しやすくなりますし、そこから疑問点を聞いたり自分の意見を述べることで会話を発展していけばより有意義で意味のある議論になるかと思います（ちょっとオーバーかな？）。
相槌だけでなく「あぁ～」や「なるほどね～」みたいな言葉もとても有効だと思います。

### 3. 自分が譲れるところと譲れないところを意識する
これは最近教えてもらったものなのですがとても有効だったのでぜひ知ってほしいです。
何かしら意見を述べたときに否定されたりこうしたほうがいい！ってなってもそれを採用してもらえない時があります。
自分も設計や実装の方針を話したら真っ向から批判されたりして、しかもそれが何回も続いて精神的につらい時期がありました。
その事を相談したときに教えてもらったのが「自分が譲れるところと譲れないところを意識する」ということでした。
イメージとしては **「俺だったらこうするけど、そんなに強いこだわりないし別にそれで試してみてもいいんじゃない？」** みたいな感じですｗ
このように自分の中で線引きしておくことで常に対立しなくてもよくなるし常に気を張る必要もなくなるのでとても気が楽になりました。
それにもしかしたら譲った方のやり方のほうが意外と良い成果が出るかもしれません。その時は素直に受け止めて次の糧にしていけばいいと思います。
ただ譲れないと思ったところは自分から言っていかないと何も意見を持っていない人というように思われてしまうので、ちゃんと出るところは出ましょうｗ

# さいごに
以上が自分が実践している考え方だったり方法です。
題名に「人と衝突したとき」とありますが、そこに限ったことではなく普段のコミュニケーションから使えることだと思います。
自分はエンジニアだけでなく新卒エンジニア職のリクルータも行っておりよく学生さんと面談をするのですが今回紹介した1番や2番を意識しています。
そうすることで最初は緊張していても途中からリラックスしてくれて色々話を聞かせてくれたりその中で相手の事をよく知ることができるようになってお互いに良い時間を過ごせるようになっていきました。

拙い文章ではありますがなにか仕事だったりプライベートだったりで精神的にきついなぁと思ったら是非試してみてください。
FreeRTOS理解その２（ボタン押下によるタスク切換えその１）

# FreeRTOS実習その２
その１と記載せずだったが、[こちら](https://qiita.com/infinite1oop/items/aac04a70c1ed71cb83cc)の続き。最初にお断りしておくが、ステキなプログラムではない（改善の余地あり）。
## やること
ボタンを押したらタスクが切り替わるプログラムの実現。
## 使ったもの
スイッチサイエンスさん経由で購入した[Nucleo-F303RE](https://www.switch-science.com/catalog/2542/)。ユーザー用ボタンが最初から搭載されているので、、、という単純な理由。

## コード
### タスク関連宣言
ボタン押下を扱うタスクとLEDオンオフを扱うタスク２つ。

```c++
#include <STM32FreeRTOS.h>

const uint8_t Led = LED_BUILTIN;
const uint8_t Btn = USER_BTN;

TaskHandle_t TaskButton_Handler;
TaskHandle_t TaskBlink1_Handler;
TaskHandle_t TaskBlink0_Handler;

void TaskButton(void *pvParameters);
void TaskBlink1(void *pvParameters);
void TaskBlink0(void *pvParameters);

```

### Arduino環境でおなじみ部分
タスク生成など。

```c++

void setup() {
  Serial.begin(9600);  
  while (!Serial) {}

  pinMode(Led, OUTPUT);

  xTaskCreate(TaskButton, "Button", 128, NULL, 2, &TaskButton_Handler);
  xTaskCreate(TaskBlink1, "Blink1", 128, NULL, 1, &TaskBlink1_Handler);
  xTaskCreate(TaskBlink0, "Blink0", 128, NULL, 1, &TaskBlink0_Handler);    

  vTaskStartScheduler(); 
}  

void loop() {
  // Empty. Things are done in Tasks.
}
```

### ボタン押下を扱うタスク

```c++
void TaskButton(void *pvParameters) {
  (void) pvParameters;
  int pressed = 0;
  
  pinMode(Btn, INPUT);
  vTaskSuspend(TaskBlink1_Handler);  
  vTaskSuspend(TaskBlink0_Handler);  
  for (;;) {
    if (pressed == 0) {
      if (digitalRead(Btn) == LOW){
        Serial.println("Button Pushed for Blink1");
        pressed = 1;
        vTaskSuspend(TaskBlink0_Handler); 
        vTaskResume(TaskBlink1_Handler);
      }
    } else { // pressed == 1
      if (digitalRead(Btn) == LOW){
        Serial.println("Button Pushed for Blink0");
        pressed = 0;
        vTaskSuspend(TaskBlink1_Handler); 
        vTaskResume(TaskBlink0_Handler); 
      }
    }
    vTaskDelay(500/portTICK_PERIOD_MS); // wait for 500ms
  }
}
```

最初にvTaskSuspend()で２つのLEDタスクを止めてしまう。ボタンが押されたら、２つのタスクを交互に眠らし（vTaskSuspend()）、起こす（vTaskResume()）。

### LEDタスク
2つのタスクの違いは、LED点滅の間隔が異なるだけ。

```c++
void TaskBlink1(void *pvParameters) {
  (void) pvParameters;

  for (;;) {
    digitalWrite(Led, HIGH);
    delay(500);
    digitalWrite(Led, LOW);
    delay(500);
    Serial.println("Blink1");
    vTaskDelay(1);
  }
}

void TaskBlink0(void *pvParameters) {
  (void) pvParameters;
  
  for (;;) {
    digitalWrite(Led, HIGH);
    delay(1000);
    digitalWrite(Led, LOW);
    delay(1000);
    Serial.println("Blink0");
    vTaskDelay(1);
  }
}
```

ボタン押下タスクへの切換えの余地を残すため、vTaskDelay()を用いている。

## 実験
コンソール上では下記のような感じ。ボタンを押すと切り替わっている。
![1stTry.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/bf6bc38b-dfac-a3c4-1c6b-f47bbdf37d3c.png)

## しかし、、
このプログラムではボタンのチャタリングを防ぐことはできず、ボタンスイッチを押しても（特にすぐに押して離す場合）タスクが切り替わらないことがある。これを解決するのは次回（その３）にて。

## 参考
[FreeRTOS API群](https://www.freertos.org/a00106.html)
PyTorch==1.1.0をWindowsへ導入

#GPU対応のPyTorchをWindowsへ導入したい
（注意　conda と pip はごちゃまぜにしない）

```
AssertionError                            Traceback (most recent call last)
<ipython-input-2-94528e288f7d> in <module>()
      2 import torch
      3 print(torch.cuda.is_available())
----> 4 torch.cuda.current_device()
# ~ 省略 ~
AssertionError: 
The NVIDIA driver on your system is too old (found version 9010).
Please update your GPU driver by downloading and installing a new
version from the URL: http://www.nvidia.com/Download/index.aspx
Alternatively, go to: https://pytorch.org to install
a PyTorch version that has been compiled with your version
of the CUDA driver.
```
Windows10でPyTorchのtorch.device("cuda", gpu_id)ができなかったので入れ直しました。

# 【本題】PyTorchの入れ直しの前と後
はじめは以下のようにしてPytorchを導入しました。

```
pip install torch===1.4.0 torchvision===0.5.0 -f https://download.pytorch.org/whl/torch_stable.html
```
ただしこれだと上述の通りGPUに対応しませんでした。CUDAなどのバージョンとあっていないのが原因だと思われます。
そこで以下のようにしました。

```
pip uninstall torch
pip uninstall torchvision
# Anaconda Promptを管理者権限で起動して以下を実行（下記サイトを参考にバージョンを変更）
conda install pytorch==1.1.0 torchvision==0.3.0 cudatoolkit=9.0 -c pytorch
```
**condaとpipは混在させてはいけません。**最悪Anacondaの入れ直しになります。そうならないようにAnaconda Navigatorで環境を管理しておくべきです。僕の場合は既にぐちゃぐちゃの環境のPCで試した後にきれいな環境のPCに整えようと思っているので、とりあえず実行できればいいやと思ってます。
PyTorchを始めようと思っていてWindowsがまだ綺麗な状態なら、conda installを使って管理してみるのはいかがでしょうか。

ちなみにCUDAとの対応などを確認するには以下のサイトが参考になります。
https://pytorch.org/get-started/previous-versions/
https://pytorch.org/
今回はCUDA9.0なのでPyTorch==1.1.0を選びました。例えば上記サイトによるとCUDA9.2だとPyTorch==1.2.0が選べます。

#以下、環境やバージョン確認方法についての詳細
## 環境

- Windows10
- GTX1060
- NVIDIA CUDA 9.0
- NVIDIA Driver Version 390.65
- cuDNN 7.0.5

## NVIDIA CUDA Windowsでの確認方法
Anaconda Promptなどで

```
nvcc -V
```

## NVIDIA Driver Windowsでの確認方法
Anaconda Promptなどで

```
cd C:\Program Files\NVIDIA Corporation\NVSMI
nvidia-smi.exe
```

## NVIDIA cuDNN　Windowsでの確認方法
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\include\cudnn.h

```
#define CUDNN_MAJOR 7
#define CUDNN_MINOR 0
#define CUDNN_PATCHLEVEL 5
```
の行を探す。上から順に7.0.5ということがわかる。

## PyTorchのGPU対応の確認

```python
import torch
print(torch.cuda.is_available())
torch.cuda.current_device()
```
出力が以下のようになっていればPytorchからGPUを使うことができます。
<img width="277" alt="pytorch_gpu.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282390/079f8dd2-8bbc-a9b2-23d5-82d004d55313.png">


# 追記 torchsummaryインストール
torchsummaryをインストールしたかったのでやってみたら、これはconda installができませんでした。なのでAnaconda Promptで、

```
pip install torchsummary
```
としました。

# 参考
http://tecsingularity.com/cuda/version_conf/
https://qiita.com/kekekekenta/items/19972a45025a97330e21
https://qiita.com/nabenabe0928/items/7962dcf3030889667de4
go修行19日目 HMAC


## HAMC

- api認証
- https://xn--go-hh0g6u.com/pkg/crypto/hmac/

```golang
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
)

// サーバサイドで正しいクライアントのものかを判定する
var DB = map[string]string{
	"User1Key": "User1Secret",
	"User2Key": "User2Secret",
}

func Server(apiKey, sign string, data []byte) {
	apiSecret := DB[apiKey]
	// sha256の同じアルゴリズムを使う
	h := hmac.New(sha256.New, []byte(apiSecret))
	h.Write(data)
	expectedHMAC := hex.EncodeToString(h.Sum(nil))
	// 同じアルゴリズムでエンコードしたhmacが一致するかを確認
	fmt.Println(sign == expectedHMAC)
}

func main() {
	const apiKey = "User1Key"
	const apiSecret = "User1Secret"

	data := []byte("data")
	h := hmac.New(sha256.New, []byte(apiSecret))
	h.Write(data)
	sign := hex.EncodeToString(h.Sum(nil))

	// ハッシュ値
	fmt.Println(sign)

	// サーバに投げる
	Server(apiKey, sign, data)
}
```

出力

```
076b55e7f7e12624b4569f162302f1e36c11fb3a9134889267748de14a84b996
true
```

## Semaphore

- goroutineが走る数を限定することができる

```
go get golang.org/x/sync/semaphore
```

```golang
package main

import (
	"context"
	"fmt"
	"time"

	"golang.org/x/sync/semaphore"
)

// 並行実行できるプロセス数を制限
var s *semaphore.Weighted = semaphore.NewWeighted(1)


func longProcess(ctx context.Context){
	// 処理が並行している場合ロックをかけることができる
	isAcquire := s.TryAcquire(1)
	if !isAcquire{
		fmt.Println("Could not get lock")
		return
	}

	defer s.Release(1)
	fmt.Println("Wait...")
	time.Sleep(1 * time.Second)
	fmt.Println("Done")
}

func main() {
	ctx := context.TODO()
	go longProcess(ctx)
	go longProcess(ctx)
	go longProcess(ctx)
	time.Sleep(5 * time.Second)
}
```

```
Could not get lock
Could not get lock
Wait...
Done
```

## ini

- configファイルを読み込む
- サーバの設定値など

```golang

package main

import (
	"fmt"

	"github.com/go-ini/ini"
)

type ConfigList struct{
	Port int
	DbName string
	SQLDriver string
}

var Config ConfigList

// main関数が呼ばれる前に設定を呼び込む
func init(){
	cfg, _ := ini.Load("config.ini")
	Config = ConfigList{
		Port: cfg.Section("web").Key("port").MustInt(),
		DbName: cfg.Section("db").Key("name").MustString("example.sql"),
		SQLDriver: cfg.Section("db").Key("driver").String(),
	}
}

func main(){
	fmt.Printf("%T %v\n", Config.Port, Config.Port)
	fmt.Printf("%T %v\n", Config.DbName, Config.DbName)
	fmt.Printf("%T %v\n", Config.SQLDriver, Config.SQLDriver)

}
```

```config.ini
[web]
port = 8080

[db]
name = stockdata.sql
driver = sqlite3
```

出力

```
int 8080
string stockdata.sql
string sqlite3
```

## 教材
https://www.udemy.com/course/go-fintech/learn/lecture/12088980
MySQL Dump取得手順

## 概要
先日MySQLのdumpをとって、別環境に反映しといて！
といわれて、初めてdumpをとって反映という作業をしたので手順等をφ(..)メモメモ

## やりたいこと
環境AのhogeDBのdumpを取得し、環境Bに反映する。

## 手順

### dumpをとる！

今回はtablePlusのGUI操作でdumpを取得したが、コマンドでもできる。

```
## データベースのダンプをまるっと取得する
$ mysqldump -u USER_NAME -p -h HOST_NAME DB_NAME > OUTPUT_FILE_NAME
```

他にもテーブルのみのダンプや、定義のみなど、色々オプションはあるので使うときに調べましょう。

### 圧縮する！

```
zip -r hoge.zip hoge.dump 
```

zipコマンドもオプションが色々ある。
例えば、-eでパスワード付き

### 環境Aから環境Bにdumpファイルを転送する！

scpコマンドをつかいます。

```
### 
scp [コピー元のパス] [コピー先のパス]
# パスの書き方は
# ユーザ名@サーバのホスト名(or IPアドレス):コピーしたいファイル、もしくは保存先のパス
```

### 環境Bでdumpを解凍する！

```
unzip hoge.zip 
```

### dumpを環境Bに反映する！

```
nohup mysql [反映先のDB名] < hoge.dump &
```

- nohupコマンドについて
  - 簡単にいうとコマンドのバックグラウンド実行。
  - 実行中に画面を閉じたり、ログアウトするとコマンドが終了してしまうが、それを防ぐことができる
  - 参考: https://www.atmarkit.co.jp/ait/articles/1708/24/news022.html
  
 
 ## まとめ
 基本的なことだが、今までやる機会がなかったので良い経験になった。
 nohupコマンドとかは知っていると知らないのじゃ、作業効率に差が出ると思うので、積極的に使いたい。
windowsでiverilog その53

#概要

windowsでiverilogやってみた。
polyphonyで浮動小数点やってみる。
整数化やってみた。

#計算手順

①符号、指数、仮数に分ける。
②指数部から、整数化の指数を求める。
③仮数に掛ける。（２進数のシフト）
④32bitで返す。

#サンプルコード


```
import polyphony
from polyphony import testbench, module, is_worker_running
from polyphony.io import Port
from polyphony.typing import bit, bit32, bit23, bit24, bit25

@module
class toint:
	def __init__(self):
		self.a = Port(bit32, 'in')
		self.b = Port(bit32, 'in')
		self.c = Port(bit32, 'out')
		self.append_worker(self.worker)
	def float2b(self, a:bit32):
		a_sig:bit = (a >> 31) & 0x1
		a_exp:bit8 = (a >> 23) & 0xff
		a_fra:bit24 = a & 0x7fffff | 0x800000
		return (a_sig, a_exp, a_fra)
	def b2float(self, a_sig:bit32, a_exp:bit32, a_fra:bit32):
		return (a_sig << 31) | (a_exp << 23) | a_fra
	def worker(self):
		while is_worker_running():
			b0:bit32 = self.b.rd()
			(b_sig, b_exp, b_fra) = self.float2b(b0)
			b_exp = 127 - b_exp + 23
			b_exp = b_exp & 0xff
			frac:bit48 = b_fra
			frac = frac >> b_exp
			frac = frac & 0xffffff
			c0:bit32 = frac
			self.c(c0)

m = toint()

@testbench
def test(m):
	m.b.wr(0x3f800000)
	print ("1.0")
	c = m.c.rd()
	print(c)
	m.b.wr(0x40800000)
	print ("4.0")
	c = m.c.rd()
	print(c)

test(m)





```

#python実行結果


```


1.0
1
4.0
4


```

以上。
[Python]virtualenvの使い方

# 概要
Pythonのパッケージであるvirtualenvの使用方法を示す。

# virtualenvとは
特定ディレクトリ以下をPythonの仮想環境としてセットアップするために用いられる。
これにより、プロジェクトごとにPythonのインタプリタ、パッケージ等のバージョンを個別に管理することができる。

※「とあるプロジェクト開発時に特定パッケージのバージョンを上げたら、同パッケージを使用しているもう一方のプロジェクトでエラーを吐くようになった」みたいなことを防げる

# 基本的な使い方
virtualenvを入手
`$ sudo pip install virtualenv`
バージョン確認
`$ virtualenv --version`
ディレクトリ配下に仮想環境を構築
`$ virtualenv <dir_name>`
仮想環境を有効化
`$ . <dir_name>/bin/activate`
仮想環境を無効化
`(dir_name)$ deactivate`
仮想環境を抹消するときはディレクトリごと全消去でOK
`$ rm -rf <dir_name>`
統計検定2級　合格して気づいたアンチパターン　


# 目的
統計検定2級について、オススメの勉強方法や合格体験記は多くありますが、アンチパターンまで振り返った記事は見かけなかったので、書いてみることにしました。

# 前提条件
- 新人エンジニア2年目。
- 理系大学院修士卒（専門は統計とは無関係）
- 仕事上で統計やデータ分析をすることは皆無
- つまり、標準偏差？なにそれ？状態からスタート
- 結果、1度目はあと4点で不合格。2度目は合格点20点超えで合格

#アンチパターン（やって悪かったこと）
- 受験方式ごとに問題傾向が違う事を知らなかった
    - 統計検定には[試験方式が二つ](https://www.toukei-kentei.jp/exam/#:~:text=%E7%B5%B1%E8%A8%88%E6%A4%9C%E5%AE%9A%E3%81%AE%E5%8F%97%E9%A8%93%E6%96%B9%E5%BC%8F,%E6%96%B9%E5%BC%8F%E3%81%AE%EF%BC%92%E3%81%A4%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82)あり、合格点が異なることからも分かるように、傾向が異なる。（[傾向についてはこちらの方が説明がして下さっています。](https://www.messyer813.com/entry/2018/11/04/194330#CBT%E6%96%B9%E5%BC%8F%E3%81%A7%E7%B5%B1%E8%A8%88%E6%A4%9C%E5%AE%9A2%E7%B4%9A%E3%82%92%E5%8F%97%E9%A8%93%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F%E6%84%9F%E6%83%B3%E3%81%A8%E9%80%9A%E5%B8%B8%E8%A9%A6%E9%A8%93%E3%81%A8%E3%81%AE%E9%81%95%E3%81%84)）
    - 私はCBT方式受験なの紙方式寄りの勉強ばかりしていて、1度目の受験で惨敗しました。
    
- 直近の過去問を解く（CBT方式で受験の場合）
    - 上述の通り、直近の傾向＝自分の試験の傾向、とは限らないです。
    
- ノートにまとめる
    - 達成感はあるが、参考書と比べて見直しに不向きです。書いた内容の暗記もそれほど捗るわけではないです。
    - その割に時間がかかります。
    
- 解けなかった過去の試験問題を繰り返し解く
    - 明らかな難問がたまに混じっています。2～3割は落とせる問題と考えて勉強しました。
    
- 時間を測って過去問を解く
    - 試験本番で時間を気にしたことはほぼありませんでした。
    - 時間をかければ解ける問題は少ない印象です。
解法がすぐに思いつかない問題は飛ばした方が良いと思います。

#逆にやって良かったこと
- 統計Webを流し読み
    - 1周目：ざっくり理解
    - 2週目以降：過去問と合わせて解法の暗記
    - みたいな活用がオススメです。
    
- 過去問を解く
    - 上述のように1,2年分は解法の暗記と割り切って、いきなり解答を見てしまっても良いかもしれません。
    
- YouTubeの動画で補足する
    - 比較的受け身で勉強できるので、統計Webの息抜き＆補足として観てました。
    - [ヨビノリチャンネル](https://youtu.be/Bj8fkq533Dc)さんが分かりやすいです。
    
    
- 試験直前にチートシートを眺める
    - 試験本番で公式を思い出せず解けない事故を防げます。自分は[こちら](https://qiita.com/moriokumura/items/ed246efe11fc5d3fc760)が一番良かったです。

- 合格体験記を書く
    - モチベーションの維持です。試験勉強と並行して合格体験記を書いていました。
    - 合格体験記を並行で書くことで勉強方法を客観視できるので、無駄な努力に走りにくいと思います。




#参考サイト
- [統計検定2級　チートシート](https://qiita.com/moriokumura/items/ed246efe11fc5d3fc760)
- [CBT方式の傾向について](https://www.messyer813.com/entry/2018/11/04/194330#CBT%E6%96%B9%E5%BC%8F%E3%81%A7%E7%B5%B1%E8%A8%88%E6%A4%9C%E5%AE%9A2%E7%B4%9A%E3%82%92%E5%8F%97%E9%A8%93%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F%E6%84%9F%E6%83%B3%E3%81%A8%E9%80%9A%E5%B8%B8%E8%A9%A6%E9%A8%93%E3%81%A8%E3%81%AE%E9%81%95%E3%81%84)
- [ほかの合格体験記　まとめ](https://qiita.com/okoppe8/items/6caca7ab6509edf0c497)
CSS フォントサイズの変更　クラス指定なし

html
<p>あいうえお</p>
<p>かきくけこ</p>


css
p{
fontsize
}

pタグにクラス名を指定せずに、「あいうえお」「かきくけこ」のフォントサイズを別々にできる方法はありますか？（「あいうえお」フォントサイズ10px、「かきくけこ」フォントサイズ20px）のように
<p style="">これ以外で外部cssで記述する方法があれば知りたいです。
iPhoneの同期とかTimeMachineバックアップのときにSambaがCoreファイルを吐いて強制終了する話

# はじめに
タイトルはあれなんだが、使い古したMac MiniにUbuntu18.04.4を入れて、
さらにそこにSamba(4.11.9)を入れて、そこにTimeMachineのバックアップ取ったり、
そこにiTunesのライブラリ（音楽ファイル）を置いてたりしてました。
（という話も書こうと思ってまだ書いてない。）

そしてある日からTimeMachineのバックアップや、
iPhoneの同期（ミュージックの同期）に失敗するようになりました。

失敗したときには、Sambaがハングアップしているので、これが原因だろうと調査しました。

# ログを見てみる
まずは```/var/log/samba/log.smbd```を見てみると

```bash:log.smbd
[2020/07/05 23:24:37.465274,  0] ../../source3/lib/util.c:501(reinit_after_fork)
  messaging_reinit() failed: NT_STATUS_DISK_FULL
```

とか出てたり、```/var/log/samba/log.%m```の方にも、
```NT_STATUS_NOT_FOUND```とか、```NT_STATUS_UNSUCCESSFUL```とか出てる。

# DISK FULL？？
いや、どこもディスク溢れてないが、、、、
90%超えたくらいでSambaはそう言ったりするとかの話もあるけど、そうでもないが。。

# DISK FULLになっていたのは/run/lockパーティション
なんか色々調べていたら/run/lockパーティションが溢れて、Sambaがパニックを起こしていたらしい。

```bash:これはサイズ変更後
$ df -h /run/lock
Filesystem      Size  Used Avail Use% Mounted on
tmpfs            16M  6.2M  9.9M  39% /run/lock
```
このパーティションはシステムが勝手にマウントする領域らしく、自分の場合は5MBでマウントされていました。
とりあえず16MBでマウント。
サイズを変えるには、```/etc/fstab```に以下の行を追加して、再起動。

```bash:fstab
tmpfs	/run/lock	tmpfs	rw,nosuid,nodev,noexec,relatime,size=16m 0 0
```

一時的なら以下のコマンドでも変更可能。

```bash:rootで実行
# mount -o remount,size=16M,noatime /run/lock
```

これでバックアップ中でも、iPhoneの同期中でも/run/lockパーティションが溢れずに、
Sambaがパニックにならず、処理が完了できるようになりました。
Heroku で mLab add-on終了による Mongo DB atlas への移行

### 背景
Heroku の Add-on として提供されていた mLab MongoDB が 2020/11/10 終了する事になりました。先日、 mLab がMongoDB, Inc. に買収されたのでそれに伴う動きなります。errbitなどを Heroku でホストしている場合、対応が必要になります。今回の移行プロセスは既存のデータも移行できるプロセスになっています。

#### ObjectRocket for MongoDB 
Heroku からのメールで移行先としておすすめされているのが ObjectRocket ですが、月額46ドル〜となっています。errbit を使っているのはコスト抑えたいからというのが多いと思うので、これは少し厳しい。
https://elements.heroku.com/addons/ormongo

#### 移行先としての MongoDB Atlas
こちらの [PR](https://github.com/errbit/errbit/pull/1472 ) でまとめられたドキュメントがあります。ただし、新規に Heroku ホストすることを前提としていますので、この部分は別の対応が必要です。
https://github.com/errbit/errbit/blob/master/docs/deployment/heroku.md 

そこで、データの移行については下記のドキュメントにまとめられています。
https://docs.mlab.com/shutdown-of-heroku-add-on/

**MongoDB Atlas** であれば無料の範囲で運用できそうです。

### 移行方法

基本はドキュメントのとおりです。

#### アプリケーションを最新バージョンにする
mongodb 4.2系のサポートが必要になるので最新版にしておいてください。

#### MongoDB Atlasのクラスターを作成する

- アカウントを作成しShared Clusterを選択する
<img width="1143" alt="スクリーンショット 2020-07-11 15.34.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/eb0460dc-a150-c8eb-a490-b75dd37e64b9.png">

- M0を選び無料枠でのクラスターを作成する
<img width="917" alt="スクリーンショット 2020-07-11 15.48.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/60748179-ea35-7f88-5fd5-5fad1aed5e3e.png">

- Database Accessからユーザーを作成する。
パスワード認証で、Read and write to any databaseの権限を付与する。
<img width="1513" alt="スクリーンショット 2020-07-11 15.50.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/81e1d743-03c7-1493-e736-0570c371523b.png">


- IPアドレスのフィルターを解除する。
Networwk AccessからAllow Access From Everywhereを選択する。
<img width="1374" alt="スクリーンショット 2020-07-11 15.53.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/10785c1a-0791-ebe9-c551-0ea59963fc88.png">

- Connectから接続情報を取得する。
Rubyの2.5以降を選択する。
<img width="1278" alt="スクリーンショット 2020-07-11 15.55.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/a7914f7b-aa8a-dec1-3ff3-19a5d0fe971b.png">
<img width="636" alt="スクリーンショット 2020-07-11 15.57.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/df589201-157b-8d68-fe2f-ab91b81126c2.png">

#### Heroku側で接続情報を更新する

- 環境変数 MONGODB_URI に上記でコピペした接続情報をコピペする。
<password>と<dbname>のところは適宜書き換える。**注意：環境変数を追加するとダウンタイムが発生します**

```
mongodb+srv://xxx:<password>@xxx.xxx.mongodb.net/<dbname>?retryWrites=true&w=majority
```

#### mLabからMongoDB Atlasにデータ移行

下記のところからmLabにアカウント接続します。
<img width="258" alt="screenshot-atlas-organization-settings.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/836794a7-b580-30ae-ae6d-617254debca8.png">

完了すると MongoDB Atlas のメニューバーに mLab の項目が出るのでそこから migration を実行できます。


#### Heroku側での残り作業

Heroku にログインして mLab のアドオンや環境変数を削除してください。これで移行完了です。移行しない場合は、 `heroku run rake errbit:bootstrap` を実行すれば DB の初期設定ができるかと思います。
vscode・Emmet Snippetでhtml, css, jsxを手っ取り早くかく（備忘録）

もし不明なところや、間違いとかがあればご指摘頂けると幸いです。

## やること

- vscodeに基本提供されているemmet snippetsを使い、手っ取り早くhtml, css,jsxを書くことを試みる
- emmetはどういうものかをざっくり目を通す

## vscodeのEmmet Snippetsとは？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/769e51a5-c5f4-ef85-87a7-4edbd0d778ce.png)

https://code.visualstudio.com/docs/languages/html#_emmet-snippets

vscodeは、基本的にemmetのauto-completionを提供している。

### htmlのauto-completion例

```emmet
ul>li*3>span.hello$
```

を書くと

```html
<ul>
    <li><span class="hello1"></span></li>
    <li><span class="hello2"></span></li>
    <li><span class="hello3"></span></li>
</ul>
```

こういうふうに、HTMLを自動で完成してくれる。

### cssのauto-completion例

```
p10
```

を書くと

```css
padding: 10px;
```

こういうふうに、css属性を自動で完成してくれる。

## Emmetとは
Emmetは既定形式の入力補完機能によりHTML、XML、XSL等を素早く編集できる、テキストエディタ用プラグイン
vscodeは、このプラグインを基本搭載している。

## Emmetでできること

html, css, xslのauto-completion

## Emmet Documents
Cheat Sheetsのいくつかを覚えておくと便利

● Cheat Sheets(html, css, xsl)
https://docs.emmet.io/cheat-sheet/

● Syntax & Documentation
https://docs.emmet.io/abbreviations/syntax/

## jsxでも使えるように設定
reactなどで便利

設定▶拡張機能▶emmet項目でsetting.jsonを開き、以下の設定を追加

```setting.json
{
  "emmet.includeLanguages": {
     "javascript": "javascriptreact"
  }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/c2d719d8-1722-29b8-2b7d-c58c1030b0b8.png)
MySQL EXPLAINの見方

## 概要
先日先輩からSQL流す前に、EXPLAINをつけるようにしてね！
と言われてそのとおり実行したのですが、出力結果の内容を理解していなかったので覚え書き...

## EXPLAINコマンドとは

流したいSQLの前にEXPLAINをつけることで、そのクエリの実行計画をみることができる。
そこで出力された情報をもとにボトルネックを探して、チューニングをしていく。

```
mysql> EXPLAIN select * from users_tbl;
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | users_tbl | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    6 |   100.00 | NULL  |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
```

## 出力結果の見方
### id

SELECT識別子、実行順序を示してる


### select_type

| 値 | 詳細 |
| ------- | ------- |
| SIMPLE | サブクエリやユニオンが含まれていない単純なselect文 |
| SUBQUERY | select文のサブクエリに指定されているselect文 |
| PRIMARY | UNIONの1つめのselect文 |
| UNION | UNIONの２つめ以降のselect文 |
| UNION_RESULT | UNIONの無名一時テーブルから結果を取得するselect文 |


### table
出力の行で参照しているテーブルの名前。

### partitions
クエリが参照したパーティションテーブル。パーティションされていない場合はNULL
※パーティショニングとは、一つのテーブルを分割する機能


### type
テーブルの結合方法

- ALL
  - フルテーブルスキャン
  - インデックスがはられていないため一番遅い

- index
  - フルインデックススキャン
    - インデックスがはられていること以外はALLと同じ、2番目に遅い

- range
  - indexを使用して、範囲検索

- const
  - PKもしくはuniqueキーを参照して検索、一番速い


### possible_keys

テーブルの行検索に使用できるindex。NULLの場合は参照するインデックスがない


### key
MySQLが実際に使用してindex

### key_ren
MySQLが実際に使用したindexの長さ

### ref

行検索の際にindexと比較されるカラムや値。

### rows

クエリ実行のためにMySQLが調査する行数。(行数が多い時は推定値)

### filtered
テーブル条件によってフィルタ処理される行数の割合。

### Extra
MySQL がクエリーを解決する方法に関する追加情報
詳細はhttps://dev.mysql.com/doc/refman/5.6/ja/explain-output.html#explain-extra-information

## まとめ

type=null かつ key=null の場合は、インデックスがはられていないテーブルをフルスキャンしているので、要改善。

EXPLAINやチューニングに関する記事を色々調べていると知らないことばかりだった...
今後はSQL流す前にEXPLAINをつけて実行計画をする習慣をつけたい。
EC2のAWS CLIをver.2にしてみる

EC2の AWS CLI が ver.1 だったので ver.2 にしてみる。


##ver.1のアンインストール
公式ドキュメントとおりにやっていく。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-linux.html#install-linux-bundled-uninstall

```sh:バージョン確認
$ aws --version
aws-cli/1.16.300 Python/2.7.18 Linux/4.14.181-140.257.amzn2.x86_64 botocore/1.13.36
$
```

```sh:アンインストール
$ sudo rm -rf /usr/local/aws
$
$ sudo rm /usr/local/bin/aws
rm: cannot remove ‘/usr/local/bin/aws’: No such file or directory
$
```
2つ目のrmは消すものが該当するファイルがなかった。
環境によってパスが違うのかな？と探してみる。

```sh:find
$ sudo find /usr -name aws
/usr/bin/aws
$
```

/usr/local/bin/aws ではなく
/usr/bin/aws にあったので消しておく。

```sh:アンインストール
$ sudo rm /usr/bin/aws
$
```



##ver.2のインストール
公式ドキュメントとおりにやっていく。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2-linux.html#cliv2-linux-install

```sh:インストールファイルのダウンロード
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 31.5M  100 31.5M    0     0  82.8M      0 --:--:-- --:--:-- --:--:-- 82.8M
$
```

```sh:解凍
$ unzip awscliv2.zip
Archive:  awscliv2.zip
   creating: aws/
   creating: aws/dist/
  inflating: aws/README.md
  inflating: aws/install
    ・
    ・
  (中略)
    ・
    ・
  inflating: aws/dist/include/python3.7m/pyconfig.h
   creating: aws/dist/lib/python3.7/
   creating: aws/dist/lib/python3.7/config-3.7m-x86_64-linux-gnu/
  inflating: aws/dist/lib/python3.7/config-3.7m-x86_64-linux-gnu/Makefile
$
```

```sh:インストール
$ sudo ./aws/install
You can now run: /usr/local/bin/aws --version
$
```

```sh:バージョン確認
$ aws --version
aws-cli/2.0.30 Python/3.7.3 Linux/4.14.181-140.257.amzn2.x86_64 botocore/2.0.0dev34
$
```
最後のバージョン確認で /usr/bin/aws が見つからないといったエラーが過去に1度だけ出たことがあるが、ver.1をアンインストールする前の環境変数でも残っているのかなと思いログインし直したところエラーにならなくなった。今となっては再現しないのでその時ちゃんと調べれば良かった。


##後片付け
不要ファイル（ダウンロードファイル、解凍ファイル）を削除する。

```sh:後片付け
$ ls -l
total 32324
drwxr-xr-x 3 ec2-user ec2-user       78 Jul  9 21:44 aws
-rw-rw-r-- 1 ec2-user ec2-user 33095846 Jul 11 08:06 awscliv2.zip
$
$
$ rm -rf aws awscliv2.zip
$
$
$ ls -l
total 0
$
```
GAS Webpack利用時にエディタが重くならないようにする

# 対象
- Google Apps ScriptでWebpack、Claspを利用してWebアプリケーションを開発している方向け
- 利用しているエディタはVisual Studio Code

# 解決したい課題
WebpackでバンドルしたソースをGASのエディタにアップロードすると、重すぎて開かない...ということが起こります。これの回避を今回したいと思います。

# 結論
Webpackバンドルされたファイルに改行を挿入すれば改善されます。

# 詳細
Visual Studio Code等もそうですが一行の文字数が増えると結構重くなります。GASのエディタもそんな要領で出力されたソースに改行を加えてるとすんなり開けるようになりました。

私の場合の改行の加え方を以下に記載致します

### Visual Studio Codeでバンドルされたソースコードを開く
バンドルされたファイルを開いて下さい。設定によりこの時点の見え方は様々だと思いますが、取り急ぎ開いて下さい。

### Ctrl + Fで置換を実行する
置換で以下のようにして下さい
1. 検索は「;」置換は「;\n」と設定する
2. 一括置換を行う
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633687/8038fd12-53a5-6617-efa8-08c323ef662b.png)
3. Claspでエディタに送信する

上記手順で送信すれば、問題なく開く事が出来ると思います。
※ なお、こんな事をしなくてもWebpackの設定変えればいいじゃん、というご指摘があれば是非頂きたいです。（探したのですが見つからず）

# 注意点
ただし、GASのエディタはそもそも重いソースファイルには不向きにつき勿論沢山バンドルして重たくなったソースに幾ら改行を追加しても重いです。

以上です
Circleciのchromeのバージョンを上げる。

# .circleci/config.yml

こんな感じのステップを追加してアップできました。

```yml

jobs:
  build:
    steps:
    [.....省略]
    - run:
        name: Upgrade chrome
        command: |
          wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
          sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
          sudo apt-get update
          sudo apt-get --only-upgrade install google-chrome-stable=83.0.4103.116-1
```

# きっかけ

システム自体はruby on railで、chrome driverの管理は[webdrivers](https://github.com/titusfortner/webdrivers)を使っています。ローカルのChromeは自動で上がっていくので、webdraiversをアップグレードしないと動かなくなり、あげたら、今度はCircleCIだけテストがコケるようになりました。

RunOverSSHでchromeのバージョンあげたらテスト通ったのでconfig.ymlに反映させました。

滅多にないけど、CircleCIだけコケると時間取られますね。と言っても今日は2時間弱でしたけど。それでもトータルで見るとCircleci的なものを使ったほうが圧倒的に時間の節約になりますが。

# 気がかりなところ

※この方法は**うまくいきません**でした。下部の追記を呼んでください。

あまり自信ないですが、runに書いたことはビルドが起動するたびに実行されるますよね？なので、Chromeのバージョンがどんどん上がっていってしまいそうだと思い、バージョンを指定してみました。

```
sudo apt-get --only-upgrade install google-chrome-stable=83.0.4103.116-1
```

あげたい時はここを変えてやればいいかなと。ただ、想像ですが、

```
deb http://dl.google.com/linux/chrome/deb/ stable main
```

この辺をどうにかしないと最新のstableが更新された時に失敗しだしそうな予感はしますが・・・とりあえず、あまり時間かけたくなかったので一旦このまま行きます。何か知ってる方いましたらコメントお願いします。

バージョンを指定する時`83.0.4103.116`とバージョンナンバーだけ指定すると、`E: Version '83.0.4103.116' for 'google-chrome-stable' was not found`と怒られます。

存在する正確なバージョンナンバーを調べるコマンドは下記。多分次のアップグレードの時必要になるので備忘録にメモしておきます。

```
apt-cache policy google-chrome-stable
google-chrome-stable:
  Installed: 83.0.4103.116-1
  Candidate: 83.0.4103.116-1
  Version table:
 *** 83.0.4103.116-1 500
        500 http://dl.google.com/linux/chrome/deb stable/main amd64 Packages
        100 /var/lib/dpkg/status
```

# 2020/07/19追記

やはりバージョンが上がった瞬間にこけ出しました。

```yml
jobs:
  build:
    steps:
    [.....省略]
    - run:
        name: Upgrade chrome
        command: |
          wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
          sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
          sudo apt-get update
          sudo apt-get --only-upgrade install google-chrome-stable
```

と普通？通りバージョン指定外せば通りますけど、これだと常に最新のChromeでテストすることになりそうですね。

まあ、ローカルもどんどん上がっていくんですけど、CircleCIにしてからローカルでテスト動かさなくなったので、全く関係のないところいじってる時にそこでこけ始めると非常に面倒かなと。あと`webdrivers`のバージョンがChromeのバージョンアップに追いつかない時もあったので、そういう時は数日間通すことが不可能になるんですよね・・・

何か方法ご存知でしたらご教示お願いします。
windowsでiverilog その52

#概要

windowsでiverilogやってみた。
polyphonyで浮動小数点やってみる。
乗算やってみた。

#計算手順

①符号、指数、仮数に分ける。
②指数部同士を足す。
③仮数部同士を掛ける。（２進数の乗算）
④仮数部のbit数をオーバー(オーバーフロー)したら指数部にそれを反映させる。
⑤32bitに組み立てる。

#サンプルコード


```
import polyphony
from polyphony import testbench, module, is_worker_running
from polyphony.io import Port
from polyphony.typing import bit, bit32, bit23, bit24, bit25

@module
class mul:
	def __init__(self):
		self.a = Port(bit32, 'in')
		self.b = Port(bit32, 'in')
		self.c = Port(bit32, 'out')
		self.append_worker(self.worker)
	def float2b(self, a:bit32):
		a_sig:bit = (a >> 31) & 0x1
		a_exp:bit8 = (a >> 23) & 0xff
		a_fra:bit24 = a & 0x7fffff | 0x800000
		return (a_sig, a_exp, a_fra)
	def b2float(self, a_sig:bit32, a_exp:bit32, a_fra:bit32):
		return (a_sig << 31) | (a_exp << 23) | a_fra
	def worker(self):
		while is_worker_running():
			a0:bit32 = self.a.rd()
			b0:bit32 = self.b.rd()
			(a_sig, a_exp, a_fra) = self.float2b(a0)
			(b_sig, b_exp, b_fra) = self.float2b(b0)
			b_exp = a_exp + b_exp - 127
			b_exp = b_exp & 0xff
			fra:bit23
			frac:bit48 = a_fra * b_fra
			frac = frac >> 23
			while (frac & 0xffffff000000):
				frac = frac >> 1
				b_exp += 1
			fra = frac & 0x7fffff
			c0:bit32 = self.b2float(b_sig, b_exp, fra)
			self.c(c0)

m = mul()

@testbench
def test(m):
	m.a.wr(0x3dcccccd)
	m.b.wr(0x3f800000)
	print ("0.1 * 1.0") #3dcccccd
	c = m.c.rd()
	print('{:08x}'.format(c))
	m.a.wr(0x3dcccccd)
	m.b.wr(0x40800000)
	print ("0.1 * 4.0") #3ecccccd
	c = m.c.rd()
	print('{:08x}'.format(c))

test(m)





```

#python実行結果


```


0.1 * 1.0
3dcccccd
0.1 * 4.0
3ecccccd


```

以上。
Vuexでstoreのstateを初期化する

## はじめに
Vuexを使用しているとき、ログアウト処理などでstoreのstateを初期状態に戻したいことがあると思います。いくつかやり方はあると思うのですが、私が手軽だと思った情報を記載します。

## 方法
こんな感じです。実際に利用する際はactionsなどから呼び出すことになると思いますが、ここでは最低限のコードのみ記載しています。
[こちら](https://tahazsh.com/vuebyte-reset-module-state)を参考にしました。参考というよりそのまま持ってきただけですが。。



```javascript:store/sample.js

// stateの初期値としたい任意のデータを定義する
function getDefaultState() {
  return {
    idToken: null,
    uid: null
  }
}

// stateを初期化する
export const state = getDefaultState()

export const mutations = {
  // stateを初期化するmutationを定義
  clearAuthData(state) {
    Object.assign(state, getDefaultState())
  }
}

```

## おわり
とくに問題ないと思っていますが、何かご指摘あれば教えてくださいm(__)m
Java StringBuilderクラスについて

StringBuilderクラス、の『クラス』とは、Javaに標準装備されている機能のこと、という理解で正しいでしょうか？

また、「プログラムを実行するための処理をまとめたオブジェクト」、という意味のクラスとは別の用語なのか否かも教えて欲しいです。

拙い投稿申し訳ありません。
OneDrive上のファイルをwgetする

# この記事の概要
FTPやSCPが使えない（or 使えるようにするのがめんどくさい）環境間でOneDrive経由でファイル連携をする

# 前提環境
- wget

```
wget --version
GNU Wget 1.14 built on linux-gnu.
```

# 手順
## OneDriveにアップロードしたファイルを共有可能にする
Webインターフェース上で操作します。

対象のファイルを右クリックして「共有」を押下します。
![2020-07-11 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556115/d2f698ee-cb1f-1392-c770-269c37f1d09a.png)

## ファイルのダウンロードURLを生成する

再度対象のファイルを右クリックして「埋め込み」を押下します。
![2020-07-11 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556115/55343c3f-b7ab-3459-8966-bfb4868c5d2f.png)

「生成」を押下します。
![2020-07-11 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556115/7c080549-ddcb-0707-c715-99ab7ae85ad6.png)

生成された埋め込みタグの```src```属性にURLが定義されています。
このURLの```embed?```を```download?```に書き換えます。

```
https://onedrive.live.com/embed?cid=xxxxx
    ↓
https://onedrive.live.com/download?cid=xxxxx
```

書き換えたあとのURLがダウンロードURLになります。

## wgetする
ファイルを連携したい先でwgetします。
URLはシングルクオートで囲む必要があります。

```
wget 'https://onedrive.live.com/download?cid=xxxxx' -O <ファイル名>
```

これでダウンロード完了です。

# まとめ
わざわざ環境を整えるほどじゃないときにけっこう便利です。
OneDriveに上げられないくらいデカイファイルなら素直にFTPしましょう。
Rust で HashMap にループで値を代入

HashMap にループで値を代入する方法です。

```rs:hash01.rs
// --------------------------------------------------------------------
/*
	hash01.rs

						Jul/11/2020
*/
// --------------------------------------------------------------------
use std::collections::HashMap;

// --------------------------------------------------------------------
fn main(){

	eprintln! ("*** start ***");

	let mut unit_aa:HashMap <String,f64> = HashMap::new ();

	for count in 0..5 {
        	let key = "key_".to_owned() + &count.to_string();
        	unit_aa.insert(key, count as f64);
		}

	println!("{:?}",unit_aa);

	eprintln! ("*** end ***");
}

// --------------------------------------------------------------------
```

```text:Makefile
hash01: hash01.rs
	rustc hash01.rs
clean:
	rm  -f hash01
```

コンパイル

```bash
make
```

実行結果

```text
$ ./hash01 
*** start ***
{"key_4": 4.0, "key_0": 0.0, "key_2": 2.0, "key_1": 1.0, "key_3": 3.0}
*** end ***
```
リリースで失敗しないために「リリース作業品質」を確保する（１）

リリース、カットオーバー、ローンチ、デプロイ・・・・呼び方はともかく、リリースはSI作業の中で最も気を使います。リリースに失敗してシステムが利用できなくなったり、データが消えてしまったりすると、ユーザーに迷惑がかかるだけでなく、開発者側にも大きな負担が発生するからです。ソフトウェア本体の開発と比べると軽視されがちですが、失敗したことがない人はいないぐらいとても難易度の高い作業です。

そこで、失敗すると生命や財産に多大な影響が発生するミッションクリティカルなシステムのリリースルールから、失敗を防ぐためのポイントを探ってみましょう。

# 環境
ミッションクリティカルなシステムのリリースルールを運用するためには、土台となる3つの環境が必要になります。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670191/6ea5074b-d4a7-4ba9-9afb-09127441b626.png)

### 開発環境
普段、開発を行う環境です。PCやサーバといったコンピューター類だけでなく、VPNやLANといったネットワーク、ストレージもセットで構成されているのが一般的です。ネットワーク的には、外部から侵入できないようになっています。ここでリリース対象物のテストまで行います。

### ステージング環境
ステージング環境はリリース対象物を開発環境からいきなり本番環境に適用するのはリスクが大きいので、予めリリースについて検証するための環境です。基本的に本番環境と同一のシステム構成ですが、予算の関係から最低限の構成となっている場合が多いと思います。この環境で、リリース対象物が適切であること、リリース手順が想定通りであること、リリース後にシステムが正常に動作することを担保します。

### 本番環境
実際にユーザーが利用する環境です。商用環境、プロダクション環境と呼んだりもします。ステージング環境で担保されたリソースや手順を用いてリリース作業を行います。

3つの環境は論理的に、場合によって物理的に分かれていて、互いに干渉しないようになっています。でないと、開発環境を触っていると思ったら実は本番環境だった・・・なんてことが起こりかねません。予算の都合上、開発環境とステージング環境が同一であることもあります。

## ポイント
以前、[日経SYSTEMSの記事](https://shop.nikkeibp.co.jp/front/commodity/0000/OS0215/)にも書いたことがあるのですが、なによりもまず__運用の品質を開発段階にて作り込む__のがポイントです。精緻なリリース計画や正しい手順の実施以前に、仕組みとして運用品質を作りこむのです。そのためには、必ずしも独立した環境を用意する必要はなく、例えば実際のプログラムや本番環境にステージング用動作確認モードを予め機能として埋め込んでおけば良いのです。

# ルール
以上を踏まえ、ミッションクリティカルなシステムのリリースルールを見ていきましょう。リリースルールは大まかに分けて以下の6つに大別できます。
- 計画する
- 作業の前提条件を確認する
- 手順、パラメーター、ファイル等を全て揃える
- 作業を実施する
- 動作確認をする
- 何かあったらすぐに元に戻す

（つづく）
FlutterのiOSアプリで、端末のエッジ部分の onTapDown が遅延する

## 経緯

とあるアプリの開発で、ユーザのタップ操作に即座に反応する必要があり、画面の左右にボタン領域を用意して、 `onTapDown` でイベントをハンドリングしようとしました。
iOS simulatorで確認しているところでは上手く動いていたのですが、iPhone XRなどの実機で確認してもらうと、「画面を押した瞬間に反応せず、コンマ数秒経ってから反応しているように見える」という指摘があり、調査しました。

状況としては、以下の動画のようなイメージです。

![d0fme-7zyqw.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8708/6abce06d-30dc-abd8-86ad-e6f02b7e4ac5.gif)

最初の2タップは、比較的中央寄りをタップしているので、指が触れた瞬間ぐらいでテキストの行が増えています。
次の2タップは、意図的に画面端をタップしており、タップした瞬間から500msecぐらい遅れて行が増えています。

調査していくと、iOSのOS側の制御として「エッジに触れられたときには、OSのジェスチャーかもしれないから、アプリにイベントを渡すのは少し待つ」的な動作がありそうでした。

そして、iOSの `preferredScreenEdgesDeferringSystemGestures` にて `[.left, .right]` を返せば良さそう、、、という記事も発見したのですが、今回の開発ではFlutterを利用していたため、UIViewControllerが露出しておらず、継承してそれを利用する方法がわかりませんでした。

## 解決策

調べていくと、Flutterで利用されている UIViewController は、 `FlutterViewController` ということがわかりました。

また、同僚からのアドバイスで、 `extension` を使ってみました。

結果としては、 `{project dir}/ios/Runner/AppDelegate.swift` の末尾に、以下の記述を追加することで改善しました。

```
public extension FlutterViewController {
    override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge {
        return [.left, .right]
    }
}
```

改善後の動画です。

![59v1n-f7upv.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8708/580bd1dc-b432-ca6d-e2ef-d5b7ee809df2.gif)

こちらも、上の動画と同様に、最初の2タップは中央寄り、次の2タップは端をタップしていますが、どちらもタップした瞬間に反応しています。

## その他

同じように、 `preferredScreenEdgesDeferringSystemGestures` にて `[.bottom]` を返すと、1度はホーム画面への遷移を防げます。

![5jlyk-lvypl.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8708/0ca72f91-7389-25c5-20cc-bc6b6ed587f3.gif)

一般的なアプリで実装されているとただ迷惑ですが、ガチャガチャ操作するようなゲームなどでは、この指定をしても良いかもしれませんね。

## その他2

多くのアプリでは、こういった制御が必要になったとしても、特定の画面のみかと思います。
Flutterパッケージを作成し、 `preferredScreenEdgesDeferringSystemGestures` が返す値を変数化、Flutterアプリ側からの呼び出しでその変数を書き換え、 `setNeedsUpdateOfScreenEdgesDeferringSystemGestures` を呼び出してやる、、、というのが良さそうではあります。