OmniAICreator/Qiita-1.07M huggingface dataset:
【semantic segmentation】Fully Convolutional Networksを理解してみる

<h1>概要</h1>
Fully Convolutional Networkを理解してsemantic segmentationを理解してみる


<h2>Base Network</h2>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/ba1f76c7-855b-4014-56cf-c3304cf50218.png)

図からみて分かるようにFCNはConvolutionのみを行い最終的にupsample(interpolation)する。
よって出力のsemantic mapの解像度は低くなる

<h2>改善</h2>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/38e794bb-dd42-ddef-55c4-1ec111030ef6.png)

前の情報を足し合わせる事で精度を上げている

FC-32s
1列目はconv7の結果を32倍upsampleしてsegmentation mapを得る

FC-16s
2列目はconv7の結果を2倍upsampleしたものとpool4の結果を足し合わせて、16倍upsampleしてsegmentation mapを得る

FC-8s
3列目はconv7の結果を4倍upsampleしたものとpool4の結果を2倍upsampleしたものとpool3の結果を足し合わせてたものに、8倍upsampleしてsegmentation mapを得る

<h2>結果</h2>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/cade2d72-cd3a-5397-5ef5-5f63932b33de.png)

図から見てわかるようにFC-32s->FC-16s->FC-8sになるに連れて精度が上がっている事が分かる。

FCNの特徴はDecordしない所かな！

<h1>参考文献</h1>
Fully Convolutional Networks for Semantic Segmentation
https://arxiv.org/pdf/1605.06211.pdf
https://github.com/wkentaro/pytorch-fcn/blob/master/torchfcn/models/fcn8s.py
知らないシステムを孤立させてしまった話

# はじめに
「[本番環境でやらかしちゃった人 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/yarakashi-production)」の16日目の記事になります。

大分昔の話なので記憶がおぼろげですが、干支一周以上前の業務経験の浅かった時にやらかした話。

某日、某データセンターに`HSRP`で冗長化された**Cisco Catalyst**の**L3スイッチ**を本番環境に繋ぐ作業をしに行きました。

作業自体は一部機器を繋ぐだけの作業だったので予定していた作業時間も短く、「帰りに何のお土産を買って帰ろう？」と悠長に考えていたりしました。

データセンターは何度も行っている慣れた場所で、ネットワーク繋ぎこみ作業も何度か実施したこともあるので今考えれば気が緩んでいたのでしょう。

**これから自分が障害を起こすとも知らずに・・・**

# 何事もなく平穏な作業
いつものように作業準備を行い、作業開始。

|確認項目|確認結果|
|:--|:--|
|LANケーブル接続|OK|
|LED確認|OK|
|インタフェース閉塞解除|OK|
|インタフェースリンクアップ確認|OK|
|ゲートウェイへのPing疎通確認|OK|
|冗長化状態確認|OK|

何事もなく進む作業。

今回は一部機器繋ぎこみだけなので、そろそろ作業の終わりも見えてきたとき、一本の電話がかかってきた。

# 一本の電話
<img width="300" alt="smartphone_vibration.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/001a2759-1afa-5f7d-5c2f-21cdabf85255.png">

電話の表示を見ると、その時の案件リーダの方の名前が表示されている。

このタイミングでかかってくる電話に良いことがあったためしがない。

でたくない、、、でたくないが、意を決して出る。

---

私：「どうしましたか？」
リ：「お客様から電話があって監視からエラーが出ていると連絡があったけど何かやった？」
私：「今、L3スイッチを繋いだところなのでリンクアップのメッセージとかじゃないですか？」
リ：「うちのシステムではなく、**別のシステム**の監視からエラーが出続けているそうなんだけど。」
私：「（別のシステム！？）」

自分のシステムならともかく、**別のシステム！！！**

<img width="300" alt="tamashii_nukeru_man.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/bfafe938-4088-8956-e303-248fdebfed45.png">

しびれとも寒気ともいえぬ、血の気が引く感覚が全身を駆け巡りました。

# 惨劇はなぜおこってしまったのか
すぐに原因の当たりはついたので、即LANケーブルを抜き、切り戻し作業開始。

結論としては、**L3スイッチ**で設定していた`HSRP`のグループIDが別システムの機器と同じになっており、さらに優先度が今回接続した**L3スイッチ**のほうが高かったことで、別システムの機器から`HSRP`のエラーが出力し続けられていたわけです。

`HSRP`は共有する仮想IPが異なっていたとしても、`HSRP`グループIDが同じであれば優先度が高い機器に引っ張られ、状態遷移してしまいます。

後の検証で分かったことですが、優先度が高く、仮想IPが同じ機器同士は`Active`、`Standby`の状態遷移を行いますが、優先度が低く、仮想IPが異なる機器同士は、たとえ元々`Active`、`Standby`の状態で動作していたとしても`Listen`状態に遷移し、優先度が高い機器がいなくなるまでそのままの状態となるので、今回L3スイッチを接続してからLANケーブルを抜くまでの間、意図せず**知らないシステムを孤立させてしまった**わけです。

![AdventCalender.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/f7d4baa3-47fe-5d8a-7c5e-347cee4be74b.png)

ちなみに`VRRP`も同じような動きをしますが、`VRRP`は`VRID`（`HSRP`で言うとグループID）が同じでも仮想IPが異なれば、状態遷移までは行われないため、`VRRP`であれば気が付かなかったかもしれません。
※とはいえそのような設計をするものではありません。

# なぜグループIDが被ってしまったのか
改めて振り返ると以下のような原因があったかと思います。

- HSRPの状態遷移について**把握しきれていなかった**
- グループIDが周りに与える影響を**想像できていなかった**
- 結果として作業に対する**認識が甘かった**

今なら自システム外のネットワークに接続する前は事前に**アドレス重複**や`HSRP`の**グループID重複**などないかを事前に担当者に確認するのが当たり前だという感覚がありますが、このころは自システム外の機器が存在するネットワークに繋げるときの**怖さ**や**影響**をイメージしきれておらず、結果、**危険個所の予測**や**事前の確認**が疎かになっていたのだと思います。

# 二度と惨劇を起こさないためにどうしたのか
以下を徹底するようにしました。

- 外部のシステムに接続する際にはグループIDが被っていないか等ヒアリング徹底。
- グループIDが被っているか調べきれない場合はパケットキャプチャでHelloパケット有無を確認。
- Helloパケットの出力があった場合はグループIDが被っていないか確認。

## ヒアリングしても防げない場合
とはいえ、たまにあるのがお客様にヒアリングしてアドレスやIDなど被っていないと言われたのに被っているケース。

お客様のシステムと言えど、1システム担当だと全体を知っているわけでもなく、お客様が知らない間に追加されていたということもあるので、できれば前もってパケットキャプチャを取得させて頂くのがベスト。

**パケットは嘘つかない。**

# おわりに
昔を思い返しながら記事を書いてみましたが、過去のことながら胃が痛くなってきます。

経験が浅いエンジニアと経験豊富なエンジニアを比べたとき、何が違うのかを考えると、知識や経験もそうですが、何かアクションを行ったとき、**どういう影響が発生するかという仮説がどれだけ立てられるか**、**どれだけ状況をイメージできるか**という点があげられるかと思います。

