OmniAICreator/Qiita-1.07M huggingface dataset:
Windowsで通知を出す神パッケージ「zroya」を見つけた話

# Windowsで通知したい
監視アプリやトレイアプリで通知をしたいとき、丁度いいパッケージを見つけられませんでした
一応、[WinAPI](http://blog.sbfm.jp/archives/137)とか[Powershell](https://quzee.hatenablog.com/entry/2019/01/14/014959)とか使えば出来るんですが、[^1]

- Python3で
- Windowsで
- Cpython・Powershellを使わずに
- Pythonのパッケージを使って
- 数行で
- トースト通知を出す

という条件だと中々ヒットしないんです…

# そんな貴方にzroya！
悩むこと数ヶ月、ついに[zroya](https://malja.github.io/zroya/)というパッケージを見つけました
[WinToast](https://mohabouje.github.io/WinToast/)というC++ライブラリを使ってるみたいです
~~まぁ結局Cpython使ってるようですが、使いやすいならOKです~~

# インストール
pipで入ります

```
pip install zroya
```

# 使い方
基本的には[公式ドキュメント](https://malja.github.io/zroya/in_action.html)見ればいいので、ここでは基本的な使い方を簡単にまとめます。

## シンプルに通知
```Python3
import zroya

zroya.init("Python", "a", "b", "c", "d")
t = zroya.Template(zroya.TemplateType.Text1)
t.setFirstLine("Just one bold line")
zroya.show(t)
```
結果
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244946/32f81b44-831d-8ca6-6188-b604811833b7.png)



## アイコン付き複数行で通知
今回は[これ](https://www.irasutoya.com/2013/12/blog-post_1838.html)を使います

```Python3
import zroya

zroya.init("Python", "a", "b", "c", "d")
t = zroya.Template(zroya.TemplateType.ImageAndText4)
t.setFirstLine("First bold line")
t.setSecondLine("Second line is in regular font")
t.setImage("cut_vegetable_cabbage.png")
zroya.show(t)
```
結果
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244946/eec7bed8-0e2d-c0ce-7c49-c437d4ecba13.png)

## 通知をクリックされたときのイベント付き
```Python3
import zroya
import time

def onClickHandler(notification_id):
    print("Clicked!")

zroya.init("Python", "a", "b", "c", "d")
t = zroya.Template(zroya.TemplateType.Text1)
t.setFirstLine("Click on me, please!")
zroya.show(t, on_click=onClickHandler)
time.sleep(10)
```
結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244946/21e7ee1f-ecb6-c2c2-5fd2-a92670a2bcf3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244946/acadd36e-015a-f9b0-6bfb-206ab81005ee.png)
`Cpp: EventHandler: Activated: なんたらかんたら`って出てるのが気になる人、下のやつを指定すると何故か消えます

# 通知の送信元をpython.exe以外にしたいとき
上記の`zyora.init()`を以下にします

```Python3
status = zroya.init(
    app_name="NotifyBot",
    company_name="MyBotCorp",
    product_name="NoBo",
    sub_product="core",
    version="v01"
)

if not status:
    print("Initialization failed")
```
結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244946/fd9f2462-4fb4-0c38-1e04-c88c0e81914b.png)
アクションセンター[^2]の表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244946/11a4e8ae-b3cf-bfd4-7c72-158725e3f528.png)

# 注意
## 通知が表示されないとき
上記サンプルコードだけを実行すると、通知が表示されません
恐らく通知を送信してから表示するまでの間にラグがあり、その間にPythonが終了してしまうためだと思います
その場合、最下部に

```Python3
from time import sleep
sleep(1)

```
を入れると表示されます。