「[本番環境でやらかしちゃった人](https://qiita.com/advent-calendar/2020/yarakashi-production)」に載るような障害を起こさないために、**心配性と言われるくらい気を配って作業する**ようにしましょう。
【UIデザイン】アイコンの位置による印象の違い

#プログラミング勉強日記
2020年11月13日
[UIデザインを紐解く。これだけは押さえたいボタンデザインのポイント](https://liginc.co.jp/280820)の記事で、アイコンの位置によってユーザーへ与える印象の違いがあると学びました。
※学習の備忘録として記録しています。

![スクリーンショット 2020-11-13 11.46.25.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/854121/878bd1ec-deac-39fb-4a99-ece3f20fa589.jpeg)


#左にアイコンがある場合
左にアイコンを置いた際は、詳細ページなどへ『入る』イメージを与えます。

そのため、一覧ページから詳細ページなど下の階層に誘導したいときに使用します。



#右にアイコンがある場合
左にアイコンを置いた際は、詳細ページなどへ『移動する・外へ出る』イメージを与えます。

そのため、階層の関係ないページへ別ウィンドウで開くページの場合に使用します。

#まとめ
アイコンの位置によって、ユーザーへ与える印象が変わると学びました。

これから、LP作成するときなど意識していきたいと思います。
Liberty20.0.0.11で/config/dropinsがビルドにはなく起動時に生成される

先月は問題なく使っていたDockerfileがビルドできなくなり。。

```
$ cat Dockerfile
FROM open-liberty
RUN mkdir /config/dropins/app.war
ADD hello.jsp /config/dropins/app.war/
$ docker build -t test .
略
STEP 1: FROM open-liberty
STEP 2: RUN mkdir /config/dropins/app.war
mkdir: cannot create directory ‘/config/dropins/app.war’: No such file or directory
略
```

たしかにNo such file or directoryでした。
（mkdirの「-p」を端折らなければよかった）

```
$ cat Dockerfile
FROM open-liberty
RUN ls -l /config
RUN ls -l /opt/ol/wlp/usr/servers/defaultServer
RUN mkdir -p /config/dropins/app.war
$ docker build -t test .
Sending build context to Docker daemon  11.78kB
Step 1/4 : FROM open-liberty
 ---> d9c569e91c0f
Step 2/4 : RUN ls -l /config
 ---> Running in 86b86fa3273c
lrwxrwxrwx. 1 default root 37 Nov 10 00:28 /config -> /opt/ol/wlp/usr/servers/defaultServer
Removing intermediate container 86b86fa3273c
 ---> ab3fc83dad56
Step 3/4 : RUN ls -l /opt/ol/wlp/usr/servers/defaultServer
 ---> Running in d8605ca18d65
total 12
drwxrwxr-x. 4 default root 4096 Nov 10 00:28 configDropins
-rw-rw----. 1 default root   41 Nov 10 00:28 server.env
-rw-rw----. 1 default root 1768 Nov 10 00:28 server.xml
Removing intermediate container d8605ca18d65
 ---> 2e59bc0045ad
Step 4/4 : RUN mkdir -p /config/dropins/app.war
 ---> Running in 6a5ab3627efa
Removing intermediate container 6a5ab3627efa
 ---> b2b21cf5e262
Successfully built b2b21cf5e262
Successfully tagged test:latest
$
```

今 2020年11月のlatestは 20.0.0.11
20.0.0.10まではdropinsあったのですが。
（タグを端折らなければよかった）

```
$ cat Dockerfile
FROM open-liberty:20.0.0.10-full-java8-openj9
RUN ls -l /config
RUN ls -l /opt/ol/wlp/usr/servers/defaultServer
RUN mkdir /config/dropins/app.war
$ docker build -t test .
Sending build context to Docker daemon  11.78kB
Step 1/4 : FROM open-liberty:20.0.0.10-full-java8-openj9
 ---> 0720bc6c6ef2
Step 2/4 : RUN ls -l /config
 ---> Running in cd923ea86863
lrwxrwxrwx. 1 default root 37 Oct  7 22:27 /config -> /opt/ol/wlp/usr/servers/defaultServer
Removing intermediate container cd923ea86863
 ---> 6dbe11d624cc
Step 3/4 : RUN ls -l /opt/ol/wlp/usr/servers/defaultServer
 ---> Running in 2fbce99e649c
total 20
drwxrwx---. 1 default root 4096 Oct  7 22:27 apps
drwxrwxr-x. 4 default root 4096 Oct  7 22:27 configDropins
drwxrwx---. 1 default root 4096 Oct  7 22:27 dropins
-rw-rw----. 1 default root   41 Oct  7 22:27 server.env
-rw-rw----. 1 default root 1768 Oct  7 22:27 server.xml
Removing intermediate container 2fbce99e649c
 ---> 4b6955b1f3f4
Step 4/4 : RUN mkdir /config/dropins/app.war
 ---> Running in 1b20af245ea2
Removing intermediate container 1b20af245ea2
 ---> adae5c3fbe06
Successfully built adae5c3fbe06
Successfully tagged test:latest
$
```

20.0.0.11も起動すればdropinsができている。

```
$ docker run -d --name=app open-liberty
1a059a7a687e7b77928d836135a180107ab981f2f85f4ae8e8ea33f9cef7c4a6
$ docker exec -it app ls -l /opt/ol/wlp/usr/servers/defaultServer
total 24
drwxrwxr-x. 1 default root 4096 Nov 10 00:28 configDropins
drwxr-x---. 2 default root 4096 Nov 12 18:56 dropins
-rw-rw----. 1 default root   41 Nov 10 00:28 server.env
-rw-rw----. 1 default root 1768 Nov 10 00:28 server.xml
$
```
dataframeでの関数適用のサンプルです。


#テストデータ
```
import pandas as pd

df=pd.DataFrame({"A":[1,2,3],"B":[10,20,30]})
print(df.to_markdown())
```
|    |   A |   B |
|---:|----:|----:|
|  0 |   1 |  10 |
|  1 |   2 |  20 |
|  2 |   3 |  30 |

#サンプルソース

```
def fnc(dt):
    return dt["A"]+dt["B"]

df["C"]=df.apply(lambda dt :  fnc(dt) ,axis=1  ) 
print(df.to_markdown())
```

# 結果

|    |   A |   B |   C |
|---:|----:|----:|----:|
|  0 |   1 |  10 |  11 |
|  1 |   2 |  20 |  22 |
|  2 |   3 |  30 |  33 |
docker 上の composer 経由で指定位置に laravel プロジェクトを用意するメモ

## 結論: どうやって実現するか

※ docker は事前にインストール・起動済みとします。(コダワリがなければ Docker Desktop https://www.docker.com/products/docker-desktop や WSL2 上に Docker をインストールして使えるようにしとけば OK です。)

例えば、 `~/Documents/tmp/laravel-project-via-composer` という laravel プロジェクトを作るなら以下。

```zsh
% cd ~/Documents/tmp
% docker run --rm -i -t -v $PWD:/app composer create-project --prefer-dist laravel/laravel laravel-project-via-composer
```

1. laravel プロジェクトを配置したいディレクトリに移動して
2. そのディレクトリで `composer` のオフィシャルイメージを使って、 laravel プロジェクトを準備する

これだけ。

（なんなら、 `-i -t` も不要だが、出力が見やすくなるので入れてる。）

これで `~/Documents/tmp/laravel-project-via-composer` に用意される。

`$PWD` を任意のディレクトリすれば、コマンドの発行元ディレクトリはどこでも良いので、 `% cd ~/Documents/tmp` も要らない。(が、うっかりミスとか怖いから、個人的には `cd` してからコマンド実行したい派。)

念の為に書くと `$PWD:/app` の右辺が `/app` となっているのは https://github.com/composer/docker/blob/fbef2df32932859094b4cd3fb072f1e93a7fa1f8/2.0/Dockerfile#L60 にて、 `WORKDIR /app` となっているから。

※つまり、もし、何らかの理由で将来 composer の Docker image の WORKDIR の位置が変わったら同様にコマンド発行時のパスも変更することになる。(使う image の Dockerfile を読むの大切。)

## なぜこの方法を使うのか

- ローカルの環境の PHP や Composer のバージョンとか気にしたくない
- anyenv とかでも管理できるけど、 OpenSSL のバージョン齟齬とかで面倒…
- build するより docker image 使ったほうが早い
- 多くの場合、本来的目的は、 build をしたいのではなく、 laravel プロジェクトを用意したいだけ
- laravel プロジェクト用意した後に、 WEB App 実行用の Dockerfile や docker-compose 用ファイルは別途用意したら良い

たぶん、他のある程度有名な FW やパッケージマネージャーがあるなら同様の考え方で WEB App の下準備ができるはず。(ハードウェアとの通信が必要とか、そういうのは別のお話。)

ハードウェアトラブルや、ハードウェアの乗り換えとかで、いちいちローカル環境を整備するコストを考えると馬鹿らしいので、使えるものは使うと便利かも知れませんよ？というお話でした。

ちなみに `laravel/installer` をインストールして `laravel new hoge` という選択肢も当然にあるのですが、 docker 使って開発環境用意するだけなら composer の image 使って実行した方が楽やん？って思ってます。知らんけど。
MacでAndroidをビルドする際に参考にしたサイト


macでunityをビルドしてAndroid実機でテストする方法
https://note.com/pes88/n/n2141cffd2f8f


UnityでAndroidにビルドする(Mac)
https://sh-lu0.hatenablog.com/entry/2018/12/09/Unity%E3%81%A7Android%E3%81%AB%E3%83%93%E3%83%AB%E3%83%89%E3%81%99%E3%82%8B%28Mac%29


Unity2018インストールからAndroidビルドするまでの手順
https://qiita.com/taroyan/items/2ff7f6aadd640221bde5
※このサイトが一番参考になった



Android Studioは結局使ってない。どこかで使うシーンが出てくるんだろうが、テスト用にAndroidのスマホにビルドしたアプリを入れるだけなら必要なかったので、案外楽チンだった
WordPressのREST APIにアイキャッチ画像のURLを追加する

WordPressのREST APIでアイキャッチ画像のURLを取得して表示しようとしたら画像のIDしか返ってこなくて微妙だったのでURLが返ってくるようにカスタマイズしたメモ。

# 環境

- WordPress 5.5.1
- PHP7.4.0

# コード

``` functons.php
add_action('rest_api_init', 'customize_api_response');
function customize_api_response() {
  // アイキャッチ画像のレスポンスを追加する投稿タイプ
  $post_types = ['hoge', 'fuga'];

  foreach ($post_types as $post_type) {
    register_rest_field(
      $post_type,
      'thumbnail',
      array(
        'get_callback'  => function ($post) {
          $thumbnail_id = get_post_thumbnail_id($post['id']);

          if ($thumbnail_id) {
            // アイキャッチが設定されていたらurl・width・heightを配列で返す
            $img = wp_get_attachment_image_src($thumbnail_id, 'large');

            return [
              'url' => $img[0],
              'width' => $img[1],
              'height' => $img[2]
            ];
          } else {
            // アイキャッチが設定されていなかったら空の配列を返す
            return [];
          }
        },
        'update_callback' => null,
        'schema'          => null,
      )
    );
  }
}
```

これでAPIのレスポンスに下記のように `thumbnail` という項目が含まれるようになりました。

```
thumbnail: {
  url: "https://xxxxxxxxxx.jpg",
  width: 900,
  height: 600
}
```

## 追記

`https://xxxxx/wp-json/wp/v2/posts?_embed` のようにパラメータに `_embed` をつけたら取得できるようになると教えてもらいました。
が、かなり階層の深いところに取りにいかないといけないようです。

https://webtatan.com/blog/wordpress/wp-rest-api-v2-json
Mathematicaで湯婆婆を実装してみる

# 元ネタ

[Javaで湯婆婆を実装してみる](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)

久しぶりにQiitaを覗いてみたら流行ってるのかな？と思って他の人がやらなさそうなMathematicaで実装してみました。

# コード

普通

~~~Mathematica
name = InputString["契約書だよ。そこに名前を書きな。"];
Print[StringJoin["フン。", name, "というのかい。贅沢な名だねぇ。"]];
newname = RandomChoice[Characters[name]];
Print[StringJoin["今からお前の名前は", newname, "だ。いいかい、", newname, "だよ。分かったら返事をするんだ、", newname, "!!"]];
~~~

変数を意地でも使わない版

~~~Mathematica
StringJoin["フン。", #, "というのかい。贅沢な名だねぇ。\n", 
   {"今からお前の名前は", #, "だ。いいかい、", #, "だよ。分かったら返事をするんだ、", #, "!!"} &@
    RandomChoice[Characters[#]]] &@
 InputString["契約書だよ。そこに名前を書きな。"]
~~~

## 簡単な解説

* `InputString` - ノートブックインターフェース上ではVBのInputBoxのようにユーザの入力プロンプトが表示されます。CLIだと標準入力から読み込みます。
* `Characters` - 引数の文字列を1文字ずつに分割したリストにします。例) `"山田太郎"` -> `{"山", "田", "太", "郎"}`
* `RandomChoice` - 引数のリストの中から1要素をランダムに選びます(こういった組込関数があるのがMathematicaの強み)。
* `StringJoin` - `Characters`とは逆に、引数の文字列を結合した1つの文字列にします。

# 実行サンプル

Mathematicaのノートブック上で上記コードのどちらかをコピー&ペーストして[Shift] + [Enter]

## 正常系

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197772/733e00ba-1d96-e091-04b1-d932b36d277d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197772/f29acbec-79d1-5409-508d-3dee867ebd85.png)

## クラッシュ湯婆婆

何も入れなかった場合はMathematicaでもちゃんとエラーになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197772/f27b6f90-5d66-7353-dbcd-5f2b5898f3c5.png)

## 「𠮷田」さん問題

自分が使っているのがMathematica 8と古いせいか、𠮷田さんに対しては無力。
最新のMathematica 12なら大丈夫と思われます(参考:[すべてのUnicode文字を使う: Wolfram言語 12の新機能](https://www.wolfram.com/language/12/networking-and-system-operations/use-the-full-range-of-unicode-characters.html.ja?footer=lang))。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197772/aceadcb2-bc1c-53c5-6d7f-7c7b040ce021.png)

## CLIでワンライナー

CLIでワンライナーも可能です。
ただしマルチバイト文字に非対応のようです。行の途中で勝手に改行もされます。

~~~bash
$ math -run 'Print[StringJoin["フン。", #, "というのかい。贅沢な名だねぇ。\n", List["今からお前の 名前は", #, "だ。いいかい、", #, "だよ。分かったら返事をするんだ、", #, "!!"] &@ RandomChoice[Characters[#]]] &@ InputString["契約書だよ。そこに名前を書きな。\n"]];Quit[]'
Mathematica 8.0 for Linux x86 (64-bit)
Copyright 1988-2011 Wolfram Research, Inc.
契約書だよ。そこに名前を書きな。
山田太郎
フン。山田太郎というのかい。贅沢な名だねぇ。
今からお前の名前は�だ。いいかい、�だよ。分かったら返\
 
>   事をするんだ、�!!
~~~
自動実行処理の方法（Windows OS 上）

こんにちは。
Windows OS 上での自動実行処理（スクリプト）の方法をまとめました。

#####方法1

コマンドプロンプト上でのバッチファイルを作成し実行する

* なお、この際に必要となる Unix 由来コマンド（例えば awk, sed, perl, python など）については、Windows 版を入手しインストールしておく必要がある[^1]。

* なお、「コマンドプロンプト上でのバッチファイル」の代わりに、[PowerShell](https://qiita.com/tags/powershell) 上での PowerShell スクリプトでも可能です。

[^1]: [Chocolatey](https://qiita.com/tags/chocolatey) を利用するとコマンドのインストール作業は多少楽かもしれません。

#####方法2

Windows OS 上の Linux 環境を用意しておき、その上でシェルスクリプトを作成し実行する。

* なお、この際に必要となる Unix 由来コマンドは、基本的には、Linux 環境に始めから付随しているので、改めてインストールする必要は無い。そして、Unix (Linux) OS 上の処理であるので首尾一貫の流儀となる。

* また、Linux 環境の用意は、[WSL](https://qiita.com/tags/wsl) のインストールの方法により、簡素・容易となっている。
PR出す時にSquashしてコードレビューしやすく纏める

## 困りごと
試行錯誤を重ね、<font color="Red">途中にデバッグコードが入ったりしているコミットが大量に含まれた状態</font>で、そのままプルリクに出されるとレビュアーの労力が大きくなってしまう

#### 注意事項

この記事は、
「**統合ブランチのコミットはプロジェクトの履歴であり、個人の記録ではない**」という思想に重きを置いて動いているプロジェクトに限った話になります。

#### 取り扱わないこと
- コミットの粒度や単位をどのくらいの大きさにするべきか

１つのPRに対して、分岐点から最新コミットまでを、１つのコミットに纏めてしまう考え方を取り上げます。

#### 今回の対象ケース

- 試行錯誤を重ね途中にデバッグコードが入ったりしているコミットが大量に含まれた状態で、そのままプルリクに出されるとレビュアーの労力が大きくなってしまう

#### 今回の対象外のケース
- コミット粒度を細かく残しておくことに重きを置かれたプロジェクトなど。


## ▼Squash作業前▼ コミットの並び

```sh
$ git log --oneline


3jr0efj (HEAD -> topic) Last Commit
gdeq394 Comment 05
49rso9d Comment 04
7f4339j Comment 03
2f201gd Comment 02
s7d4jd7 Comment 01
9sae3ox (tag: release-v1.2.1) Merge pull request #53 from Foo/Bar 
```

## Interactiveなrebaseコマンドの挙動

```sh
$ git rebase -i {分岐点のコミットID} {纏めたい最新コミットID}
```

## rebaseの開始点と終了点の指定

- {第一引数} 
  - (必須パラメータ)
  - コミットIDで指定 (ブランチ名指定も可能)

- {第二引数}
  - (省略可)
    - [省略した場合：デフォルト値 = HEADのコミットID]
  - コミットIDで指定 (ブランチ名指定も可能)
 

## (手順1) 分岐点のコミットIDで、Interactive Rebaseを実行

```sh
# git rebase -i {分岐点のコミットID}
$ git rebase -i 9sae3ox
```
## (手順2) デフォルトエディタ起動(vim)が自動起動

```
pick s7d4jd7 Comment 01
pick 2f201gd Comment 02
pick 7f4339j Comment 03
pick 49rso9d Comment 04
pick gdeq394 Comment 05
pick 3jr0efj Last Commit

# Commands:
# p, pick = use commit
# s, squash = use commit, but meld into previous commit
```

## (手順3) pickをsquashに変える (１行目はpickにすること)

```
pick s7d4jd7 Comment 01
s 2f201gd Comment 02
s 7f4339j Comment 03
s 49rso9d Comment 04
s gdeq394 Comment 05
s 3jr0efj Last Commit

# Commands:
# p, pick = use commit
# s, squash = use commit, but meld into previous commit
```

- 上書き保存 (vimなら、`:wq`)  

## (手順4) ２度目のvimの自動起動

- Squashで纏めあげたコミットメッセージを編集
  - 「#」がついているところは、コメントアウト  

今回は例として、コミットメッセージを以下のようにします。

```sh
Squashで１つに纏めたコミットです
```

- 上書き保存 (vimなら、`:wq`)  

## (手順5) 完了

## ▼Squash作業後▼ コミットの並び

```sh
$ git log --oneline

83vdkwf (HEAD -> topic) Squashで１つに纏めたコミットです
9sae3ox (tag: release-v1.2.1) Merge pull request #53 from Foo/Bar 
```

## あとがき

コードをレビューしてもらう側の立場にいる際には
コードレビューをしてくださるレビュアーさんに
配慮したプルリクを送りたいですね。(自戒も込めて)
  
そして、レビュアーさんの負担を
減らすことができれば、
コードレビューの精度も上がり
結果的にチーム全体として
恩恵を受けられることに繋がるのかもしれません。
【React Native】Invariant Violation "main" has not been registered. This can happen if: *Metro (the local dev server ... の解決法

## はじめに
自分の場合は[とても処方的なミス](#自分の解決策)でした (react-navigationが関係)
他にもいくつか試した対処法も載せてあります。

expoで開発していたら以下の様なエラーが起きた。

``` shell
Invariant Violation "main" has not been registered. This can happen if: *Metro (the local dev server) 
is run from the wrong folder. Check if Metro is running, stop it and restart it in the current project.*
A module failed to load due to an error and `AppRegistry.registerComponent` wasn't called.
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488042/4b72a247-a7d3-1051-fa24-56b1f921ecfc.png" width=60%/>

## 環境
```json-doc
// app.json
   {
    "sdkVersion": "38.0.0"
   }
// package.json
  "dependencies": {
    "expo": "^38.0.8",
    "react-native": "^0.62.2",
    "react-navigation": "^4.4.3",
    "react-navigation-stack": "^2.10.0",
    "react-navigation-tabs": "^2.10.1",
   }
```

## 試した対処法
調べてみるといくつか方法があった

### 1つめ
1. watchman watch-del-all
2. node_modules & package-lock.json (もしくはyarn.lock) の削除
3. `npm install` (もしくは`yarn install`)
4. `expo install react-native-safe-area-context`
5. `expo start`

試してみたが画面は変わらず。。

### 2つめ
1. expoを止めている状態で、`ps aux | grep react-native` を実行して動いているプロセスを探す
2. 結果が表示されたら、そのプロセスを `sudo kill 'pid'`

自分は動いてるプロセスは見つけたものの、killすると
`kill:'pid': No such process`
と出て解決には至らず。。

### 3つめ
package.jsonのnameとApp.jsonのexpoのnameを同じにする

→ 何も変わらず

##自分の解決策


結局めちゃくちゃ初歩的なミスでした。。
react-navigationを使っている部分で、 `createAppContainer`を呼んでいるが、肝心のimportをし忘れていた為、エラーが起こっていた様です。

今回のような場合だけでなく


```react
// ここを書き忘れていた
// import { createAppContainer } from "react-navigation";

 const AppContainer = createAppContainer(HomeTab);
```

普段こんな場合は
`ReferenceError: Can't find variable: Button` 
とかでエラーが出ると思うのですが。。。

importの部分を書き足すと正常に動作しました。

ルーティング周りで変更を加えた場合は、そこの箇所を戻してみると治るかもしれません。

##### 2020/11/14 追記

```react
export default class Index extends React.Component{}
```
この部分を

```react
export default class Index extends React.Component(){}
```
と不要な()をつけてしまった為、同じエラーが起きた。

おそらく特定のパターンに絞れないエラーなので、まずはコードに間違いが無いか確認してみると良いと思います。

### メモ
「`expo start --no-dev --minify`で起動すると解決する」
とexpoのForumsにあったので、試してみると確かに一時的に解決した。
[Forums] (https://forums.expo.io/t/application-main-has-not-been-registered/11753/4)

しかしこれはproduction用にアプリをminifyして不要な部分を削っている為、部分的に解決しただけだと思われる。
[expo -Development and Production Mode] (https://docs.expo.io/workflow/development-mode)
zshに変えて変なコマンド打ったらパスが通らなくなった話

初めまして。マレーシアの大学に通うしがない学生です。これからたま〜に記事を投稿することもあるかと思います。よろしくお願いします。

#この記事を書くきっかけ

Webサービスを構築しようと思い、Vagrantで仮想環境を整えている時でした。その足音が近づいてきたのは。
iTermsが僕に何かささやいてくるのです。
>Bashなんか古くない〜？今時はzshでしょ〜

そんな言葉を鵜呑みにしてしまい、色々な記事を見て勉強しました。

>なるほど。拡張性に優れていて楽しいCLIライフを送れそうだ。

と思い、早速試してみることに。

ここからです。地獄の時間を過ごすことになったのは。。。

#環境変数ってなんだ？
変更して、どうやら.bash_profileに記述してある環境変数をそのまま.zprofileにコピーするといったコマンドだったと思います。
安易に打ってしまい、そこからエラーの連続。
e.g) 

```iTerms.
$brew
zsh: command not found: brew
```

大して理解していなかった細かい環境変数のことを色々調べるハメに。。

#解決策
本当に色々試してみても全くうまくいかず、初期化すら考えたところでした。
ふとこんな考えが脳裏を過りました。

>いったんファイルの中の記述消してみたら？

ああ、なるほど。それでもなおエラーを吐くようだったら~~死んでしまえ。~~消してしまおうと思いました。

ファイルの中を消してみて、今まで通らなかったコマンドを試してみたところ。

>あれ？これいけてね？

本当にしょうもないことで詰まっていたんだと痛感。

無事解決できました。

#最後に
本当に悩んでいる人もいるかもしれないと思ったため、この備忘録を残しておこうと思いました。

Twitter: @ryuji_vlog
vim-pandoc-syntaxでurlを非表示にしたい



# markdown/vimwiki/pandocのsyntaxハイライト

vimwikiのsyntaxでは、以下のようなリンクは

```markdown
[説明](url)
```

このように表示されます(`+conceal`オプションが有効な場合)

[説明](url)

これがあると、長いURLを持つドキュメントでの可読性がグンと上がります

例えば、[blender data blocks](https://cj-bc.github.io/blog/posts/2020-08-19-blender-data-blocks.html)の記事は`markdown`/`vimwiki`/`pandoc`それぞれのsyntaxで
以下のように見えます。

![markdown, vimwiki, pandocのハイライトの違い](https://cj-bc.github.io/blog/images/2020-11-13-pandoc-vim-conceal-url-by-default/difference_md-vimwiki-pandoc.png)

さて、これを普段使いの`pandoc`syntaxでも使いたいというのが今回の希望です。

# 結論: デフォルトの変数を設定しろ

もうこれが答えでした！  
ドキュメントよもうね！！！！

```vim
let g:pandoc#syntax#conceal#urls = 1
```

これだけでURLの`conceal`が有効になり、vimwikiと同じような見た目になります

![設定後のpandoc](https://cj-bc.github.io/blog/images/2020-11-13-pandoc-vim-conceal-url-by-default/pandoc-with-conceal.png)

# おまけ

ちなみに該当のコードは[300-304行目](https://github.com/vim-pandoc/vim-pandoc-syntax/blob/2521e2e9b99a3550e1a20f24e09fa46679cbbbc7/syntax/pandoc.vim#L300-L304)にありました。

``` vim
if g:pandoc#syntax#conceal#urls == 1
    syn region pandocReferenceURL matchgroup=pandocOperator start=/\]\@1<=(/ end=/)/ keepend conceal
else
    syn region pandocReferenceURL matchgroup=pandocOperator start=/\]\@1<=(/ end=/)/ keepend
endif
```
M5Stackで複数のntrip casterの設定を切り替え出来る装置を作る

##目標
RTK基地局が調子悪い時に切り替えたい

##UI作ればいい
わかってるよそりゃ・・。けど大変。

##力技で解決する
LovyanLauncher
https://raspberrypi.mongonta.com/howto-start-m5stack-m5burner-lovyanlauncher/
SDカードに基地局の設定を変えたbinファイルを置き、LovyanLancherで書き換える。

##ソース
###M5Stackのセットアップ
https://mag.switch-science.com/2018/02/28/getting-started-with-m5stack/

###ntrip client for arduino
zipでダウンロードして、arduinoに入れてください。
https://github.com/GLAY-AK2/NTRIP-client-for-Arduino

<details><summary>ソース</summary><div>

```M5Stack_NTRIPClient_v3
/*
 *  NTRIP client for Arduino Ver. 1.0.0 
 *  NTRIPClient Sample
 *  Request Source Table (Source Table is basestation list in NTRIP Caster)
 *  Request Reference Data 
 * 
 * 
 */
//#include <ESP8266WiFi.h>  //Need for ESP8266
#include <WiFi.h>           //Need for ESP32 
#include "NTRIPClient.h"

//M5stack
#include <M5Stack.h>
#include <M5StackUpdater.h>

const char* ssid     = "your_ssid";
const char* password = "your_password";

char* host = "ntrip caster host";
int httpPort = 2101; //port 2101 is default port of NTRIP caster
char* mntpnt = "ntrip caster's mountpoint";
char* user   = "ntrip caster's client user";
char* passwd = "ntrip caster's client password";
NTRIPClient ntrip_c;

void setup() {
  M5.begin();
  Wire.begin();
  if(digitalRead(BUTTON_A_PIN) == 0) {
    Serial.println("Will Load menu binary");
    updateFromFS(SD);
    ESP.restart();
  }  
  // put your setup code here, to run once:
  Serial.begin(115200);
  delay(10);
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  
  Serial.println("Requesting SourceTable.");
  if(ntrip_c.reqSrcTbl(host,httpPort)){
    char buffer[512];
    delay(5);
    while(ntrip_c.available()){
      ntrip_c.readLine(buffer,sizeof(buffer));
      Serial.print(buffer); 
    }
  }
  else{
    Serial.println("SourceTable request error");
  }
  Serial.print("Requesting SourceTable is OK\n");
  ntrip_c.stop(); //Need to call "stop" function for next request.
  
  Serial.println("Requesting MountPoint's Raw data");
  if(!ntrip_c.reqRaw(host,httpPort,mntpnt,user,passwd)){
    delay(15000);
    ESP.restart();
  }
  Serial.println("Requesting MountPoint is OK");

  
}

void loop() {
  // put your main code here, to run repeatedly:
  while(ntrip_c.available()) {
        char ch = ntrip_c.read();        
        Serial.print(ch);
        
  }
}
```
</div></details>

##電気的なこと
Trimble等のGPS装置にRTCM3を流す場合、M5Stackから出てくる信号をRS232に変換する必要があります。
https://www.amazon.co.jp/dp/B00OPTOKI0/
Note Book : Don't work Python with OpenCV on AMD Ryzen CPU on WSL2 Ubuntu 18.04 And 20.04

MAIN BOARD
ASUSTek COMPUTER INC.
PRIME X570-PRO
Rev X.0x

CPU
AMD Ryzen 7 3700X

MEM
G.Skill DDR4 3600

GPU
RTX 3900

It's looks like this error.
Don't work.

```
$ python
>>>import cv2
WARNING: CPU random generator seem to be failing, disable hardware random number generation
WARNING: RDRND generated: 0xffffffff 0xffffffff 0xffffffff 0xffffffff
```

Maybe it.
https://askubuntu.com/questions/1264439/warning-cpu-random-generator-seem-to-be-failing-disable-hardware-random-number

I update bios. It's fatal.
It's working update after.
My computer use PRIME X570-PRO BIOS 0602. I set up PRIME X570-PRO BIOS 2802.

```
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>>
```
【SwiftUI】【Xcode12】AppDelegate.swift と SceneDelegate.swift が無いんだが

# なぜ

Xcode12で新しくプロジェクトを作る際に『Interface』の選択肢で「SwiftUIでコードを書くから」ということで **UIKit App Delegate** ではなく **SwiftUI App**を選択すると掲題の2ファイルが作られない。
で、何が困るのかというとスーパー初心者がテキストなどを参考にした際に掲題のファイルにアレコレ書いてくれとあるが、そんなファイルが無いから困ってしまったのだ。

## なんとかする

`Test`という名前のプロジェクトを作ったと仮定する。

```Swift:TestApp.swift
//
//  TestApp.swift
//  Test
//
//  Created by 名前 on 日付.
//

import SwiftUI

@main
struct TestApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {

            // SceneDelegate.swift の代わりとして仮定
            // 最初に表示したい画面のファイル名を書く。例えば Index.swift の場合
            Index()
        }
    }
}

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        
        // この間に AppDelegate.swift の処理を書く。今回は書いてない
        
        return true
    }
}

struct TestApp_Previews: PreviewProvider {
    static var previews: some View {
        /*@START_MENU_TOKEN@*/Text("Hello, World!")/*@END_MENU_TOKEN@*/
    }
}


```

現時点でぼくがわかるのはこれくらいです。
以下のサイトを参考にしました。

**[Xcode 12] アプリの起動について変更になった部分まとめ**
<https://dev.classmethod.jp/articles/xcode12_change_appdelegate/>
DynamoDB オンデマンドモード ≠ エラーなしのアクセスし放題

# 問題

DynamoDB をオンデマンドモードにして運用していればテーブルへのアクセス集中による対処(スロットリング）は気にしなくても良い。 **というのは間違った認識である。**

[オンデマンドの DynamoDB テーブルを使用していますが、まだスロットルされています。なぜでしょうか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/on-demand-table-throttling-dynamodb/) にあるように、例えオンデマンドモードであってもスロットリングは発生する。

## そもそもリクエスト単位って何？

ここの説明に書いてある「リクエスト単位」というのは何を意味するのだろうか？　読み込み・書き込みがあるが、今回は書き込み側に絞ってみていく。

定義は [ここ](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html) に書いてある。 同ページ内に書き込みキャパシティ単位(WCU)の説明もあるので混同に注意。

### 書き込みリクエスト単位 (Write Request Unit, WRU)

> One write request unit represents one write for an item up to 1 KB in size. If you need to write an item that is larger than 1 KB, DynamoDB needs to consume additional write request units. Transactional write requests require 2 write request units to perform one write for items up to 1 KB. The total number of write request units required depends on the item size. For example, if your item size is 2 KB, you require 2 write request units to sustain one write request or 4 write request units for a transactional write request.

要約すると以下の通り。

- 「どれだけ使ったか（＝課金に関する値）」を意味する
    - ap-northeast-1 の場合は 100 万 WRU あたり 1.4269 USD (記事執筆時点)
- 1WRUは **最大1KB** のデータを **1つ** 書き込んだことを意味する
- 1KBより大きいデータを書き込むときは、1つ上のサイズに切り上げた分のWRUを消費する (1.5KBのデータなら2 WRU)
- トランザクションで書き込むときはさらに2倍

各種ドキュメントを探してもこういう結果になるのだが、この定義だと [オンデマンドの DynamoDB テーブルを使用していますが、まだスロットルされています。なぜでしょうか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/on-demand-table-throttling-dynamodb/) で説明されている

> テーブルの各パーティションは、最大 3,000 の読み取りリクエスト単位または 1,000 の書き込みリクエスト単位、またはその両方を線形的に組み合わせることができます。

という内容を説明できない。 素直に読むと "1000件しか書き込みができない" となってしまう。

なので、おそらくではあるが、これらの文脈では **per second が省略されている** とみてよいと思う。 というのも、いくつかの記事を見る中では、WRU/sec などとして用いられていたためである。

- https://tarepan.hatenablog.com/entry/2018/02/12/AWS_DynamoDB
- https://pages.awscloud.com/rs/112-TZM-766/images/Session%204%20-%2020200825_CyberZ_OPENRECTV_Purpose-Built-Databases-Week-v2.pdf

なので、定義のページを読んでも読み取れないので不安ではあるが、

- 文章で書き込みリクエスト単位の数値が提供されている場合、それは1秒間に書き込み処理できる最大数である (/secが省略されている)

と、捉えることとする。　

それを踏まえると、[AWS アカウントのオンデマンドのデフォルトでは、40,000 RRU / 40,000 WRU となっている](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Limits.html) ため、秒間に 40,000 単位の読み込み・書き込みに対応しているが、上限緩和をしない限りはいくらうまく使ったとしても、これ以上の速度で処理を行えないということではある。


# 調査するに至ったきっかけ

今回出くわしたのは「**同一パーティション** の大量のデータ書き込みを SQS + Lambda の組み合わせで遅延処理で実施」した。 その結果スロットリングが発生してデータが書き込めない状況が発生した。
テーブル自体は最初からオンデマンドで作成しており、このデータ書き込みが発生するまではほとんどアクセスがない状態だったので、２倍に引き上げたところで性能が追い付かず、また、同一パーティションの書き込みだったので同一シャードにのみ負荷をかけることとなり、結果として上述で示されていた限界よりもかなり小さい 300 ～ 500 WRU / sec あたりでスロットリングの発生を確認した。 少し調整して、100 ～ 125 WRU / sec あたりを維持することでスロットリングは発生しなくなった。

ここを動的に調整しようと思うと、[トラブルシューティングの記事にならって](https://aws.amazon.com/jp/premiumsupport/knowledge-center/on-demand-table-throttling-dynamodb/) 、 **Provisionモードで事前に高いCapacity Unitを持つテーブルを作成し、これをOn-Demandに変更する** 方法や、**30分前からウォームアップをしてトラフィックピークを予見する** といった方法がある。

ただ今回自分が起こした問題については「同一パーティション」にしてしまったことがそもそもの問題である。 この手の処理で並列投入する予定はなかったが必要になってしまった。

ので、「DynamoDBをオンデマンドで使っているから、スロットリングによってエラーが返ってくることはない」と誤った認識で開発するのではなく、大量書き込み・読み込みが行われるかをちゃんと設計段階で考慮して使わなければならない。
【Java】オブジェクトの中のキーでdistinctを行いたい

## 概要
JavaもStreamの機能が実装されてから、Listから重複削除（distinct）が行えるようになりました。ただ、[【Java8】Streamで重複削除（& 重複チェック）](https://qiita.com/wrongwrong/items/02c03de086c2e46c1390)の記事にある通り、標準の機能ではListの値のみで重複削除が可能であり、Listがオブジェクトの場合にオブジェクトの中の指定したキーで重複削除が行えません。
ということで、今回はどのようにしたらオブジェクトの中の指定したキーで重複削除を実現できるか、というのを書いてみます。

## 対応候補
[Stream.distinctをフィールド・プロパティなどで行うには](https://qiita.com/duffelcat/items/70bf2a21f0465e9c18ca)の記事にある通り、distinctを使わずにfilterとHashSetを組み合わせて重複削除を実現する方法が紹介されています。また、[Java 8 Distinct by property](https://stackoverflow.com/questions/23699371/java-8-distinct-by-property)の記事には、groupingByを使う方法やクラスをWrapperする方法、ライブラリを使う方法が紹介されています。
方法は色々あって、どれでも良いかなとは思うのですが、今回は`RxJava`のライブラリを使う方法を紹介します。

<2020/11/13追記>
@Rui_K さんのコメントで紹介頂いた記事[Java8のStream distinctを使用する方法](https://codechacha.com/ja/java8-stream-distinct/)では、標準Streamのdistinctの内部処理ではequalsが使われているようです。なので、equalsメソッドに同一判定のロジックを実装すれば、標準のメソッドでも対応できそう。


## RxJavaを使った重複削除
RxJavaとは[今さらながらのRxJava - 概要編](https://tkhs0604.hatenablog.com/entry/rxjava-overview)の記事に紹介されている通り、リアクティブプログラミングを実現するために開発されたライブラリです。RxJavaで用意されているObservableクラスにおいてdistinctメソッドが用意されていて、このメソッドでは重複対象とするキーを指定することができます。こちらの[ドキュメント](http://reactivex.io/RxJava/javadoc/rx/Observable.html#distinct-rx.functions.Func1-)を参照ください。
サンプルコードは以下の通りです。ここではUserクラスのemailの値で重複削除を行っています。

```sample.java
List<User> distinctUserRecords = Observable.fromStream(userRecords.stream())
    .distinct(u -> u.getEmail()).toList().blockingGet();
```
PHPプロジェクトで導入すると便利そうなツール5選

# はじめに
PHPプロジェクトで導入すると便利そうなツールをまとめてみました。

## 自動テスト
### PHPUnit
PHPでの単体テストと言えばPHPUnitが最も有名かと思います。
やり方についてはググればいくらでもでてきますので、ここでは個人的所感を書いていきます。

###### 手動テストが不要になるわけではない
自動テストを頑張って書いていればある程度の動作保証にはなると思いますが、それによって手動テストが完全に必要なくなるかと言われればそうはならないと思っています。

###### ただ凡ミスは防げる
リファクタリング時にテストを実施した際に「あ、やべここ壊れれてた。危ない危ない。」というのは何回かありました。

###### 複雑なパターンの検証には便利
少しずつ条件を変えてテストしなければならない箇所には、自動テストがかなり力を発揮してくれるかと思います。

###### テスタビリティの高いコードはいいコード
これが大きいメリットかなと個人的には思っています。
魔のメソッドを生み出してしまった際これどうやってテストコードに落とし込むの？と自問自答してしまうことがありました。
単一責任の原則から乖離したメソッドは、テストがしづらいです。逆に言うとテスタビリティの高いコードというのは責務が明確になっています。これは仕様変更などの際に影響範囲が明確になり、対応が行いやすくなります。

自動テストは手動テストの代替手段とだけ考えていましたが、実際には設計にも役立ちました。
また、カバレッジレポートの出力を行えばデッドコードや不要な引数などもひと目でわかるようになりますので、コードの品質維持にもつながっていきます。

## デバッグ手法
### XDebug
「XDebug」は、PHPのデバッグ用の拡張モジュールになります。

プロファイリングツールとして処理が遅い部分を突き止めてくれたりもするらしいですが、私はバグ調査時などに重宝しています。

ステップ実行は神です。延々と変数をログに吐き出していた頃が懐かしいです。教えてくれたチームメンバーありがとう。
PHPで開発する際は必須なツールかと思います。私はもう手放せません。

## ボトルネック調査（プロファイリング）
### Blackfire
実効効率を改善する場合に用いられるプロファイリングツールです。
私自身まだ使ったことはないのですが、PHPでのプロファイリングツールで調べるとXDebugとBlackfireの記事がよくでてきたので、機会があれば使ってみたいと思います。

## バグの事前検知
### phpmd
PHPの静的解析ツールになります。
潜在的なバグになりそうな部分や実装上の問題を検出してくれるツールです。

## マニュアルの自動生成
### PHPDocumentor
PHPDocやタイプヒンティングが書いてあるコードであればそれを元に自動でドキュメントを生成してくれるツールです。
生成されたドキュメントよりも、これがあることにより、PHPDocなどが適切に書かれることになりチーム開発での品質維持に繋がりそうだなと思いました。個人でやるというよりは、チームとして取り決めて使っていく方がよさそうです。

# まとめ
エンジニアなりたての頃（まだペーペーですが）はとりあえず動けばよしという感じだったのですが、運用や保守を経験していくうちに過去の自分に苦しめられることが何度もありました。そして今の自分も未来の誰かを苦しめる可能性が常に存在しています。その可能性を少しでも減らすために、ツールの力も借りつつテスタビリティが高いコードを書いたり、ドキュメントを残したりとできることはやっていかなければならないなと思っています。
また、バグ調査時などもツールを駆使して早期解決に役立てたいなと思いました。
mateのcajaでコンテキストメニューからvscode

# 概要

- Linux向けのデスクトップ環境mateのファイルマネージャーcajaのコンテキストメニューをカスタマイズ
- 右クリックでコンテキストメニューを開いてvscodeを起動

# 環境セットアップ

- 実験環境はFedora31
- ``rpm -qi caja-actions`` でcaja-actionsがインストールされているか確認
    - なければ ``dnf install -y caja-actions`` でインストール

# コンテキストメニューのカスタマイズ

- 設定アプリを起動する

```text
$ caja-actions-config-tool
```

- Editメニュー/設定を開いて「Create a root 'Caja-Actions' menuのチェックを外す
![settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147328/3419f01a-728d-8e0a-3747-1fc7341d014d.png)
- "Define a new action" を押して以下のように入力する
![newAction.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147328/a67ba9af-62e1-77e1-7f79-2d9ae3052897.png)
- commandタブでコマンド情報を入力する
![Screenshot at 2020-11-13 00-37-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147328/f88787bb-4412-bc99-ed5e-268ecf342418.png)
- 保存して終了

# 使う

- Cajaの右側ペインでコンテキストメニューを開くと「vscode」が現れます
- Cajaの左側ペインのコンテキストメニューには現れないようです
【Ruby】正規表現でマッチした文字列の一部分だけを置換するには？

## 問題

以下のような文字列があった場合、`.png` で終わるURLの`http`だけを`https`に変えることはできるでしょうか？

```ruby
str = 'kkk<a href="http://abcdege/hoge222/bar/t22est.md">aaab.png 
bbb<a href="http://abcdege/ho22aage/bddfear/ted2st.png">aaak
ubotabbbccxcb <a href="http://abcdege/22hoge/b22ar/tfeest.md">aa23a
bbkubotasbbb <a href="http://abcdege/hoffee11ge/bar/test.html">appkub
otapoooabbb<a href="http://abcdege/ho22aage/bddfear/ted2swwt.png">ab
ddbbb.png'
```
## 考察

結構悩みました。
rubyのgsub(正規表現, 文字列)メソッドを使って置換しようとしたのですが、

* 正規表現でマッチするものがURL全体
* そのマッチしたURLをある固定の文字列で置換してしまう

そこで、マッチしたもの（URL）の一部分（今回はhttpの部分）だけを置換する方法はないか考えました。

## 考えた結果

上記の考え方では思いつかなかったです。そもそも、gsub(正規表現, 文字列)メソッドのメソッドだけを使おうとする考えがよくなかったかもしれないです。
正規表現のブロックみたいなのを使った方法もあるかもしれないですが。
**ただ、結局、それと同等の結果を導く手順は作成できました。**

２段階subで置換します。

#### 考えたアルゴリズムの大枠
* .png で始まるURLをすべて配列に格納
* その配列の要素を１つずつ読んで

```
".png で始まるURL".gsub(http, "https")
```
で置換するとい流れです。

#### 考えたアルゴリズムの詳細（完成品）
* .png で始まるURLをすべて配列に格納

まず文字列からURLを抜き出します。
ここで、`String#scan`を使おうと思ったのですが、「文字列からURLを抽出する」というメソッドがすでにあるようです。。(すごすぎる)
参考：[文字列からURLを抽出する - Ruby Tips!](
http://rubytips86.hatenablog.com/entry/2014/03/23/072416)

```ruby
URI.extract(str)
#=> ["http://abcdege/hoge222/bar/t22est.md", "http://abcdege/ho22aage/bddfear/ted2st.png", "http://abcdege/22hoge/b22ar/tfeest.md", "http://abcdege/hoffee11ge/bar/test.html", "http://abcdege/ho22aage/bddfear/ted2swwt.png"]
```
次に、これらを使ってそれぞれを判断して置換していきます。
###### （完成品）

```ruby
URI.extract(str).each do |uri|
  if /.*(\.png)$/.match(uri)
    new_uri = uri.sub("http","https")
    str = str.sub(uri, new_uri)
  end
end
str
#=> "kkk<a href=\"http://abcdege/hoge222/bar/t22est.md\">aaab.png \nbbb<a href=\"https://abcdege/ho22aage/bddfear/ted2st.png\">aaak\nubotabbbccxcb <a href=\"http://abcdege/22hoge/b22ar/tfeest.md\">aa23a\nbbkubotasbbb <a href=\"http://abcdege/hoffee11ge/bar/test.html\">appkub\notapoooabbb<a href=\"https://abcdege/ho22aage/bddfear/ted2swwt.png\">ab\nddbbb.png"
```
２段階subで置換するのがポイントな気がします。
VSCode の php-cs-fixer で使っている設定

## このページについて
PHP を VSCode を使用して開発する事がことが多く、
現場が変わる度に設定を調べ直すのが面倒だったので、ここにメモがわりに書くことにする。

```settings.json
  "php-cs-fixer.onsave": true,
  "php-cs-fixer.executablePath": "${extensionPath}/php-cs-fixer.phar",
  "php-cs-fixer.lastDownload": 999999999999999,
  "php-cs-fixer.rules": {
    "@PSR2": true, // PSR-2 Coding Style Guide に即した形式にフォーマットする
    "no_unused_imports": true, // 使用していない use 句を削除する
    // "ordered_imports": true, // use 句をアルファベット順にソートする
    "array_syntax": { "syntax": "short" }, // 配列の定義方法を短縮形（例： $hoge = [];）にする
    "single_quote": true
  },
  "[php]": {
    "editor.defaultFormatter": "junstyle.php-cs-fixer"
  },
```
AWS SQS FIFOの並列動作について書いておく

## AWS SQSではグループIDが異なれば並列で動くのか？

標準SQSであれば受信可能なメッセージから極力FIFOで処理されていきますが、基本的には順序保証なくどんどん消化されます。
トリガーにLambdaが設定されていれば、複数のLambdaインスタンスにより処理されていきます。

ではFIFOはどうなのか？

FIFOはグループID単位で順序を保証します。
ではグループIDが異なっていればどうなるか？

例えば

1番目 グループID:A 8:00:01にキュー登録
2番目 グループID:A 8:00:02にキュー登録
3番目 グループID:B 8:00:03にキュー登録
4番目 グループID:C 8:00:04にキュー登録

とした場合。
トリガーのLambdaは10秒処理がかかるとします。

この場合は
１番目→３番目→４番目→２番目

の順でメッセージを取得していきます。
このとき、３番目の実行タイミングは１番目が実行中のときに開始しますので、8:00:03に処理開始します。
４番目も同じく、8:00:04に処理を開始します。
２番目のキューは１番目の処理が完了してから動作するため、8:00:11秒から動作します。



## 相変わらずわかりにくい公式ドキュメント

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html

![スクリーンショット 2020-11-13 0.23.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59457/475b14f9-5526-9a02-d917-8fe49c8eb9fe.png)

プロデューサーとか言われても。。。

## ということで

FIFOだからグループIDが別であっても先入れしたメッセージが取得して終わらなければ、次のメッセージ取得はブロッキングされてしまうのではと言う不安、ありますよね。
実際に動作させてみたところ、前述のような動作することが確認できました。
ただ実際のところグループIDが別れていれば並行してメッセージが取得されるかと言われると、それは言い切れないかもしれません。

というのもSQSトリガーのLambdaは初期状態では５インスタンスしかありません。
メッセージの増加に従いスケールしていき、最終的には上限の同時期同数に達します。
ただ増加はそこまで急激ではなく、メッセージの増加量に追いつかないケースが考えられます。

その場合はおそらくスロットリング。。。
WireGuardを使って爆速でVPNトンネルを構築する

## せっかちな人向け
aptでWireGuardをインストールして、
[Wireguard Config Generator](https://www.wireguardconfig.com/)で設定を生成して、
systemctlでサービス化すれば完成！

## はじめに
この記事ではVPSと自宅LAN内に設置したラズパイの間にトンネルを張ること目指す。
順調に進んだ場合10分程度で完了する。

## 環境
- サーバー側
    - Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-52-generic x86_64)
- クライアント側
    - Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-1021-raspi aarch64)

## 手順
### WireGuardのインストール

サーバー側・クライアント側ともに同様にインストールする。

```bash:
sudo apt update
sudo apt install wireguard
```

### 設定の生成

[Wireguard Config Generator](https://www.wireguardconfig.com/)を使うと簡単に設定を生成できる。
各項目を入力し、[Generate Config]をクリックすると設定が書き出される。
今回は下記の設定を使用する。

- Listen Port
    - ポート設定
    - 今回はデフォルトの値(51820)を使用
- Number of Clients
    - クライアントの数
    - 今回は1を指定
- CIDR
    - 構築される仮想ネットワークが使用するIP
    - 今回はデフォルトの値(10.0.0.0/24)を使用
- Client Allowed IPs
    - クライアント側から仮想ネットワーク上に流すIPの範囲
    - カンマ区切りで複数指定できる
    - 今回はサーバー側のIPアドレス(10.0.0.1/32)を指定
- Endpoint (Optional)
    - [サーバーのグローバルIPアドレス]:[Listen Port]
    - IPv4でもIPv6でも良い
- DNS (Optional)
    - 今回はいらない
    - クライアントの通信を全てサーバー経由にしたい場合は設定する必要がある
- Post-Up rule, Post-Down rule
    - 今回はいらない
    - クライアントの通信を全てサーバー経由にしたい場合は設定する必要がある
- Use Pre-Shared Keys (Enhanced Security)
    - 使うとよりセキュアになる
    - 今回は有効にする

### 設定の保存

サーバー側・クライアント側ともに生成された設定を `/etc/wireguard/wg0.conf` に書き込む。
それぞれの[Peer]の最後に `PersistentKeepalive = 10` を追記し、常時接続となるようにする。
また、MTU値を調整すると接続が安定するので、[Interface]に `MTU = 適切な値` を指定する。
とりあえず1350あたりを設定しておけば安定するはず（詳しくないので適当ですが許してください）。

最終的に下記のようになる。（PrivateKey, PublicKey, PresharedKeyはマスク済み）

```:/etc/wireguard/wg0.conf（サーバー側）
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
MTU = 1350

[Peer]
PublicKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
PresharedKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
AllowedIPs = 10.0.0.2/32
PersistentKeepalive = 10
```
```:/etc/wireguard/wg0.conf（クライアント側）
[Interface]
Address = 10.0.0.2/24
ListenPort = 51820
PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
MTU = 1350

[Peer]
PublicKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
PresharedKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
AllowedIPs = 10.0.0.1/32
Endpoint = [サーバーのグローバルIPアドレス]:51820
PersistentKeepalive = 10
```

### ポート開放

サーバー側のポートをudpを指定して開放する。

```bash:ufwの場合の例
sudo ufw allow 51820/udp
sudo ufw reload
```

### デーモン化

サーバー側・クライアント側ともにsystemctlの設定を行い、起動時にトンネルを張るように設定する。

```bash
sudo systemctl start wg-quick@wg0
sudo systemctl enable wg-quick@wg0
```

### 疎通確認

```bash:サーバーからクライアント
ping -c 3 10.0.0.2
```
```bash:クライアントからサーバー
ping -c 3 10.0.0.1
```

## おわり

WireGuardは非常にお手軽で素晴らしい。
[Wireguard Config Generator](https://www.wireguardconfig.com/)もお手軽で素晴らしい。
docomo らくらくホン F-02J 物理ボタンのキーコード一覧

# 前書き
## 環境
|データ|値|
|:--|:--|
|メーカー|Fujitsu (docomo)|
|機種|F-02J|
|Androidバージョン|5.1.1|
|ビルド番号|V28R066A|

## 調べ方
Android API の`onKeyDown`メソッド引数`keyCode`を参照

# 実測値
## ダイヤルパッド
|表示キー|キーコード|
|:--|:--|
|1|8|
|2|9|
|3|10|
|4|11|
|5|12|
|6|13|
|7|14|
|8|15|
|9|16|
|*|17|
|0|7|
|#|18|

## ワンタッチダイアル
|表示キー|キーコード|備考|
|:--|:--|:--|
|１|96|外部アプリケーションのポインタ切り替えにも利用（無効化不可）|
|２|97|
|３|98|

## 方向・サブメニューキー
|表示キー|キーコード|備考|
|:--|:--|:--|
|↑|19|
|↓|20|
|←|21|
|→|22|
|決定|23|
|メニュー|131|Androidの機能に割り当てられている可能性あり（詳細不明）|
|電話帳|132|

## 発信・戻る
|表示キー|キーコード|備考|
|:--|:--|:--|
|発信|5|
|戻る|4|AndroidのBackボタンに割り当て|
|切断|-|不明（アプリケーションの終了になっているため）|

## 本体下部ファンクションボタン
|表示キー|キーコード|備考|
|:--|:--|:--|
|使い方|104|
|らくらくサイト|105|
|カメラ|103|

## サイドボタン
|表示キー|キーコード|備考|
|:--|:--|:--|
|読み上げ|102|
|+|24|
|-|25|

## ワンタッチブザー
|表示キー|キーコード|備考|
|:--|:--|:--|
|ワンタッチブザー|83|（引き抜き時のみ。引き抜き状態では画面が隠される）|
OAuth 2.1 と 2.0 で適当に diff をとってみた

Original: [OAuth 2\.1 と 2\.0 で適当に diff をとってみた \| tail \-f pinzo\.log](https://pinzolo.github.io/2020/11/12/diff-oauth-v2.1-and-v2.0.html)

---

最近は OAuth, OpenID Connect, FIDO とすっかり AuthN, AuthZ をがっつり勉強しております。

んで、7月末に WG Draft が出た [The OAuth 2\.1 Authorization Framework](https://tools.ietf.org/html/draft-ietf-oauth-v2-1) があるわけですが、勉強がてら OAuth v2\.1 と OAuth v2\.0 の diff をとってみた。[diff の内容はコチラ](https://gist.github.com/pinzolo/732c3fe3c0c1a0ae0fefc47bac40791d)

まあ、[Section 12.](https://tools.ietf.org/html/draft-ietf-oauth-v2-1-00#section-12) を読めば大体わかるんですがね。

基本的にこのドラフトは下記の文書を統合した物です。

* [RFC6749 - OAuth 2.0](https://tools.ietf.org/html/rfc6749)
* [RFC6750 - Bearer Token Usage](https://tools.ietf.org/html/rfc6750)
* [RFC7636 - Proof Key for Code Exchange ](https://tools.ietf.org/html/rfc7636)
* [RFC8252 - OAuth 2.0 for Native Apps](https://tools.ietf.org/html/rfc8252)
* [OAuth 2.0 for Browser-Based Apps](https://tools.ietf.org/html/draft-ietf-oauth-browser-based-apps-06)
* [OAuth Security Best Current Practice](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-15)

主な変更点はこちら。ただ、足りてないと思う。クライアントタイプが3つになるとかかなりでかい変更なのに Section 12. では触れられてないし。

* Authorization Code Grant を PKCE で拡張した
* Implict Grant を廃止
* Resource Owner Password Credentials Grant を廃止
* URI のクエリストリングでの bearer トークンの削除
* リフレッシュトークンは sender-constrained もしくはワンタイムトークンとすべき

BCP バージョンが上がった 16 が出ているし、Browser-Based Apps にいたっては Fix したら持ってくるとか気の長いことを言っているのでまだまだ変わりそう。

あと、クライアントタイプが増えているのはやっぱり気になる。__confidential__ の定義が変わるのはほかのいろんなドキュメントに影響を与えるし、_認可サーバに身元が確認されたクライアント_ なんてしれっと書いてあるけど、これは __認可サーバはクライアントの身元を確認する__ という要件が増えているとも取れる。__public__ と __confidential__ の定義は変えずに身元が確認された confidential クライアントを __trusted__ とか __certified__ とかにするのじゃダメだったんだろうか？

Device Flow は取り込まれずに例としてあげられているだけ、app2app や CIBA なんかは OpenID Connect 由来だからか全く触れられていない

あくまでも統合したものなので、この文書を起点にドラスティックな変更が現れることはなさそうな気がする。いや、クライアントタイプな変更はかなりドラスティックな気もする

まあ、まだ 00 なので、今後に注目ですね
kotlinラムダ式

1. ラムダ式、つまり関数型リテラルの完全な構文形式

```
val sum = { x: Int, y: Int -> x + y }
```

2. 発展

```
val sum: (Int, Int) -> Int = { x, y -> x + y }
```

3. 高階関数

Kotlinでは、関数の最後のパラメータが関数である場合、そのパラメータは括弧の外に指定することができるという慣習があります

```
//定義
fun <T, R> List<T>.map(transform: (T) -> R): List<R> {
  val result = arrayListOf<R>()
  for (item in this)
    result.add(transform(item))
  return result
}

//呼び出し
val doubled = ints.map { it -> it * 2 }
```

関数内のラムダ式で return すると通常は関数から戻りますが、@ でラベル指定することで、ラムダ式を return することが可能。returnするときに返り値が必要な関数もある。
Djangoでマイグレーション時に気をつけたいこと

自分への備忘録＆同じことでハマってしまっている人へ。

### 結論
manage.pyとアプリディレクトリが同じ階層に無いとマイグレーションできない

### ハマった背景
- ルートディレクトリ名とプロジェクト名を同じにしていた
- プロジェクトディレクトリ内でstartappしてしまい、manage.pyとアプリの階層が別になってしまった

### 起きていたエラー内容
```
ModuleNotFoundError: No module named 'appディレクトリ名'
```

### NGなディレクトリ構造
```
├.vscode
├projectディレクトリ
　└appディレクトリ
├venv
└manage.py
```


### OKなディレクトリ構造
```
├.vscode
├projectディレクトリ
├appディレクトリ
├venv
└manage.py
```

振り返れば初歩的すぎることですが、同じことにはまらないために寄稿します。
【GNS3】VRF(VRF-Lite)！！

# 環境
・Windows10
・GNS3 version 2.2.15
・Cisco 3745(IOS Version 12.4)

## vrfとは
VRF（Virtual Routing and Forwarding）の略。
1つのルータ上で複数のルーティングテーブルを保持することができる技術。
VRFの単位をインスタンスだとかルーティングインスタンスだとか言うらしい。
インスタンスに各ルーティングプロトコル（OSPF、EIGRPとか）を紐づけれるられる。
VRFはIPアドレスの付与できるIFに紐づけ可能（SubIFとかでもOK）
VRFというとMPLS-VPNの実装で使われることが多いらしい。

※MPLS‐VPNの実装のない、ルーティング分離機能をVRF-Liteというらしい。（Ciscoでは）
（このへんはあまりしっくりきていない部分…）

## 今回の検証
中央のVRF_Routerの物理IFにVRFを紐づけてRED側とBLUE側でL3レベルで分ける。
RED側および、BLUE側で重複したIPアドレスを付与しOSPFの設定をする。
RED側、BLUE側でPingでの疎通試験をする。
![vrf.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184521/05acee46-cc3b-e639-c342-495f963f1a6e.gif)

### 確認コマンド
・Global Routing Table:show ip route
・VRFの紐づけ:show ip vrf brief
・VRF IF:show ip vrf interface
・VRF Routing Table:show ip route vrf xxx
・VRF Ping：ping vrf xxx x.x.x.x
・OSPF：show ip ospf neighbor
・ICMPの到達性:debug ip icmp

### ポイント
・VRFを識別するのは中央のVRF_Routerのみのため、それ以外ではVRFを意識する必要はない。
・Cisco（IOS）の場合だと、ルーティングプロトコルのプロセスIDは重複不可能なので注意が必要。
　VRF毎に分けてOSPF neighborを確認するコマンドがなさそう…。

### 結果
無事にL3レベルでの分けることができた。イメージはVLANのL3バージョンみたいな感じ。

### まとめ
・VRFを分けることによって重複したIPの不要が可能
（VRF間で通信する際は設計がややこしくなりそうだが…）
・設定および確認コマンドをしることができた。

### 展望
VRF間でのRoutingやMPLS-VPNでの使用方法なども今後ためしていければと思います。
Medium Editorでカーソルを指定の位置に設定する方法

##環境
Rails6 (6.0.1)
ruby 2.7.0

##参考
[Change Cursor Position to particular para Medium Editor](https://github.com/yabwe/medium-editor/issues/1056)


##MediumEditorとは？
有名ブログサービスのMediumで使われているWYSIWYGエディターです。

※RailsにMediumEditorを導入する際は[こちらの記事](https://qiita.com/sayama0402/items/8c0ecac2bca3a76625ac)を参考にしました。


##なぜカーソル位置を指定の場所に移動させるのか？
インデントが適用されたpタグ内でテキストを入力し文字確定でEnterを押すとなぜかカーソル位置がpタグ内の先頭に移動してしまうバグが発生。このバグを解消させるために、元の位置にカーソルを戻す方法がないか調べた結果、カーソル位置を指定の場所に移動させる方法があったので、この記事にまとめました。



##カーソル位置を指定の場所に移動させる方法
MediumEditor.selectionが持つmoveCursor()メソッドを使うことで実現できた。

```js
MediumEditor.selection.moveCursor(document, node, offset);
```

_node: カーソルの移動先となるノード_
_offset: カーソルの位置（ノード内の文字列の先頭から〜番目）_

今回の場合は文字確定時のカーソルがあるノードを取得する必要があったので
getSelection()メソッドのfocusNodeオプションを利用しました。

```js
target_node = document.getSelection().focusNode;
```

あとはoffsetを指定することで任意の場所にカーソルを移動させることができます。

__テキストノードの先頭にカーソルを移動させる__

```js
target_node = document.getSelection().focusNode;
MediumEditor.selection.moveCursor(document, target_node, 0);
```

__テキストノードの先頭からn番目にカーソルを移動させる__
5番目に移動させる場合

```js
target_node = document.getSelection().focusNode;
MediumEditor.selection.moveCursor(document, target_node, 5);
```

##結果
今回のバグ対応は、文字確定時のカーソル位置に再びカーソルを戻すという特殊な対応だったので、getSelection()メソッドのfocusOffsetオプションでノードの先頭を基準に現在のカーソル位置を取得しました。

```js
offset = document.getSelection().focusOffset;
```

上記の方法でnodeとoffsetを取得できたので、カーソル位置が変わってしまった後に下記の処理を走らせることで無事バグの解消はできました。

```js
MediumEditor.selection.moveCursor(document, target_node, offset);
```
Power BI Tips - Power BI上でテーブルを作成する

#概要
Power BIを使うシステムを開発しているときに、
ちょっとした変換テーブルが欲しくなって、
CSVとかExcelとかデータベース上じゃなくて、
Power BI上でテーブルを作ったので、
その時の備忘録。

#手順
###作成手順
①リボンのホームタブにある、「データの入力」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146789/bbb35c5e-76a5-80b8-9918-90c3bff68f33.png)

②必要なデータを入力。名前も適宜入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146789/6de5ef72-9031-4f4d-b55a-ffdc6469bfc1.png)

③読込みボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146789/f0ef1d0e-f524-35d5-212b-5a3ea8f6d09b.png)

以上。
超簡単ですね（汗）。

###変更手順
①リボンのホームタブにある、「データの変換」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146789/db4a8397-5cd6-b5a2-1ad7-43ff605cfc2a.png)

②Power Queryエディタが起動するので、クエリペインで対象のテーブルを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146789/41e02923-128a-642b-3841-f51083b8ff31.png)

③クエリの設定ペインで、「ソース」の設定アイコンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146789/60af0818-3a39-624e-9e48-98f0e398971e.png)

④以下のような画面が表示されるので、適宜変更して「OK」ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146789/24ee3f70-daff-e6d9-1314-9695c00b31f3.png)


変更の仕方が最初わからなくて、
テーブルを作り直してた時期もありました（汗）。

データベースのデータが変更できないとか追加できないとか、
ちょっとした場面で活躍できそうな機能。
AWS SDK for RubyでS3オブジェクトサイズの取得

HLS形式の動画サイズ取得の為に使いました！

※オブジェクトデータ1000件以上を想定しています。

[Class: Aws::S3::Client](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html#list_objects_v2-instance_method)

```ruby
    
client = AWS::S3::new

size = 0
options = { bucket: [バケット名], prefix: [プレフィックス] }
loop do
  object_list = client.list_objects_v2(options)
  object_list.contents.each do |object|
    size += object.size
  end
  options[:continuation_token] = object_list.next_continuation_token
  break unless object_list.next_continuation_token
end

gigabyte = (size / (2 ** 30).to_f).round(2)

```

CLIだとさらに簡単
[AWS CLIを使ってS3上にあるファイル数とファイルサイズの合計を取得する](https://dev.classmethod.jp/articles/aws-cli-count-s3-filesize/)

```terminal
$ aws s3 ls s3://[バケット名]/[フォルダ名]/  --recursive --human --sum
```

実装後にLambdaに書けばよかったなーーと反省。