## それでも表示されないとき
[ここ](https://malja.github.io/zroya/tutorials/index.html#troubleshooting)を参考に設定を見直してください


[^1]: WinAPIはソースが長すぎて使いづらく、Powershellは個人的に嫌いです
 まぁ使いやすいようにクラスかパッケージを書けばいいだけなんですが…凄まじくめんどくさい…
[^2]: 右からスッと出てくる、通知一覧と他諸々があるやつです
gulp3からgulp4へのバージョンアップ手順

# はじめに
gulp3から4へバージョンアップで少しハマりどころがありましたので備忘録がてら手順をまとめます。

# 前提
* 過去にgulp3をインストールしたことがある
* バージョンアップ後は(執筆時点で) `4.0.2` となります。

# 手順
1.現状確認
グローバル（CLI）のバージョンを確認します。
`3.9.1` になっている際は少し注意です。 `2.2.0` の場合は手順5へスキップください。

```
$ gulp -v
CLI version: 3.9.1
Local version: 3.9.1
```
通常であれば `sudo npm rm -g gulp`等 で削除されるのですが、不具合なのか何なのか削除されない事象に遭遇しました。
この様な場合はgulpのバイナリを直接削除する強硬手段で対応します。
**削除できない方は手順2以降をご覧ください。**

2.gulpのbinのパスを確認

```
$ whereis gulp
gulp: /usr/bin/gulp /usr/local/bin/gulp /usr/share/man/man1/gulp.1.gz
```

3.パスを見つけたら削除（または解除）
２で抽出されたパスがファイルもしくはシンボリックリンクかで適宜コマンドを走らせてください。

```
$ sudo rm /usr/bin/gulp /usr/local/bin/gulp /usr/share/man/man1/gulp.1.gz
または
$ sudo unlink /usr/share/man/man1/gulp.1.gz
```

4.グローバルでgulp-cliをインストール

```
$ sudo npm install --global gulp-cli
```

5.ローカルのgulpをバージョンアップ

* package.jsonで `"gulp": "^4.0.2"`で指定している場合は jsonファイルが存在するディレクトリ位置で `npm i`を実行
* コマンドから直接インストールする際は `npm i --save-dev gulp@4.0.2` または `npm i --save gulp@4.0.2` 等を実行

6.バージョン確認

```
$ gulp -v
CLI version: 2.2.0
Local version: 4.0.2
```

# 最後に
gulpfile.jsの記法もだいぶ変わる様なので、詳細は[公式サイト](https://gulpjs.com/docs/en/getting-started/creating-tasks/)をご覧ください。
誰かの助けになれば幸いです。

# 引用
[How to uninstall CLI version 3.9.1?](https://github.com/gulpjs/gulp-cli/issues/178)
Option型に対するmapとflatMapの違い

# 背景
scalaの勉強をしていく中で、mapはよく使うメソッドだと思います。自分もJSをずっとやっていたので配列をみるととりあえずmapかああとなります。
scalaにはOption型というものがあり、それにもmapを使うことができてflatMapとの違いが面白いなあと思ったので簡単にまとめます。

#map
簡単に書きます。

```scala
val msgOpt: Option[String] = Some("a")
val mappedMsgOpt = msgOpt.map(msg => msg)

println(mappedMsgOpt) // Some("a")

```
Option型に対してmapをして、値を返すだけです。
ここで言いたいことは**map は文脈を保ったまま、ふつうの値を取ってふつうの値を返す関数を適用する**ということです。
そして最終的にはOptionに包まれて返ってきます。

#flatMap
ここも簡単に書きます。

```scala
val msgOpt: Option[String] = Some("a")
val flatMappedMsgOpt = msgOpt.flatMap(msg => Some(msg))

println(flatMappedMsgOpt) // Some("a")
```
結果としては同じですが、flatMapの中の関数がmapとは違います。
flatMapは**必ず文脈を保ったまま計算をする**ということです。
flatMapの中の関数は文脈を保ってなければいけません。

```scala
val flatMappedMsgOpt = msgOpt.flatMap(msg => msg) // エラー
```
こう書いてしますとStringが返ってくるため、Optionという文脈が保たれたいのでエラーになります。
Optionという文脈さえ保たれていれば、対象が変わっても問題ないのがflatMapの特徴です。

```scala
val flatMappedMsgOpt = msgOpt.flatMap(msg => Some(1))
```
意味のないことをしていますが、Stringで受け取ってIntで返すといったこともできます。

#両者共通
mapとflatMapに共通するものとして、Noneを受け取った場合があります。

```scala
val msgOpt: Option[String] = None

val flatMappedMsgOpt = msgOpt.flatMap(msg => Some(1))
println(flatMappedMsgOpt) // None

val mappedMsgOpt = msgOpt.map(msg => msg)
println(mappedMsgOpt) // None
```
Noneだった場合は処理が行われずスキップされNoneが返されます。

#まとめ
mapとflatMapの違いについて整理することができました。
Option型をうまく扱えるようになりたいですね。
#Ralls の Controller で パラメータ付きのURLを得るには request.url  ( query string params with full URL )

# 例

```rb
request.url
#  "http://www.example.com/v1/users?page=1&ffilter[foo]=bar"
```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3072








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Anaconda Prompt起動時にディレクトリと環境を指定する（Windows 10）

Anacondaで開発をしていると、
Promptを立ち上げるたびに環境変えてディレクトリ移動してという作業がつらいので
デフォルトのディレクトリと環境を変更できないかと調べていました。

バージョンの違いなのか、いまいち解決方法が見つからなかったのですが、
下記のスレッドの中にショートカットの設定でprompt起動時に起動ディレクトリと環境を変更する方法が投稿されていました。
[How to change default Anaconda python environment](
https://exceptionshub.com/how-to-change-default-anaconda-python-environment.html)

## 環境
- Windows 10(64 bit)
- Anaconda 2020.02

## 指定方法
まずAnaconda Promptのファイルロケーションを開きます。
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31194/31e94c1f-5397-4b8c-fd12-841a9507e95b.png' width='70%'>
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31194/d5823009-ab72-1725-6175-256794afc339.png' width='70%'>

するとショートカットがあるので、Anaconda Power Shell Prompt(anaconda3)を右クリックしてプロパティを表示します。
![コメント 2020-04-15 092458.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31194/2d49cc26-1c9b-7e49-4b5d-6e2839f4ea66.png)

**Target**が環境の指定で**Start In**が起動ディレクトリの指定になっています。

### 環境
初期では下記の様に、最後の方にactivateのコマンドが記載されています。

```
%windir%\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy ByPass -NoExit -Command "& 'C:\Users\{user}\anaconda3\shell\condabin\conda-hook.ps1' ; conda activate 'C:\Users\{user}\anaconda3' "
```
この部分ですね。

```
conda activate 'C:\Users\{user}\anaconda3'
```
これを下記の様にすればPrompt実行時に指定した環境に切り替えを行ってくれます。

```
conda activate 'C:\Users\{user}\anaconda3\envs\{環境}'
```

### ディレクトリ
これは単純に**Start In**に初期のディレクトリを入れてあげれば、Prompt起動時にそのディレクトリに移動してくれます👍
composer installまでの道のり

#初めに
業務でcomposerを使うことがあったのですが、Windowsユーザーがほとんどでmacの環境でドキュメントが書かれていなかったのでインストールまでの手順

- macOS Catalina 10.15.4

#Homebrewから
エンジニアなら当たり前のように入ってると思うのですが一応

```terminal
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

(中略)

$ brew doctor
Your system is ready to brew
```

終わり

#composerをインストールしよう！

```Terminal
#composerをインストールする
$ curl -sS https://getcomposer.org/installer | php

#/usr/local/bin/composerに移動させる
$ sudo mv composer.phar /usr/local/bin/composer

$ composer --version
Composer version 1.10.1 2020-03-13 20:34:27

$ composer install
```

これで終わり！
あなたも快適なPHPライフを

#余談
ようやく新生活が始まったんですが、僕の会社はリモートです（というかほとんどそうか・・・）
入社式もリモートでしたね。

話が180度変わって新しいMacBookPro買いました
13インチのやつ。
16GBにカスタマイズしたのですがビュンビュン動いてくれてありがたい。
MacBook出ないかなーって楽しみにしてたのですが、Airが先に出てしまったので仕方なく・・・
人気ないのかな・・・
railsで二つのモデルに共通のタグを関連づけるときの選択肢

# この記事でやること

* tagはtoxi法で実装（ https://qiita.com/you8/items/b2394104c6f9865f5d46#toxi%E6%B3%95 ）
* 二つのモデルの投稿フォーマットを共通のタグに関連づける

# 選択肢

* STIで一つのテーブルに二つのモデルをいれる
* tag_mapテーブルをそれぞれ用意する
* tag_mapに二つのidカラムを用意

## STIで一つのテーブルに二つのモデルをいれる

STIはこの記事が分かりやすい

「railsでSTIの使い方」
http://mikamisan.hatenablog.com/entry/2016/06/05/152738

メリットはtableを新しく作らなくていいというところだがデメリットとしてtableが肥大化するというのがある。

## tag_mapテーブルをそれぞれ用意する

![副業Q-A-10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193389/f4ef5453-e61e-d833-4fa6-ffdc27987bb0.jpeg)

上記のような設計にする。

メリット

* tableが肥大化しない
* modelを別々にできるのでそれぞれシンプル

デメリット

* 一緒にランキング計算やインデックスで出したいときに別々に処理を書かないといけない

## tag_mapに二つのidカラムを用意

片方がnullになる設計だがなんか気持ち悪い。。。
まだ自宅でipv4していますか？(テレワーク時代のwifi + ipv6ネットワーク)

# はじめに
このご時世、この2週間はほぼ自宅からネットワークを使っていますが、ふと、家のネットワークが遅いのではと思い、スピード計測サイトで測ってみると、恐ろしく残念な結果に。自宅のネットワークは、ありがちな「フレッツ光マンションタイプ」というもの。開通した当初に測ったときは、こんな数字ではなかったのですが。
ということでプロバイダーとやりとりして、初めてわかったことがいくつかあり、ここにメモとして残しておくことにしました。

# 結論
いろいろ紆余曲折があったのですが、結論として問い合わせ前からの変更を最短でやるとどうなる、という手順をまとめます。
スピード測定サイトの数字はよくはなりました。しかし、測定サイトにより数字が極端に異なる結果に。この理由はまだ解明できていません。おいおい調べることにします。
一連の変更をすることで、WiFiルータ経由でインターネット接続をしている場合、PC側の設定は一切せずに、結果的にipv6による高速ネットワークを使えるようになるみたいです(ipv4 over ipv6 トンネリング)。

## アクション1 WiFiルータの機種変更
最初のアクションはWiFiルータの機種変更です。
私の場合、元々 **Aterm WG1900HP** だったのを、同じ会社の最新機種である **WG1800HP4** に変更しました(このあたりの商品もご多分に漏れず品切れ状態で、私は在庫ぎれ直前にヨドバシ通販で入手しました)。
以下に対応ルータのリストがあります。

https://v6-hikari.net/v6-router/

## アクション2 契約の変更
そもそも、今回のことをするためには、プロバイダー側で、「**ipv6プラス**」と呼ばれるサービスを提供している必要があります。私のプロバイダーは対応していました(だから勧められたわけですが)。申請はネットで可能で、開通まで1日かからなかったと記憶しています。初期費用・ランニング費用含めて追加費用はゼロでした。

## アクション3 WiFiルータの設定変更
### ipv6プラスモードへの変更
機種によっては、ルータ側でこの設定変更をする必要があるみたいですが、WH1800HP4では、自動的に検知して勝手にipv6プラスモードになっていました。

### オートチャネル変更OFF
新しい機種になって基本的な通信速度は速くなったのですが、1日に1回程度の頻度でWiFiがまったく使えないなる事象が発生しました。再度メーカーに問い合わせて戻ってきた指示がこちら(5GHzの詳細設定)。設定後の管理画面も添付しておきます。

![スクリーンショット 2020-04-15 8.45.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/961fdcd1-1be3-b18f-2b62-5c49dd6b711d.png)

ちなみに、この問題はメーカーサポートデスクによると「レーダー波検出による、DFS機能により強制的に無線チャネルの切り替え」なのだそうです。細かい話は全然わかっていないので、おいおい調べてみたいと思います。

参考文献

https://www.nic.ad.jp/ja/newsletter/No37/0800.html

https://www.ntt.com/business/services/network/internet-connect/ocn-business/bocn/knowledge/archive_13.html
Google Cloud Platform (GCP)サービスの正式名称・略称・読み方まとめ#15(ネットワーキング)

Google Cloud Platform (GCP)のサービスで正式名称や略称はともかく、読み方がわからずに困ることがよくあるのでまとめてみました。


クラウド コンピューティング サービス  |  Google Cloud
https://cloud.google.com/?hl=ja



## まとめルール

まとめルールについては下記を参考ください。

Google Cloud Platform (GCP)サービスの正式名称・略称・読み方まとめ#1(AI と機械学習/AI ビルディング ブロック) - Qiita
https://qiita.com/kai_kou/items/fa930eef23470c2f8f0b


## Amazon Web Services (AWS)のまとめはこちら！

Amazon Web Services (AWS)サービスの正式名称・略称・読み方チートシート - Qiita
https://qiita.com/kai_kou/items/cb29d261c8acc49fd22a

Amazon Web Services (AWS)サービスの正式名称・略称・読み方まとめ #1 (コンピューティング) - Qiita
https://qiita.com/kai_kou/items/a6795dbab7e707b0d1a6


## 概要について

サービス一覧ベージの概要を引用しています。

プロダクトとサービス  |  Google Cloud
https://cloud.google.com/products?hl=ja#product-launch-stages


間違いや、こんな呼び方あるよーなどありましたらコメントお願いします！


## Networking - ネットワーキング

### Cloud Armor

DoS 攻撃やウェブ攻撃からサービスを守ります。

- 正式名称: Google Cloud Armor
- https://cloud.google.com/armor
- 読み方: グーグル クラウド アーマ
- 略称: なし
- 俗称: なし


### Cloud CDN

Google のグローバル ネットワークでコンテンツを配信します。

- 正式名称: Cloud CDN
- https://cloud.google.com/cdn
- 読み方: クラウド シーディーエヌ
- 略称: なし
- 俗称: なし


### Cloud DNS

信頼性と復元性に優れ、レイテンシの低い DNS サービス。

- 正式名称: Cloud DNS
- https://cloud.google.com/dns
- 読み方: クラウド ディーエヌエス
- 略称: なし
- 俗称: なし


### Cloud Load Balancing

高性能でスケーラブルな負荷分散。

- 正式名称: Cloud Load Balancing
- https://cloud.google.com/load-balancing
- 読み方: クラウド ロード バランシング
- 略称: なし
- 俗称: なし


### Cloud NAT

GCP のマネージド型高性能ネットワーク アドレス変換。

- 正式名称: Cloud NAT
- https://cloud.google.com/nat
- 読み方: クラウド ナット
- 略称: なし
- 俗称: なし


### Google Cloud Hybrid Connectivity

条件に合わせて、どこからでもインフラストラクチャを GCP に接続できます。

- 正式名称: Google Cloud Hybrid Connectivity
- https://cloud.google.com/hybrid-connectivity
- 読み方: グーグル クラウド ハイブリッド コネクティビティ
  - 参考: [コネクティビティ\(こねくてぃびてぃ\)とは \- コトバンク](https://kotobank.jp/word/%E3%82%B3%E3%83%8D%E3%82%AF%E3%83%86%E3%82%A3%E3%83%93%E3%83%86%E3%82%A3-3424)
- 略称: なし
- 俗称: なし


### Network Intelligence Center

包括的なネットワーク モニタリング、検証、最適化プラットフォーム。

- 正式名称: Network Intelligence Center
- https://cloud.google.com/network-intelligence-center
- 読み方: ネットワーク インテリジェンス センター
- 略称: なし
- 俗称: なし


### NETWORK SERVICE TIERS

ネットワークのパフォーマンスやコストを最適化します。

- 正式名称: NETWORK SERVICE TIERS
- https://cloud.google.com/network-tiers
- 読み方: ネットワーク サービス ティア
- 略称: なし
- 俗称: なし


### Network Telemetry

サービスの安全性を維持する詳細なネットワーク テレメトリー。

- 正式名称: Network Telemetry
- https://cloud.google.com/network-telemetry
- 読み方: ネットワーク テレメトリー
- 略称: なし
- 俗称: なし


### Traffic Director

エンタープライズに対応したオープン サービス メッシュ用トラフィック管理。

- 正式名称: Traffic Director
- https://cloud.google.com/traffic-director
- 読み方: トラフィック ディレクター
- 略称: なし
- 俗称: なし


### Virtual Private Cloud (VPC)

GCP リソース用の VPC ネットワーキング。

- 正式名称: Virtual Private Cloud
- https://cloud.google.com/vpc
- 読み方: バーチャル プライベート クラウド
- 略称: VPC
- 俗称: なし
いまさら CentOS8 で 内向きDNS(unbound)を建てる


自宅のネットワーク環境で BIND 建てているけどお手軽に「内向きDNS, キャッシュサーバ」ということで unbound を導入してみました。今更感が凄いですね～実際は自分の備忘録ですｗ

# 内向きDNS（DNSキャッシュサーバにunbound）を建てる
unbound だけでなく折角なので dig, nslookup もインストールしておきます。
設定内容ですが色々な方のサイトを見ると `unbound.conf` を直接変更する方法がとられていますが [unbound.conf(5)](https://unbound.jp/unbound/unbound-conf/) を見ると、 "include:ディレクティブを使ってファイルを取り込むことができます…（以下略）" とのことですので個別設定ファイルは `/etc/unbound/conf.d` の下に作成するようにします。

まずは unbound のインストール。 `bind-utils` も指定しているのは dig, nslookup コマンドを使用できるようにするため。

```
# dnf install unbound bind-utils
```

unbound 全体の設定 ※unboundサーバを `192.168.11.111` とします。

```/etc/unbound/conf.d/my_unbound.conf
server:
    interface: 0.0.0.0
    do-ip4: yes
    do-ip6: no
    do-udp: yes
    do-tcp: yes

    access-control: 0.0.0.0/0 refuse
    access-control: 127.0.0.0/8 allow
    access-control: 192.168.11.0/24 allow

    hide-version: yes
    hide-identity: yes

    logfile: "/var/log/unbound.log"
    use-syslog: no
    log-time-ascii: yes

forward-zone:
    name: "."
    forward-addr: 8.8.8.8
    forward-addr: 8.8.4.4
```

この段階で `unbound-checkconf` を実行し定義ファイルに誤りが無いことを確認する。
サーバ証明書が無い！と下記のエラーが表示される場合は `unbound-control-setup` コマンドで証明書を作成し再度 `unbound-checkconf` を実行してエラーが発生していないことを確認する。

```
# unbound-checkconf
/etc/unbound/unbound_server.key: No such file or directory
[1585546626] unbound-checkconf[8958:0] fatal error: server-key-file: "/etc/unbound/unbound_server.key" does not exist
```

あ。log ですが `logfile: "/var/log/unbound.log"` としているのでファイルを作っておきます。

```cmd
# touch /var/log/unbound.log
# chmod 666 /var/log/unbound.log
```

もちろんローテーションしておかないとパンクしちゃうので設定しときます。
・[Unboundで内向きDNSを建てる](https://jyn.jp/unbound-internal-dns/)


# ローカルの正引き,逆引きの設定
`/etc/unbound/conf.d` の下に作成します。 `unbound` を再起動します。

```my_hosts.conf
server:
    local-data: "nas. IN A 192.168.11.138"
    local-data-ptr: "192.168.11.138 nas."
```

resolv.conf の nameserver は `127.0.0.1` を指定する。

```/etc/resolv.conf
nameserver 127.0.0.1
```

DNSを指定して 正引き,逆引き ができるか確認する。

```
$ nslookup nas 192.168.11.111 ※unboundを設定したIPアドレス
$ nslookup 192.168.11.138 192.168.11.111 ※unboundを設定したIPアドレス
```

同一ネットワーク内の他のマシンからも同様のコマンドで `nslookup` できることを確認する。
time outエラーが発生する場合は、port:53 が空いてないので穴あけする。

```cmd
# firewall-cmd --permanent --zone=public --add-service=dns
# firewall-cmd --reload
# firewall-cmd --list-all
```

よし、よさげに設定できた！


# 参考にさせて頂いたサイト様
・[構築事例：unboundによるDNSキャッシュサーバ](https://www.designet.co.jp/system/oss.php?category=dns&id=1&oss=unbound)
・[Unboundで内向きDNSを建てる](https://jyn.jp/unbound-internal-dns/)
・[Unboundを使ってみよう](https://tech-lab.sios.jp/archives/12903)
OpenID Connect Adminメモ

#OpenAM Adminメモ
ドキュメントリンクのメモです。
OpenID Connectについてはまた別途まとめられればと思います。
誤り等ございましたら、ご指摘いただければ幸いです。

##OpenAMでサポートしているFlow

###[OpenID Connect Authorization Code Flow](https://backstage.forgerock.com/docs/openam/13/admin-guide/index.html#chap-openid-connect)
サーバーサイドアプリケーション向け
![openid-connect-basic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256703/468cc8b6-f74f-3268-7124-356002353629.png)
有効なアクセスtokenを使用して、UserInfoエンドポイントから
プロファイル、email、住所、電話の詳細などのユーザー情報を取得する方法も定義される。

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f34323235302f61393139343863312d396664612d366232302d313433352d6237353936346530306134632e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256703/ab167474-815a-75b5-fec8-b5c49517a6cd.png)


###[OpenID Connect Implicit Flow]()
ネイティブアプリケーション向け
今回は学んでいないので省略

#OpenAM Developersガイド
##[OpenID Connect 1.0](https://openid.net/connect/)
OpenID Connect 1.0はOAuth 2.0を拡張し、クライアントがエンドユーザーのIDに関するクレームを確認し、エンドユーザーに関するプロファイル情報を取得し、OpenAMセッションの終了時にユーザーをログアウトできるようにします。

OpenAMは、OpenID Connect 1.0の目的で次のRESTエンドポイントを公開します。

Endpoints for discovering information.

An endpoint for registering client applications.

Endpoints for client authorization.

Endpoints for session management.

##その他重要事項
###[OpenID Connect Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html)
プロバイダに関する情報を取得するための仕様

`OpenID プロバイダーの発行者識別子 (https:// で始まる URI)/.well-known/openid-configuration`
に HTTP GET リクエストを投げると、サポートしているclaimなどが確認できる

```//accounts.google.com/.well-known/openid-configuration
{
 "issuer": "https://accounts.google.com",
 "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
 "token_endpoint": "https://oauth2.googleapis.com/token",
 "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
 "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
 "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
 "response_types_supported": [
  "code",
  "token",
  "id_token",
  "code token",
  "code id_token",
  "token id_token",
  "code token id_token",
  "none"
 ],
 "subject_types_supported": [
  "public"
 ],
 "id_token_signing_alg_values_supported": [
  "RS256"
 ],
 "scopes_supported": [
  "openid",
  "email",
  "profile"
 ],
 "token_endpoint_auth_methods_supported": [
  "client_secret_post",
  "client_secret_basic"
 ],
 "claims_supported": [
  "aud",
  "email",
  "email_verified",
  "exp",
  "family_name",
  "given_name",
  "iat",
  "iss",
  "locale",
  "name",
  "picture",
  "sub"
 ],
 "code_challenge_methods_supported": [
  "plain",
  "S256"
 ]
}
```

##参考記事
###Qiita
[OAuth & OpenID Connect 関連仕様まとめ](https://qiita.com/TakahikoKawasaki/items/185d34814eb9f7ac7ef3)
[超速習 OpenID Connect](https://qiita.com/sylph01/items/208ae313c03426feedc1)
FlutterでHTTP通信してみる


# httpパッケージのインストール

以下を参考に、httpパッケージをインストールします
https://pub.dev/packages/http#-installing-tab-


- pubspec.ymlの`dependencies`に`http: ^0.12.0+4`を追記
    - ※バージョンは記事執筆当時のもの

```
dependencies:
  http: ^0.12.0+4
```

```
flutter pub get
```


# HTTP通信をしてみる

使い方はREADMEを見ましょう
https://pub.dev/packages/http#-readme-tab-



- http.dartをインポートします

```
import 'package:http/http.dart' as http;
```

- GETの場合

```
final String url = 'http://www.test.com';
http.get(url);
```

- POSTの場合

```
final dynamic body = {'test': 'aaa'};
final String url = 'http://www.test.com';
http.post(url, body: body);
```
enebularでblockly

#概要

enebularでblocklyとwebsocketしてみた。


#flow

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/2a28b247-2fe8-0d17-4a65-a5d0ef92a2b7.png)

#写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/12f4ebf8-a804-3882-175d-9d7c33e13397.png)

#サンプルコード


```

Blockly.Blocks.send = {
	init: function() {
		this.jsonInit({
		message0: "send %1",
		args0: [{
			type: "input_value",
			name: "TEXT"
		}],
		previousStatement: null,
		nextStatement: null,
		style: "text_blocks",
		tooltip: Blockly.Msg.TEXT_PRINT_TOOLTIP,
		helpUrl: Blockly.Msg.TEXT_PRINT_HELPURL
	})
}};

Blockly.JavaScript.send = function(a) {
    return "send_(" + (Blockly.JavaScript.valueToCode(a, "TEXT", Blockly.JavaScript.ORDER_NONE) || "''") + ");\n"
};

var demoWorkspace = Blockly.inject('blocklyDiv', {
    toolbox: document.getElementById('toolbox')
});

Blockly.Xml.domToWorkspace(document.getElementById('startBlocks'), demoWorkspace);

function showCode() {
    Blockly.JavaScript.INFINITE_LOOP_TRAP = null;
    var code = Blockly.JavaScript.workspaceToCode(demoWorkspace);
    alert(code);
}

function runCode() {
    window.LoopTrap = 1000;
    Blockly.JavaScript.INFINITE_LOOP_TRAP = 'if (--window.LoopTrap == 0) throw "Infinite loop.";\n';
    var code = Blockly.JavaScript.workspaceToCode(demoWorkspace);
    Blockly.JavaScript.INFINITE_LOOP_TRAP = null;
    try
    {
        eval(code);
    }
    catch (e) 
    {
        alert(e);
    }
}

function showXml() {
    var xml = Blockly.Xml.workspaceToDom(demoWorkspace);
    var code = Blockly.Xml.domToPrettyText(xml);
    var out = document.getElementById('out');
    out.value = code;
}

function send_(data) {
    ws.send(data);
}

var ws = new WebSocket("wss://ev2-prod-node-red-76a86c2c-f24.herokuapp.com/pub");
ws.onopen = function(e) {
    alert("open");
};
ws.onerror = function(e) {
	alert("err");
};
ws.onmessage = function(e) {
    alert("recv");
};




```

#成果物


以上。
Elmでも&nbsp;したい

表題のとおりです。

`'\u{00a0}'` を使うだけです。

```elm
import Html

view : model -> Html msg
view _ =
    Html.text "\u{00a0}\u{00a0}\u{00a0}\u{00a0}インデントつきテキスト"
```

これで `&nbsp;` が表示されます。

まあ、CSSで `white-space: pre` を指定してふつうに半角スペース使えばいいことの方が多いけどね。
初心者によるプログラミング学習ログ 291日目

#100日チャレンジの291日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
291日目は、

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>291日目　2h<br>・xdデザインカンプからのサイト模写<br><br>画面いっぱいに拡大されすぎなんだが・・・<a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a><a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a><a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1250157466626580481?ref_src=twsrc%5Etfw">April 14, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Pythonのturtleでマウスクリックしたところに亀を移動させる

#Pythonのturtleでマウスクリックしたところに亀を移動させる

### 実行イメージ
<img width="302" alt="スクリーンショット 2020-04-15 4.23.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38743/2e96505b-a3bb-52bb-1e9f-30ee3ef12dd1.png">


### サンプルプログラム
```python
import turtle

kame = turtle.Turtle("turtle")

def moveKame(x, y):
    kame.goto(x, y)

kame.screen.onclick(moveKame)

turtle.done()

```

### 解説
```python
# turtleモジュールを読み込む
import turtle
```

```python
# kameという名前の変数にturtleモジュールの中の亀（Turtle）を生成して格納する
kame = turtle.Turtle("turtle")
```

```python
# moveKameという名前の関数を定義
# def は関数を生成しますよ、という意味
# moveKame　は任意の名前でOK
# x, y はマウスでクリックした座標の数値が入る
def moveKame(x, y):
    # 亀を移動させる
    kame.goto(x, y)
```

```python
# マウスクリックのイベントを登録する。（マウスクリックしたらmoveKame関数が実行される。）
kame.screen.onclick(moveKame)
```

```python
# プログラムの実行時にウインドウをすぐに閉じないようにする。
turtle.done()
```
[Unity]マルチタッチ情報はindexではなくfingerIdで追う必要がある

## はじめに
Unity開発で画面タッチ情報は[`Input.GetTouch(index)`](https://docs.unity3d.com/jp/460/ScriptReference/Input.GetTouch.html)などで簡単に取得できます。
マルチタッチの場合も全てのタッチ情報が取得できますが、特定タッチの移動などを追う際はタッチ情報のindexではなく`fingerId`を参照する必要があります。[公式ドキュメント](https://docs.unity3d.com/jp/460/ScriptReference/Touch-fingerId.html)でも書かれています。

これがつまりどういうことなのか…実際に目で見てわかる形で動作を確認した記録です。

### 対象
- Unityでマルチタッチ情報を取り扱おうとしているひと
- Unityのマルチタッチ情報がどんな状態で格納されているか気になるひと


## 動作確認
動的にメッシュを描画するなどの習作を兼ねて、マルチタッチ(4点まで)の各タッチ情報が見てわかるようなアプリを作成しました。(Android用)
![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474074/14194a82-9b1b-3240-accd-676771e1d929.jpeg)
githubに置いてあります：https://github.com/zeffy1014/Unity_TouchExperience

### アプリ制作・動作確認環境
- Unity: 2019.3.0f6 64bit
- Android端末: URBANO V02, Android 5.1

### 動作確認結果
①→②→③の順番で画面タッチした後、①の指を離した場合にどうなるか確認しました。
![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474074/fde8bc59-76fb-832a-8162-39bb42a02787.jpeg)
残った②③については`fingerId`は変わりませんが、タッチ情報の配列のindexとしては前に詰まりました。
このことから、例えば②のタッチ情報を追跡する場合は
　×：`Input.GetTouch(1)`ではなく
　○：一通りタッチ情報を取得した上で `fingerId==1`となるタッチ情報を参照する
という必要がある。ということになります。

なお、この後再度どこか追加タッチした場合は、その地点が`index=0`,`fingerId=0`で格納されました。

### なんとなく考察
実際の動作を確認した上で、マルチタッチの情報がどのように格納されるのか？について考えますと…
推測の域を出ませんが、新規タッチを検出するたびに

- `fingerId`について0から順に空いているものが割り当たる
- タッチ情報の配列は新規タッチ、既存タッチ問わず`fingerId`の若いものから順番に入る

という感じになるのかなと思われました。

このあたりは正直開発者はあまり気にしなくてよい部分だとは思いますが、複雑なタッチ操作を行うアプリを実装する機会があった際にちょっと知っておけるとよいかと思います。
とはいえ、とりあえずは「同一タッチを追うなら`fingerId`を参照」だけ注意すればよさそうですかね。

以上です。
AWSからFirebaseにサイトを移行した

タイトルの通り
前回[AWSでサーバレスと称し自分のサイトを公開した](https://qiita.com/s-tyd/items/2b40fc88b78b49b84b35)がRoute53で月50円取られていたので勉強がてらに無料で話題のFirebaseを利用してサイトを移行した備忘録


# 準備
- Firebaseで 『プロジェクトを追加』から適当なプロジェクトを作成する
 - **ロケーションを設定しておく** （ロケーションがどこが良いかは各自調べる、大体は東京で良い）
- npmを使うのでnodeを入れておく

# firebase-tools を入れる
```sh
npm install -g firebase-tools
```
（記憶があっていれば）Webで認証するのでFirebaseにログイン

# 初期設定
`firebase init` を実行すると歓迎される

```
~/project ❯❯❯ firebase init

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

....

? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices. (Press <space> to select, <a> to tog
gle all, <i> to invert selection)
❯◯ Database: Deploy Firebase Realtime Database Rules
 ◯ Firestore: Deploy rules and create indexes for Firestore
 ◯ Functions: Configure and deploy Cloud Functions
 ◯ Hosting: Configure and deploy Firebase Hosting sites
 ◯ Storage: Deploy Cloud Storage security rules
 ◯ Emulators: Set up local emulators for Firebase features
```

最初にいるもの聞かれるので選択する（スペースで選択）
いるもの全部選択したらEnter押して決定
今回はHostingだけしてほしいのでHostingのみを選択した

で、多分既存のプロジェクト使うかどうか聞かれるのでそこで最初に準備したものを選ぶ

あとはなんか色々聞かれるが、デフォルトのままで大丈夫。
最後に公開するディレクトリを聞かれるのでちゃんと教えてあげる。
（適当にEnter押してて公開されずに一回悩んだ）


```
? What do you want to use as your public directory? src
? Configure as a single-page app (rewrite all urls to /index.html)? Yes
? File src/index.html already exists. Overwrite? No
```
上でやってんのは srcディレクトリにあるindex.htmlみてねって言ってる


# 余談： Error: Error fetching Firestore indexes
このエラーが出た人は多分Firestoreを選択したと思う。
Firestoreを**ネイティブモード**にしておくと解決する。

# Deployする
`firebase deploy`を実行する

```
~/project ❯❯❯ firebase deploy

=== Deploying to 'your-project'...

i  deploying hosting
i  hosting[your-project]: beginning deploy...
i  hosting[your-project]: found 10 files in src
✔  hosting[your-project]: file upload complete
i  hosting[your-project]: finalizing version...
✔  hosting[your-project]: version finalized
i  hosting[your-project]: releasing new version...
✔  hosting[your-project]: release complete

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/your-project
Hosting URL: https://your-project.web.app

```
実際にHosting URLを覗いてみると公開されている。すごい、はやい。


# Hosting設定する
FirebaseのコンソールでHostingに行く
するとドメインを追加ってあるので追加する。

GoogleDomains勢はこちらを参考にする。
[Firebase Hostingに Google Domains でサブドメインを設定する](http://backham.me/blog/2018/05/01/firebase-hosting%E3%81%AB-google-domains-%E3%81%A7%E3%82%B5%E3%83%96%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B)




# 終わり
爆速デプロイでびっくりした。
最近webサービスの個人開発にハマってるのでとりあえずFirebase使っていこうと思う。
この記事も爆速で書いたのでわりと適当。
docker runした日(注意すること)

##以下コマンドで起動する
docker run -p 8888:8888 -v ~/dev/ds_python:/work --name my-lab 520b56985511 (image ID)

##注意点
1. ポートを指定する(-p コンテナのポート:ホストのポート)
2. ファイルシステムのマウント(-v コンテナの作業フォルダ:dockerfileで作ったフォルダ)
3. コンテナ名を命名(--name 任意)



###参考
https://datawokagaku.com/startjupyternote/
【Python】起動方法による sys.path の違い (v3.8.2)

# 概要

Python のプログラムから絶対 importするときには、**`sys.path` に書かれているパスの先頭から検索される**ので、これに何が入っているかは重要。
Python のプログラム起動方法には何種類かあり、それによりモジュールの検索パスである `sys.path` の値が異なる。

# 参考文献

v3.8.2 版を閲覧

- Python のセットアップと利用, 1. コマンドラインと環境. https://docs.python.org/ja/3/using/cmdline.html

# 詳細

簡単に言うと

- (A) ファイルなどを直接指定した場合はそれに関連するディレクトリが `sys.path` の先頭に来る
- (B) `-m` でモジュール・パッケージを指定した場合はカレントディレクトリが先頭要素になる。カレントディレクトリは空文字列 `''` で表される。
- (C) 「実行するプログラムの場所」に相当するものがない場合も、カレントディレクトリが先頭になる。
- いずれの場合でも、モジュール名は `"__main__"` という文字列である。

まとめると以下の通り。ディレクトリ (パッケージ) や .zip ファイルを起動できることを自分は知らなかった。また、パターン (A) の場合にも、カレントディレクトリが `sys.path` に含まれていると思っちゃう人も多いのではないだろうか。 

| パターン | `python` の後の引数 | 実行されるもの | そのモジュール名 (`__name__`) | `sys.path` の先頭要素 |
|---|-----------------|------------------|------------------|----|
| (A) | `<.py ファイル>` | そのファイル | `__main__` | `<そのファイルのあるディレクトリ>` |
| (A) | `<ディレクトリ>` | `<ディレクトリ>/__main__.py` | `__main__` | `<ディレクトリ>` |
| (A) | `<.zip ファイル>` | `.zip ファイル` 内の `__main__.py` | `__main__` | `<.zip ファイル>` |
| (B) | `-m <モジュール>` | `<モジュール>.py` | `__main__`| カレントディレクトリ (空文字列) |
| (B) | `-m <パッケージ>` | `<パッケージ>/__main__.py` | `__main__`| カレントディレクトリ |
| (C) | `-c <コマンド>` | <コマンド> | `__main__` | カレントディレクトリ |
| (C) | `-` | 標準入力で渡されるスクリプト | `__main__` | カレントディレクトリ | 


## `-I` 使用時の注意

起動オプションで `-I` を指定すると、`-E -s` を指定したことになり、**isolated モード** でインタプリタが起動する。
このとき、(`-s` の影響により) 上記 **先頭要素は `sys.path` に追加されない。**
したがって基本的には、`pip install` でインストールされたモジュールしか (絶対) import できない。
実行スクリプトの隣にあるモジュールであっても import できないので注意すること[^1]。

[^1]: なお、実行スクリプトの隣りにあるモジュールは相対 import もできない。`__main__` モジュールからの相対インポートができないからである。
macOSにOpenJDKをインストールする

## OpenJDK 11.0.2の場合

1. [Archived OpenJDK General-Availability Releases](http://jdk.java.net/archive/)からダウンロードする。

    ```shell
    wget https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_osx-x64_bin.tar.gz
    ```

1. `openjdk-11.0.2_osx-x64_bin.tar.gz`ファイルを`/Library/Java/JavaVirtualMachines/`に解凍する。

    ```shell
    sudo tar zxvf openjdk-11.0.2_osx-x64_bin.tar.gz -C /Library/Java/JavaVirtualMachines/
    ```

1. ファイルの所有者/所有グループを変更する。

    ```shell
    sudo chown -R root:wheel /Library/Java/JavaVirtualMachines/jdk-11.0.2.jdk
    ```

1. `OpenJDK`が認識されていることを確認する。

    ```shell
    /usr/libexec/java_home -V
    ```

1. `JAVA_HOME`環境変数を登録する。

    ```shell
    export JAVA_HOME=`/usr/libexec/java_home -v 11.0.2`
    ```

1. `java`コマンドを実行し、動作確認する。

    ```shell
    java -version
    ```

1. `macOS Catalina 10.15`はzshを採用しているため、`~/.zprofile`ファイルを変更する。

    ```shell
    vi ~/.zprofile
    ```

    ```shell
    export JAVA_HOME=`/usr/libexec/java_home -v 11.0.2`
    ```
Pythonで「大石泉すき」を何回で揃えられるかゲームをつくる

#概要
[「大石泉すき」Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ohishi-izumi-suki)にて[Excel VBAでつくったもの](https://qiita.com/tsuru2_mitsuru/items/171386402987d87f8587)を、Pythonの勉強がてら焼き増ししただけのものです。

```py
import random

STRING = '大石泉すき'
i = 0
output = ''

n = len(STRING)
max = n - 1

while output != STRING:
    output = ''

    for _ in range(n):
        location = random.randint(0, max)
        output += STRING[location]
    
    print(output)
    i += 1

print('「{}」が揃うまで{}回かかりました。'.format(STRING, i))

```
定数STRINGに好きな文字を入れて遊べます。

#結果
<img width="342" alt="スクリーンショット 2020-04-15 2.41.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490117/8a651597-7179-0e6e-b41f-5352ac245d0d.png">
Apollo ClientでIDなしオブジェクトのフィールドを含めたレスポンスでキャッシュを更新しようとすると怒られる

# Store error: the application attempted to write an object with no provided id but the store already contains an id of Hogehoge for this object.

Apollo Clientで、以下のようなqueryによって取得/キャッシュされたnoteオブジェクトがあったとして

```graphql
query notes {
  notes {
    id
    content
    author {
      id
      name
    }
  }
}
```

キャッシュされているnoteオブジェクトを更新するようなmutationのフィールドが以下のようになっていた場合

```graphql
mutation updateNote($input: UpdateNoteInput!) {
  updateNote(input: $input) {
    id
    content
    author {
      name
    }
  }
}
```

authorにidがないため、見出しのようなエラーが出る。
ちなみに以下のようなフィールドにするとエラーは出ないがエンティティを特定できないため当然キャッシュは更新されない。

```graphql
mutation updateNote($input: UpdateNoteInput!) {
  updateNote(input: $input) {
    content
    author {
      id
      name
    }
  }
}
```
コードを予測してくれる機能をつけたいです

例えば、「⋦ｂｏｄｙ≻」と打ったら、「＜ｂｏｄｙ＞＜／ｂｏｄｙ＞」と予測変換する機能はどうすれば追加できますか？
ご回答宜しくお願い致します。
【究極サバイバル】上司がExcel/VBAでシステム開発を迫ってきたら

# あなたの置かれている状況は
- Excelとそれを動かす言語VBAで何かを登録したり表示したりしろと迫られています。他の道具は使えません。
- Excelとは何でしょう。触ったことがないなら幸せです。今事切れれば幸福度の損切りができます。簡単に言うとgoogle spreadsheetの劣化コピーです。spreadshitです。
- あなたのポケットには運良くgitが入っているかもしれません。しかしdiffは取れません。.xlsm(マクロ付きExcelファイル)はzipされたxml、バイナリなので容易に差分比較できません。気持ちを切り替えて 「株価一覧_20200414_01_罫線調整.xlsm」みたいなのを手動管理する手間が省けたことを喜びましょう。
- 他の被害者と協力し1つの.xlsmを編集するのは一見良さげですが危険な行為です。mergeもクソもないですよバイナリなんですから。ただし、「モジュール」を「エクスポート」するとテキストが吐かれます。それをマージするというなら現実的です。
- ただし、モジュールをすべて吐き出す機能はありません。「vba 一括エクスポート」でググって実現したとしましょう。それでも**致命的なのは「シートの状態」などは容易にエクスポートできないという点**です。
- 被害者達は「**Excelシートの状態**」と「**VBAで書かれたコード**」の2つを管理しなければ生き残れません。絶望的なのは「**シートの状態**」がこの上なく管理しにくいという事実です。普通の開発で言ったらhtmlファイルがなんかひと塊になってて中身がうんこ色になっている状態ですね。

# Excelというジャングル
をちょっと覗いてみましょう。深淵もまた覗いているのだ。
## シート
なんとやら.xlsxをダブルクリックすると内部的には*workbook*が開きます。
下のタブにsheet1と書かれているでしょう。
マス目が並んでいてA列の1行目が選択されているかもしれません。
Excelは *workbook* > *sheet* > *セル*(*range*や*cell*)  という階層からなります。

それぞれのオブジェクトに名前がついています。*workbook* はファイル名。*sheet* は下のタブ名と連動。ここがミソなんですが、*セル* は"B2"など座標で指定する方法と、名付けてしまう方法があります。名付けられたセルは上部の「数式」タブからしか一覧参照・編集ができません。見つけにくいです。

## コード
次はVBAコードを書く場所に着目してみます。

- 各シート ... sheet1にfooというpublic関数を書いたらsheet1.foo()が呼べるわけです。
Meという修飾子はsheet1オブジェクトを示します。Me.Range("A1")でそのシートのセルが参照できるのでそういうのを利用したい関数を書けばいいんじゃないでしょうか。
- 標準モジュール ... シートに依存しない共通した処理をかけます。グローバル定数とかも。ただし、グローバル変数を宣言しても破棄されるかもしれん保証はしないという噂を聞きました。聞かなかったことにしました。
- クラスモジュール ... クラスみたいなものをかけます。20年前の最新技術です。

ということで、VBAでセルを指定する方法は複数あります。いくつか例をあげると

- sheet1.Range("**銘柄コード入力欄**")
- Me.Range("**A1**")
- .Cells(1, 1) 

*Sheet*オブジェクトのRange関数で座標を指定するというのが基本だと思います。
セルに名付けてセル名参照か座標参照かは統一したほうがいいんじゃないでしょうか。

# どう切り拓くか
さて、「シート」が少し厄介なhtmlファイル、「コード」が20年継ぎ足し継ぎ足しで使ってる秘伝の言語ということがわかりまし ***上司「その日の室温・湿度と我が社の株価・日経平均(これだけ自動取得)を手入力して保存するシステムを作ってくれ」*** この必要火急なシステムを作りましょう。

## 想定: 弊社の「室温及び株価管理部」のユーザ 1人か2人
「室温・湿度記録.xlsx」と「株価・日経平均記録.xlsx」の2ファイルを成果物として出すことにしましょう。小規模なので「シート」に記録してしまいましょう。ユーザの寿命か株価の寿命が来るまでのデータは1列で保存できます。数えてませんが少なくとも200行はあるので。
1ファイルにしたほうがUXが良い気がしますが、構成管理担当のエクスペリエンスを上げたいので分けます。絶対に共通する処理がありますが分けます。ファイルは開発者分に分割しましょう。1人1ファイルを担当します。「室温・湿度記録.xlsx」を先に作ってもらって、それをコピペして後者のファイルを作ります。これは石器時代によくみられる開発手法です。いいんだよExcelなんて尖った石がついたモップの柄なんだから。
もう一人開発者が来たら日経平均をスクレイピングする部分を書かせます。この処理は「シート」にあまり影響を与えないので平和に分業できます。できないかもしれません。来なかったら日経平均は19000で固定します。

## 想定: 全国50工場の「室温及び株価管理部」
ここでやっと役立つTipsです。.xltmというファイルがあります。これはテンプレファイルというやつです。普通に開くと「ファイル名1.xlsm」が生成されます。ユーザに汚されても、もとの.xltmは変わりません。配布するときに役立ちますね。
しかし、各工場のローカルな.xlsmファイルにデータを保存されたら保守運用の人がかわいそうですが雇用創出のために放っておきます。
本当はDBに保存したいですよね。各工場にIDを振って。
SQLを処理するサーバにクエリだして結果をテキストで受け、それをオブジェクトに変換するという手法があります。VBAの仕様上、結果を表すテキストが大きすぎるとオーバーフローしたりします。絶対ベストプラクティスじゃないです。限りなくワーストに近いはずです。しかしそこに正解はない。ExcelがDBへの保存というものを見据えていないから。

## 開発における注意点

- 全「シート」にロックをかけて入力させたい「セル」のロックを外すと入力欄だけ編集可能になる
- 一応パスワードかけとかないと秩序が崩壊する
- 1シートのロックに1秒くらいかかることがある
- ページの遷移的なものは各種ボタンやクリックイベントなどを利用する
- ボタンには2種類あるので統一したほうがいい
- ここらへんの細かいノウハウはあまり世に出ていないし出してはいけない
- .Range("A1") => 文字列とか数値
- .Range("A1:B1") => 配列。型エラー出うるけどコンパイル時に弾かれない？
- エラーメッセージが2種類くらいしかない気がします。例外処理やらエラーログ出力やらはプロジェクトで統一した方法を使いたいですね。

# 学び
今回の開発で異なる2つの「シート」がそれぞれViewとModelを担当し、「コード」がPresenterを担うMVP開発がExcel/VBAという閉じていて枯れた環境において実現できるとわかりました。
Angular CDK とは何か？何が含まれるのか？



はこです。こんにちわ！

[Angular CDK](https://material.angular.io/cdk/) はとても便利な機能なのですが、ドキュメントがとっつきづらいのもあって、なんとなく1年ぐらい避けてました。
今回改めて見直すと死ぬほど便利だったのです！

カンタンなまとめが存在してなさそうだったので、カンタンにまとめました。


## Common Behaviors 
汎用的な機能です。

- Clipboard: クリップボードにコピーする機能。
- Drag and Drop: ドラッグ&ドロップの解決。たとえば `<div cdkDrag >ドラッグ・ミー！</div>` でドラッグ可能になる。
- Scrolling: 仮想スクロール。`<cdk-virtual-scroll-viewport><div *cdkVirtualFor="let i of million"></div></cdk-virtual-scroll-viewport>` とすると、百万行のfor文でも、表示部分のみレンダリングしてくれる。
- Layout : レスポンシブ用のレイアウト。画面サイズ変更、および回転(スマホのみ)を検知する `breakpointObserver`が変更を通知してくれる。
- Observers : `<ng-content>` の内容が変更されたときに検知する `cdkObserveContent` を提供する。
- Portal : 内部要素を書き換えます。router-outletに似てるかも？タブグループの表現などで利用。
- Overlay: オーバーレイを作成。モーダルダイアログなどに。Portal(前述)を継承してるので、オーバーレイの内部要素はPortalとして注入可能。
- Platform: UserAgent関連情報。`isAndroid` のような判定と、利用可能なイベントリスナ一覧等
- Accessibility : アクセシビリティ機能。要素にフォーカスがあるときやスクリーンリーダー等で見た目を変更する。カスタムのボタン作る等に使う。
- Bidirectionality: 双方向性。RTL(アラビア語のように右から左に読む)言語を検知してレイアウト変えたりするための、
- Text field: `<textarea>` と  `<input>` 関連の便利機能。しかしオートフィル監視と自動リサイズしか無い。。

## Components

スタイルが適用されてない(つまりバニラな)コンポーネント。

- Stepper : 入力ウィザード的な。[例](https://material.angular.io/cdk/stepper/examples) を見てもらうほうが早そう…。
- Table : `<table>` `<tr>` `<th>` `<td>` の関係を再構成して forで回しやすくしたテーブル。便利なのだがとっつきづらさも否めない。。。
- Tree: ツリー型メニュー。[https://material.angular.io/cdk/tree/overview](実例) 見るのが速い。

## Testing
テストのためのツール
- Component Harnesses: 3種類のAPIがある。
1. サードパーティのUIライブラリを使ったテスト作成者向け。具体的には、AngularMaterialのメニューコンポーネントを使っていて、これを操作するユニットテストが書きたいケース。<br> ComponentHarness を使ってテストする。
2. ComponentHarness作成者向け。つまりUIライブラリの作成者向け。
3. テスト環境の作成者向け。つまり新しいテストフレームワークで使うための。

一番多い、1のケースでのテストの書き方としてはこんな感じになる。

```JavaScript:sample.spec.js
it('loads harnesses', async () => {
  const buttonHarness = await loader.getHarness(MyButtonHarness);

  // クリックを確実に実行する
  await buttonHarness.click();
  
  // 文言をチェック
  const text = await buttonHarness.text();
  expect(text).toBe('aaa');
});
```

# 感想
Drag and Dropや Scrolling, Layout はいろいろなところで使えそうですね！
逆に TreeやStepper は、Angular Materialのほうにもあります。独自カスタマイズのデザインのTreeを作成する場合にはCDK役に立つかも？
ERR_CONNECTION_TIMED_OUT に苦しめられた

# 背景

制作物をデプロイする際に　ERR_CONNECTION_TIMED_OUT の連発
ネットワーク関係分からないため調べて、キャッシュクリア等するも解決せず。
URLを確認してみると、SSL化していないのにも関わらずhttpsになっていることに気づく
その際にHSTSというものが関係しているかも？と知る。(キャッシュクリアしても解決しないのは何で)
新たに別EC2で再デプロイするも結果変わらず　ERR_CONNECTION_TIMED_OUT 
諦めてEIPを新たに設定すると問題なく接続され、デプロイ終了。

#　どうしてタイムアウトになったか(考察)
デプロイ後、certbotでSSL化しようとある程度進めていたが、ドメインを取得しておらず途中で断念、
その際に proxy_set_header X-FORWARDED_PROTO https　を追記しており 
それでhttpsに接続されようとしていた?(これが合っているかも分からないため今後検証)
追記した内容を消しても、一度httpsで繋ごうとしていたため、httpと入力してもhttpsに接続しようとしていた？
正直分からないことが多過ぎる....

# 総評

できそうかも？で挑戦したなら最後までやりとげろ、中途半端にするくらいならやるな


といった自分への戒めというか、ひとりごと。
RailsにRspecを導入してみた

新しく開発をしようと考え、テストの方も勉強したいなと感じたのでメモがてらRailsにRspecを導入する方法まとめてみました。

##1 gemのインストール

```ruby:Gemfile
group :test do
  gem 'rspec-rails'
  gem 'factory_bot_rails'
  gem 'rails-controller-testing'
end
```

Gemfileに上記のgemを記述します。

##2 bundle install

```
$ bundle install
```

##3 Rspecに必要なファイルを作成

```
bundle exec rails generate rspec:install
```

すると以下のファイルが作成されます。

```
.rspec      
 spec
 spec/spec_helper.rb
 spec/rails_helper.rb
```

##4 Factory_botの設定

spec/rails_helper.rbの最下部に以下の記述をします。

```ruby:spec/rails_helper.rb
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end
```

## 5 rails g コマンドと同時にテストファイルを作成させる

```ruby:application.rb
config.generators do |g|
      g.test_framework :rspec,
                       fixtures: true,
                       view_specs: false,
                       helper_specs: false,
                       routing_specs: false,
                       controller_specs: true,
                       request_specs: false
      g.fixture_replacement :factory_bot, dir: "spec/factories"
    end
```

## 6 Rspecが導入されているかの確認

```
$ bundle exec rspec
No examples found.

Finished in 0.00065 seconds (files took 0.10275 seconds to load)
0 examples, 0 failures
```

と表示されれば導入は完了です！
外出自粛でやることがない？おいリモートデュエルしろよ

タイトル煽りはすみません。元ネタは[「おい、デュエルしろよ」](https://dic.pixiv.net/a/%E3%81%8A%E3%81%84%E3%80%81%E3%83%87%E3%83%A5%E3%82%A8%E3%83%AB%E3%81%97%E3%82%8D%E3%82%88)です。

さて、世界は未曾有のパンデミックに見舞われ、多くの人々は外出自粛を要請され自宅で過ごすことを余儀なくされる日々。全国1億2000万人のデュエリストの皆さんはどうお過ごしでしょうか？

もちろん！自宅でも闇のゲームを楽しめるリモートデュエルをして過ごしてますね！

まだデュエリストで無い全国約590万人の方々も楽しんでもらえるよう説明すると、リモートデュエルとは下記のようなものです。
https://www.yugioh-card.com/japan/notice/information/?42

zoomやGoogle Hangouts Meetを利用してリモートデュエル自体は簡単にできますが、ライフの計算やコイントスなどのやり方が煩雑で難しいと言う問題点があります。
その計算を楽にするリモートデュエル支援ツールを友達と一緒に作成したので紹介します。

## 説明とか

リモートデュエル支援ツールなサイトはこちらです。

https://duelmanager.netlify.com/

### 機能について


![dualmaneger説明.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155890/5be135c3-23ff-7b85-c680-08f8cad4b2f7.png)


それぞれの機能は下記です。

① クリックするとお互いのライフを8000に初期化するボタンです。
② コイントスを行えるボタンです。
③ このあたりをクリックするとライフの増減を行える電卓を表示できます。
④ ユーザー名とアイコンを変更します。アイコンはGithubのアイコンが使用されます。
⑤ 間違えてライフを増減させてしまったときにキャンセルできるHistoryのボタンです。

### リモートでのパラメータ確認について

これらの機能はFirebaseを利用して状態が共有されているため、
URLには固有のパラメータが付与されているので同じURLを開くだけで、デュエル中のプレイヤーは互いに状態を共有することができます。

 
![dualmaneger.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155890/82e6c867-b7a4-563e-3b60-83e31f3dd606.gif)

### 構成とか

Vue.jsとFirebaseで実装してNetlifyでホスティングとデプロイしてます。

![dualmanegerアーキテクチャ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155890/3408cab7-1edb-3ea5-4e28-cc337c2ae7a3.png)

このようなシンプルな構成でも、多くの機能を簡単に実現できる素晴らしいサービスです。

## "duelmanerger" NEEDS YOU!

このプロジェクトには、デザインを良い感じにする方と音楽を耳コピできる方がいません。
協力できるデュエリストの方がいましたら是非contributerになってください！

<a href="https://github.com/team-satisfactions/duelmanager"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/team-satisfactions/duelmanager.png" width="460px"></a>

## 魔法・罠(トラップ)・モンスターの効果について

遊戯王はカードに様々な効果があります。
これらを画像認識してお互いのプレイヤーが確認できるようにするのは次のタスクではありますが、
現行では互いのカードの効果を正確に確認することはできません。

しかし、アニメや漫画のように効果発動時に
「モンスターで貴様の〇〇に攻撃！」
「しかし、〇〇には特殊能力がある〜〜効果の説明〜〜。つまり△△することによって、攻撃を無効にし破壊する！」
「何！俺の□□が！」
というようにロールプレーをすることで楽しみましょう！

## まとめ

ルールを守って楽しくデュエル！
ガッチャ！楽しい投稿だったぜ！
react navigationのindex.tsxでSyntaxErrorが出た時の解消法

# はじめに
React Nativeでreact navigationを入れようとしたところ、以下のようなエラーが

~~~
SyntaxError: /Users/hogehoge/news-app/node_modules/@react-navigation/stack/src/index.tsx: Unexpected token (51:12)
~~~
該当のファイルを開くと、確かに赤波線が出てエラーになってるけど、そもそもnpm installで入れたやつなんだけど？という時の解消法

# 解消法
~~~
rm -rf node_modules
rm package-lock.json
npm install
~~~
[公式](https://reactnavigation.org/docs/troubleshooting/#im-getting-syntaxerror-in-react-navigationxxxxxxtsx-or-syntaxerror-xxxreact-navigationxxxxxxtsx-unexpected-token)に書いてあったという
ざっと見て日本語の記事がなかったのできっと意味はあるはずと信じたい
.NETで正確に文字列のサイズを計測するのに2度手間がかかる

.NETで文字列のサイズを計測するのには``Graphics.MeasureString()``を使いますよね？文字列のサイズが知りたいのに、1度適当なサイズの``Bitmap``を``Graphics.FromImage()``してあげないと``MeasureString()``が使えないという話は置いておいて、ただ単純に``MeasureString()``をしただけじゃ、文字列のサイズを正確に計測することはできません。**どうしても、左揃えなら右側に、右揃えなら左側に謎の空白ができてしまいます**。

(正確には、はみ出しを抑制するための空白です。ちゃんと意味があります。)

これを回避するために、``MeasureString()``の第4引数に``StringFormat.GenericTypographic``を指定してやる必要があります。ですが、第4引数を指定するには、その前にある第3引数、文字列の最大の長さ、を指定する必要があります。

ここで思います、「今から文字列の長さを知りたいのに、なぜ最大の長さを指定する必要があるのだろう」、と。

確かに、文字を詰めて表示するために上限を決めたり、すでにウィンドウサイズが決まっていたりするのであれば、上限の横幅というのを指定しても良いですが、ほとんどの場合、純粋に文字列を描画したときの長さが知りたいはずですし、ウィンドウサイズが一定のアプリであるとも限りません。

ですから、何らかの値を入れてやる必要があります。適当な定数でも、``int.MaxValue``でも問題はなさそうですが、あまりスマートではありませんよね。

----

そこで、一番初めに紹介した、「謎の空白を生み出してしまう計測法」を用います。これは、純粋な文字列のサイズではないですが、「正しい文字列のサイズ」よりもちょっと大きいサイズを取得できることは100%、間違いないので、近似値と言えるこの値を使います。

```csharp
// Fontという名のフィールドがすでにあるとする

// 適当なBitmapを生成
var bitmap = new Bitmap(16, 16);
// 適当なGraphicsを生成
var graphics = Graphics.FromImage(bitmap);
// 謎の空白付きの文字列のサイズを計測。
var graphicsSize = graphics.MeasureString("成就した恋ほど語るに値しないものはない。", Font);
// ちゃんとした文字列のサイズを計測。
var trueGraphicsSize = graphics.MeasureString("成就した恋ほど語るに値しないものはない。", Font, (int)graphicsSize.Width, StringFormat.GenericTypographic);

bitmap.Dispose();
graphics.Dispose();
```

適当な定数を使うよりも、こっちの方がスマート……な気がします(計算量は増えるけど)。

**謎の空白を生み出してしまうあのメソッドが、なんとここに来て役に立ってしまいました**。Microsoftのおじさんもこう使われることを想定していたのでしょうか。

ともあれ、.NETで正確に文字列のサイズを計測するのには2度手間が掛かります。たぶん。
Laravelプロジェクトでcomposer install時にエラー

##エラー内容

Laravelプロジェクトでcomposer install時にエラー発生。

>Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Your requirements could not be resolved to an installable set of packages.

![cap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147857/80dc2ae5-d051-44c5-d4de-3bcbb8f8b2c9.png)

拡張機能ext-mbstringがなくて怒られている模様。

CentOSとかだとyum install・・・でext-mbstringをインストールすればいいようですが、
こちらWindows。

##解決策

php.iniファイル内に拡張機能を指定する項があるので、そこを修正。

>extension=mbstring

上記がコメントアウトされていたので、コメントアウトを除外して解決。

phpの拡張機能はphpフォルダのext内にあり、iniファイルでどの拡張機能を使用するか指定している模様。
シンプルなImageEffectその１。モザイク。

Twitterに貼ったシンプルなモザイクImageEffectのコードを貼っておきます。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">しょぼいネタだけどシェーダ楽しいよね、という事でモザイクImageEffect。<br><br>最近リモートワークが始まってモチベ低下がヤバい（自宅作業が気分転換にならなくなってきた）ので、簡単なものでもとにかく作ってモチベを上げていくテスト。<br>後でコードQiitaに貼ります。 <a href="https://t.co/UbWywGNExM">pic.twitter.com/UbWywGNExM</a></p>&mdash; MIYAKE (@ScreenPocket) <a href="https://twitter.com/ScreenPocket/status/1250066088727130112?ref_src=twsrc%5Etfw">April 14, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

floor(パラメータ * _DivideNum ) / _DivideNum
とすることで、パラメータを階段化（粗階調化）できるのは色々使えるので覚えておくと良いかと。

下記のコードではuvを階段のように刻むことで、モザイク化を実現しています。

```glsl:Mosaic.shader
Shader "ScreenPocket/ImageEffect/Mosaic"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _DivideNum ( "Divide Num", Float ) = 1
    }
    
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;
            float _DivideNum;

            fixed4 frag (v2f i) : SV_Target
            {
                return tex2D( _MainTex, floor(i.uv * _DivideNum ) / _DivideNum );
            }
            ENDCG
        }
    }
}

```

DivideNumには画面のモザイクタイル分割数を入れてあげてください。
もし、モザイクを正方形にしたいなら、画面比でAspect値をを求めて、_DivideNumを補正してあげると実現できるはず。
GL-MT300N-V2 の Firmware Pre-Release 3.102 を試してみた

### はじめに
小型の Wi-Fi ルーター探しているときに見つけた[GL-MT300N-V2](https://www.amazon.co.jp/dp/B073TSK26W) を2019年6月に購入して使っています。Wi-Fi ルーターになるだけではなく、OpenVPN のクライアントにもなったり、とかいろいろな機能があるみたいです。

2019年8月に最新 Firmware 3.025 にしてから更新がしばらくないので、 GL.iNet Docs の Firmware Releases のページを見ると、Pre-release 版の 3.102がありました。
どこが変わっているんだろう、ということで試してみました[^1]。

[^1]: 説明するまでもないと思いますが、Firmware の更新の結果については自己責任でお願いします。


### 画面の変更箇所
さっそく設定画面を見ていくと、無線の設定画面で3カ所の変更がありました。
![00musen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27855/ce1aa8df-fcd6-c961-e2d1-d5d469e7649f.png)

1. Wi-Fi Mode は、11MHz, 54MHz, 300MHz などの周波数が選択肢だったのですが、802.11b などの規格名に変更されています。Pre Release 版の ReleaseNote.txt に記載された Fixed の 2番目、「Modify the wireless speed setting method, change to mode and bandwidth.」のことでしょうね。
2. 送信出力は 1 から 20 までのスライド式だったのですが、Max、高、高[^2]、低[^3]の4種類の選択肢に変更されています。同じく、Fixed の 1番目の「Changed tx power to showed by levels.」に該当すると思われます。
3. チャンネル最適化ボタンが増えました。試してみると、しばらくしてからチャンネルの番号が自動選択されます。ReleaseNote.txt に記載された New Features の1番目の「Added Channel Optimization」に該当すると思われます。

ほかに目につくところでは、VPN 設定に internet kill switch が増えたり、他の設定＞カスタムDNSサーバーの設定に Dnscrypt-Proxy Settings が増えているようです。

[^2]: 「中」とするのがわかりやすいでしょうね。GL.iNet の Facebook ページから報告しておきました。
[^3]: 我が家は2DK の賃貸ですが、「低」でも十分な出力が得られます。ちなみに駐車場の端まで歩いてみましたが（おおよそ20m くらい）、十分な出力が得られます。
MTSQLのエラー　備忘録

##エラーが出た時にやってはいけないこと

```
$ sudo touch /tmp/mysql.sock
```
mysql.sockのファイルはmysql実行時に作られるファイルの為、実行する前に作ってしまうとエラーが表示されます

##色々試したがエラーが解決できない時

下記のサイトの記事を参考にmysqlを削除しましょう

https://qiita.com/akiko-pusu/items/aef52b723da2cb5dc596