OmniAICreator/Qiita-1.07M huggingface dataset:
EC2サーバーの立て方

皆さん、特に初学者の方はサーバー、サーバーってよく聞くかと思います。
サーバーは一体どんなものなのか。一旦は「画面がないコンピュータ」だと思ってもらえればいいです。

今日は実際にAWSのEC2を使ってサーバーをたて(構築する)て見ましょう。

それではコンソールにログインします。

![スクリーンショット 2021-05-30 13.17.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/baf61ad9-26e5-ead5-db2e-4029c890b8e9.png)

ここでEC2を選択してください。


![スクリーンショット 2021-06-03 7.43.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/c7b58b65-71a5-6ce7-0b8e-efb07bf724e3.png)

ここにInstancesとありますね。これがサーバーです。

クリックしてください。

![スクリーンショット 2021-06-03 7.44.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/88257854-7b4d-b3e1-6c76-6960c66804c4.png)

ここに今存在してるインスタンスの一覧が表示されます。
新しいインスタンスを起動するには右上のオレンジのボタンをクリックしてください。

![スクリーンショット 2021-06-03 7.44.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/d961b978-e875-c447-e269-c840b9f89a70.png)

今回は無料枠の対象であるAmazon Linux 2 AMI　を利用しましょう。

![スクリーンショット 2021-06-03 7.45.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/fc958f6a-0fe9-a699-0df0-3bfdc115dce6.png)

さてここでインスタンスを配置するVPCとサブネットを選択します。
VPCとサブネットの設定の仕方はこちらの記事
https://qiita.com/Hibiki24/items/fe39d2a951ac81a8bb58
を参照してください。

![スクリーンショット 2021-06-03 7.45.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/a853791a-dd39-9401-0d24-6da2a378c9b7.png)

さて、こちらのパブリックIPアドレスを有効にするかしないかと言う項目ですが、今回はどっちらでも大丈夫です。一応Enable(有効にする)にしておきましょう。
これは、VPC内(仮想ネットワーク内)でのIPアドレスと別にインターネット上の(パブリックな)IPアドレスをインスタンスに割り振るか否かを決める項目です。

![スクリーンショット 2021-06-03 7.47.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/6d1c8661-0220-92e0-7018-839491b1d5d4.png)

これはセキュリティグループです。このインスタンスに対してどんな方式の通信を許可するか、どこからの通信を許可するかと言うのを決める項目です。

![スクリーンショット 2021-06-03 7.48.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/49a7def6-39b2-714c-ee20-70609ae92754.png)

今回は特に大事なものも入っていないのでall trafics(すべての通信)にしておきましょう。
普段はこの設定は絶対ダメですからね！！！

![スクリーンショット 2021-06-03 7.49.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/5fa2b635-c793-52f2-1b25-fc89125c1ed3.png)

さて、最後にkey-pairをダウンロードします。これは何かというとサーバーにログインする際に必要になってくる鍵です。
このタイミングでしかダウンロードできないので大切に保管してください。
鍵は新しいものをこの時作ることもできれば以前使った他のインスタンスと共通のものをダウンロードすることもできます。完了したら右下のLaunch Instancesをクリックしましょう。

![スクリーンショット 2021-06-03 7.50.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/5508d436-fa95-41b1-d0e8-9082f3c541ba.png)

無事インスタンスが立ち上がりました。

![スクリーンショット 2021-06-03 7.50.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/73c67f69-3e87-af9f-eaa4-59b44560d5aa.png)

右にスクロールしていくとパブリックIPアドレスも割り振られていますね。

今回はここまでです。お疲れ様でした。
Tips: Qiitaに書いている文字数が知りたい

## この記事は

3000文字Tipsイベントの参加記事です。

https://qiita.com/official-events/d523df99d6479293ffa7

> テーマは「3000文字Tips - 知ると便利なTipsをみんなへ届けよう」です。今まで記事投稿をしてきた人もしてこなかった人も、知っておくと便利なTipsをこの機会に投稿してみてください。

3000文字！シンプルでいいですね。

> いろいろな知見は持っているけれど、記事などの投稿はしたことがなかった方
記事投稿にハードルを感じていた方

記事、真面目に書こうとするとなかなかハードルありますよね。でもそんなこと無いよという趣旨だと思う。弊社の各位にも早速紹介しました。

> 以下のような記事を期待しています。

> 記事の文字数が3000文字以下
Tips記事

...って。
ちょっとまって、3000文字ってどのくらいやねん！わからん！と思ったので考えました。

## 文字数カウント

### Step.1

F12を開き開発者ツールConsoleを開きます。

### Step.2

以下を貼り付けます。

```js
// let input = document.getElementsByClassName("css-1iu5ybx"); 古くなったので修正 2021.09
let input = document.getElementsByClassName("css-avadu4");
let count = input[0].value.replace(/\n/g, "").length;
console.log(count); 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/258447c1-4a0f-ee38-4d5f-55fe53547dc5.png)

ここまでで612文字のようです。

### Step.3

以上でも最低限の気もしますが再利用しづらいのでブックマークレットにしてみます。

https://qiita.com/kanaxx/items/63debe502aacd73c3cb8

URL: `chrome://bookmarks/` を開きます。

右上からブックマークを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/b293f8e5-f971-0e77-f090-5d801ccefe3a.png)


`javascript: alert(document.getElementsByClassName("css-1iu5ybx")[0].value.replace(/\n/g, "").length);` 
 (2021.09 Qiitaの変更に伴い修正)

`javascript: alert(document.getElementsByClassName("css-avadu4")[0].value.replace(/\n/g, "").length);` をURLに登録してみましょう。出来上がったら編集しながら、ブックマークボタンを押下。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/e5a4f9ce-eeef-4f7e-644d-2bf43211922a.png)

ここまでで当記事、1064文字になりました。

## まとめ

https://qiita.com/t12u/items/8c28484100dfd3a6351b

必要な情報を適切な長さでまとめるのが、良い記事を書くコツ（Tips）でもあるようです。
以上参考になればさいわいです。 (1429文字) 

### 後日追記

https://zenn.dev/sosukesuzuki/articles/d21d69a5914a03

豆知識。
CodeCommit導入手順

# CodeCommit導入手順

CodeCommitを新規プロジェクトで使うことになったので導入手順を備忘録メモ
AWSコンソールからCodeCommitを検索

## 目的

1. 新規リポジトリ作成
2. 認証設定

## 新規リポジトリ作成

1. 名前・説明を入力して、作成をクリック
![_2021-06-02_12.56.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/5a07e5c5-5453-5468-3522-6b3911e00c78.png)

2. 作成後、リポジトリ一覧表示
![_2021-06-02_12.57.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/3a9f27e0-2dee-ef23-8f17-2e47ffa9fbf1.png)

## 認証設定

**SSH用のキー生成**

入力内容は各々入力、passphraseは今回省略

```bash
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/takashimorita/.ssh/id_rsa): xxx_id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in xxx_id_rsa.
Your public key has been saved in xxx_id_rsa.pub.
The key fingerprint is:
```

**ユーザー設定**

IAMよりユーザーを選択

認証情報タブを選択、SSHパブリックキーのアップロード
![_2021-06-02_14.33.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/e840ceba-3b9c-bc78-6143-905d48b7a593.png)

アクセスキーが発行される
![_2021-06-02_14.40.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/d7607c32-9470-a308-a6e8-52ebb81dcc93.png)

**MacにSSHの設定を追加**

```bash
$ vi ~/.ssh/config

Host git-codecommit.*.amazonaws.com
    User XXXXXX # SSHキーID
    IdentityFile /Users/takashimorita/.ssh/xxx_id_rsa # 作成したプライベートキーパス
```

**Git Clone**

```bash
$ git clone ssh://git-codecommit.ap-southeast-1.amazonaws.com/v1/repos/[リポジトリ名]
Cloning into '[リポジトリ名]'...
The authenticity of host 'git-codecommit.ap-southeast-1.amazonaws.com (54.240.226.221)' can't be established.
RSA key fingerprint is SHA256:ZIsVa7OVzxrTIf+Rk4UbhPv6Es22mSB3uTBojfPXIno.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'git-codecommit.ap-southeast-1.amazonaws.com,54.240.226.221' (RSA) to the list of known hosts.
Counting objects: 3, done.
Receiving objects: 100% (3/3), done.
```

---

いいね！と思ったら LGTM お願いします :clap::clap::clap:

【PR】週末ハッカソンというイベントやってます！ → https://weekend-hackathon.toyscreation.jp/about/
ユーザー名でプレイグラウンドを作成できません

質問者自ら解決したようです。

1- 「EMAIL ACCOUNTS」に複数の電子メールが接続されていたので、1 つではなくすべてを切断しました。
2- 「SALESFORCE ACCOUNTS」または「SOCIAL ACCOUNTS」にあるものもすべて切断します。この古いアカウントの参考として、1 通の電子メールだけにしましょう。
3- 古いアカウントでまだ使用されているものではない電子メールを使用して新しいアカウントを作成する必要があった
4- ポイントとバッジを失わないように、新しいアカウントを古いアカウントと統合する必要がありました。

[ユーザー名でプレイグラウンドを作成できません](https://trailblazers.salesforce.com/answers?id=9064S000000DvCJ)
MacからICカードリーダーとOpenSCを使ってFelicaカードのIDmを確認する


# 環境

- ICカードリーダー
  - ACR1251CL
- MacOS Mojava

（最初 libusb & nfcpyでやろうとしたんだけど、自分の環境/スキルではうまくできなかった...）


# OpenSCのInstall

```bash
$ brew install opensc
```

# カードリーダーの認識

（参考）lsusbの見え方

```bash
$ lsusb
（略）
Bus 020 Device 005: ID 999:9999 9999 ACR1251 CL Reader PICC
（略）
```

```bash
$ opensc-tool -a
No smart card readers found.
Failed to connect to reader: No readers found
（ここでUSBを指し直してみた）
$ opensc-tool -a
Using reader with a card: ACS ACR1251 CL Reader
```

# IDmの取得

`-s FF:CA:00:00:00` は GetDataコマンドの発行

```bash
$ opensc-tool -s FF:CA:00:00:00
Using reader with a card: ACS ACR1251 CL Reader
Sending: FF CA 00 00 00
Received (SW1=0x90, SW2=0x00):
（ココに16進数のIDm番号が表示される）
```
【Swift】PhotoLibraryからPeopleアルバムを取得したかった話

# 結論
現状、取得できない。

[stack overflowで見つけた記事](https://stackoverflow.com/questions/50952605/access-people-album-and-getting-images-from-it)によると、"Peopleアルバムにアクセスできないのはバグor意図的に隠されてる可能性がある"とのこと。

## 取得できそうに見えるけどできない
通常、`fetchAssetCollections(with:subtype:options:)`でPhotoLibraryから取得したいアルバムを指定する。
`with`(内部引数はtype)には、ユーザが作成したアルバムか、システムが作成したアルバムかを指定。`subtype`に具体的なアルバムの指定をする。

```Swift
let collections = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumSyncedFaces, options: nil)
collections.enumerateObjects { collection, _, _ in
      // 表示可能なアルバム名をprint
      print(collection.localizedTitle!)
}
```
お...？`subtype`に`.albumSyncedFaces`とやらを指定できるっぽい...Peopleって顔認識だろうしこれっぽい...いける！！！

```:表示可能なアルバム名
Panoramas
Videos
Favorites
Time-lapse
Hidden
Recently Deleted
Recents
Bursts
Slo-mo
Recently Added
Selfies
Screenshots
Portrait
Live Photos
Animated
Long Exposure
Unable to Upload
```
Peopleがない...
調べてみると`.albumSyncedFaces`というのは、Peopleに似た古い機能(アルバム)を指しているっぽい。
昔、iPhotoという、iTunesを介してiOSデバイスに同期する機能？があり、その中で、顔認識を使用して写っている人物をグループ化してアルバムにしていたらしい。

ドキュメントにも似たようなことが書かれてた
>A Faces group synced to the device from iPhoto.
https://developer.apple.com/documentation/photokit/phassetcollectionsubtype/albumsyncedfaces

# まとめ
元々は「iPhoneに保存されている写真から特定の人物の写真だけを抽出して〜...」と色々とやってみたいことがあり、Create MLで特定人物の顔を学習させたModelを生成すればいいのかなと思ったが、精度をあげるには色々と調整したり面倒なので、いっそのことPeopleアルバムから取得すればいいじゃん！って思ったが、そううまいこといかないようで残念。
まあ、悪意のある開発者が、第三者の端末の写真から特定人物の写真だけ裏で取得して...みたいなことが簡単にできるとセキュリティ的によくないだろうし使えないままで正解なのかもしれない。


# 参考
[PHAssetCollectionType早見表](https://qiita.com/shtnkgm/items/5b14d41685226f5c5e4b)
[iOS Photos Framework: is it possible to access photos from “People” smart folder?](https://stackoverflow.com/questions/41287387/ios-photos-framework-is-it-possible-to-access-photos-from-people-smart-folder)
[Access “People ” album and getting images from it [duplicate]
](https://stackoverflow.com/questions/50952605/access-people-album-and-getting-images-from-it)
Mac初期化時のメモ

# Mac起動時のキーコンビネーション
## 1. command (⌘) + R
内蔵のmacOS復旧システムから起動
## 2. option + command + R
インターネット経由でmacOS復旧から起動
## 3. shift + option + command + R
インターネット経由でmacOS復旧から起動

## 2と3の違い
2と3の違いがよくわからないが、どうやら起動時に押したキーの組み合わせでmacOS復旧でインストールされるmacOSのバージョンが異なるらしい。

### 公式ドキュメント
[Mac の起動時のキーコンビネーション](https://support.apple.com/ja-jp/HT201255)
MFJ-4416B/C Power MOSFET 修理メモ

バッテリーブースターと称されて巷で 13.8V ± 10% の狭い範囲でしか動かん通信機器を、電圧降下を見た目誤魔化すガジェットじゃ。

これが、ぶち壊れよる。
ワシのんは一回不注意で壊した以外、元気に動いちょるのじゃが、初期不良やら使っているうちにブレードヒューズが破断しよる。

その壊れる箇所が決まって Q1 と Q2 の Power MOSFET なんじゃ。

MFJ-4416B
[MTP3055V のデータシート](https://www.onsemi.jp/pdf/datasheet/mtp3055v-d.pdf)

MFJ-4416C
[FDPF55N06 のデータシート](https://www.onsemi.jp/pub/collateral/fdpf55n06jp-d.pdf)

症状として、どちらかの FET がショートモードでご臨終しよる。

とりま、似通った Power MOSFET を用意するのじゃが、近似値のん大阪日本橋界隈じゃと見つからんけ、ちぃ～とデカ目のんで対応で、以下の FET をチョイス。

シリコンハウスで購入した Power FET
[IRFS4410 のデータシート](https://www.infineon.com/dgdl/Infineon-IRFS4410-DataSheet-v01_01-EN.pdf?fileId=5546d462533600a40153563a29f521b0)

比較資料

|          |MTP3055V|FDPF55N06|IRFS4410|
|:---------|-------:|--------:|-------:|
|VDSS      |60V     |60V      |100V    |
|RDS(on)max|150mΩ   |22mΩ     |10mΩ    |
|ID        |12A     |55A      |88A     |

大は小を兼ねると、昔から言われよるのじゃが、ち～とデカすぎじゃが仕方あるまい。

交換後は、調子よく動いちょるけ、問題無いじゃろと判断。

注：この記事を真似しよっても一切のイチャモンは聴かんけ、自己責任でやりんさい😁
Windows10でAndroidエミュレーターが動作しなかった原因がHAXMだった時にした事

エミュレーターがアップデート時に動作しなくなりました。
その時に解決した方法を書きます。
まず、原因がHAXMかどうか調べます。
Toolsー＞
SDK Managerー＞
AndroidSDKタブのSDKToolsを開くー＞
(HAXM installer)と書いてある所にチェックが入っているか確認。
入っていなかったらチェックを入れてApply
その後、インストール出来ず、IDEを確認してくださいと出た場合の対処法です。
![qitta1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1593052/3ab06853-b33f-7b4c-4b0e-9395690fa9c0.png)

ファイルー＞Manage IDE Settingsー＞Import Settings
再インストールのような形になりますが、
前のデータなどが消える訳ではないので、
（前のデータを消しますかと選択肢が出るので、チェックを入れずに次に進む）
アンインストールするよりはましかもしれないです。
なかなか解決出来なかったので何かの役に立つと嬉しいです。
![qitta2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1593052/028d0b3f-4a30-ba9d-0149-6afc8911dec0.png)
機械学習のプロダクト開発におけるデプロイパターン

# はじめに

この記事はCourseraのコース「[Introduction to Machine Learning in Production](https://www.coursera.org/learn/introduction-to-machine-learning-in-production/)」を受講し、要点をまとめたものです。そのため、人に読んでもらうということよりは、自分で後で見返したときに思い出すことを目的とした記事なので、誤りや見づらい点がございましたらどうぞ遠慮なくご指摘頂ければ幸いです。

本記事では、機械学習システムをデプロイする際のユースケースやケースに応じたデプロイパターンについて解説します。


# デプロイパターン
ここでは3種類のデプロイパターンについて紹介されています。

1. シャドーモード
2. カナリアデプロイ
3. ブルーグリーンデプロイ

それぞれについて詳しく見ていきます。

## シャドーモード
下図は教材動画から転載したものです。教材ではスマートフォン製造過程における検査業務のシステム化を例にしてます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658983/c8cbb860-af8d-aeb8-5e05-087056c92aed.png)

このデプロイ方法では、初期段階では機械学習モデルの出力は業務の意思決定には一切関与せず、人間が従来通りの業務を遂行します。つまり機械学習モデルの出力が何だろうと、とりあえず人間の判断を仰ぐことになります。
シャドーモードのデプロイ方法の目的は、**機械学習モデルがどのように実行されているか、それが人間の判断と比較してどうなのかというデータを収集・検証し、将来的に機械学習システムに実運用下で意思決定をさせるかどうかの判断材料とすること**です。

既に古い意思決定システムが動いていたり、人間が作業をしている場合に、**実環境に実装する手間をかけず**にパフォーマンスの検証ができる効果的な方法です。

## カナリアデプロイ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658983/f856243a-f83c-3117-61d7-23648e5b6b56.png)

シャドーモードなどでの検証を終え、機械学習システムに実際の意思決定をさせる準備ができたら、一般的にはカナリアデプロイという方法をとります。カナリアデプロイでは最初は全体のトラフィックの５％以下という小さな割合で展開し、部分的に実業務の意思決定に関与させます。
トラフィックのごく一部で実行することにより、例えシステムに予期せぬ動作が生じた際にも、影響の範囲をごく一部に限定することが可能です。

同時にシステム監視を行い、パフォーマンスに自信が持てるようになったら、徐々にトラフィックの割合を拡大していきます。

余談ですが、この「カナリアデプロイ」という言葉は、昔に炭鉱夫がガス漏れを発見するためにカナリアを使っていたことに由来するそうです。

へ～　ってなりますよね。モルモットというかなんというか。カナリアかわいそうｗ
この辺は部署とかで区切るとなると実際のプロジェクトでは利害関係の調整が大変そうだな～と思いました。実際にはその辺の根回しや掌握がプロジェクト成功のカギを握りそうですよね。

## ブルーグリーンデプロイ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658983/b871ecd9-7d56-000f-b200-b18bdfd288ad.png)

これはルーターを使って、利用するシステムの向け先を旧バージョンから新バージョンにスイッチするデプロイ方法です。
ルーターのトラフィックコントロールにより、旧システムから新システムへ突然バージョン切替します。この方法のメリットはロールバックが簡単に出来ることです。新バージョンで何らかの問題があった場合には、旧バージョンにルーターの設定を切り戻すことで復旧がすぐに可能です。

一般的にはトラフィックの100％を旧から新に切り替えるようですが、徐々にトラフィックの割合を変えるような、緩やかなデプロイ方法もあるようです。

# デプロイ方法を考える上でで大切なこと

いくつかデプロイの方法を紹介しましたが、システムのデプロイ方法を考える上では、「どの程度の自動化が適切か」を考えてシステム設計をすることが大切と言っています。機械学習アルゴリズムの適用が難しい業務は全て人間が行うと見極めるのも重要な判断ですし、あくまでAIはアシストの位置づけで人間の意思決定の支援をするという部分的な自動化を考えるのも重要なことです。部分的な自動化を行う場合は、人間の最終判断をフィードバックし再学習することで、よりパフォーマンスが改善し、更なる高度化・全自動化へ繋がります。

大半の場合は完全な自動化を実現する必要はありません。システムの性能やアプリケーションの要件によって適切な設計を行い、段階的な導入を行うことが最良な選択肢になり得ます。

# さいごに

本記事では、いくつかのデプロイパターンをご紹介しました。また、用途に覆布手最も適切な自動化の度合いを選択する方法についても触れました。これらを検討する上では、問題を発見して対処できるようにするために、モニタリングが重要になってきます。
次回はモニタリングについての方法の詳細をご紹介できればと思います。
sshで"WARNING: UNPROTECTED PRIVATE KEY FILE!"が出たときの対処

# 対処法
自分が遭遇した場面では

```
$ ssh xxx

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
```

このような感じでした。どうやら調べてみると秘密鍵の権限が現状だと外部からの読み書き全てを許可してしまっているよう。なので...

```
$ cd .ssh
$ chmod 600 秘密鍵
```

をすると対処することができました。
AWSの無料枠で課金発生した話。

どうでもいい備忘録。
初学者さんでAWS利用する方もいると思うので。

無料枠の利用期間にもかかわらず、
Elastic IP　address
で料金が発生しました。

https://gyazo.com/b78b2a90e19856307e558351d48353c3

削除というネーミングではなく、
オプションからElastic IP の解放を選択。
どうやら課金は止まったようです。
funannotateをsingularityで動かす

### はじめに

以前書いた [funannotateを遺伝研スパコンで動かす](https://qiita.com/motthy/items/503766baf41d0e77fd92) という記事の続きです.

condaでインストールするとめちゃくちゃ面倒だったので、DockerHubで配布されているdockerイメージをsingularityイメージに変換して、遺伝研スパコンで使えるかどうか試してみました.

#### Singularityを使うメリットとデメリット

**メリット**

- インストールが楽
- $HOMEを自動でマウントしてくれる
- ヘルプメッセージを確認する程度ならインタラクティブノード（qloginで入れるノード）で実行可能
- 最新版をcatch upできる

**デメリット**

- 作者さんのGitHubで配布されているfunannotate-dockerという簡単実行スクリプトが（そのままでは）使えない

### やりかた

ゲートウェイノードにログインしてから,

```bash
$ qlogin -l mem_req=20G,s_vmem=20G # memoryを多めにしてqlogin

$ cd /your/tools/dir/ # 任意のディレクトリに移動

# dockerイメージをsingularityイメージに変換
$ singularity build funannotate.sif docker://nextgenusfs/funannotate

INFO:    Starting build...
(途中略)
INFO:    Creating SIF file...
INFO:    Build complete: funannotate.sif
```

`funannotate test`コマンドで実行テストをします.
`#$`で始まる行はスパコンの計算ノードに投入するためのコマンドです.

```test_funannotate.sh
#$ -S /bin/bash
#$ -pe def_slot 10
#$ -cwd
#$ -l medium
#$ -l mem_req=15G,s_vmem=15G
#$ -l d_rt=192:00:00
#$ -l s_rt=192:00:00

singularity exec /your/tools/path/funannotate-1.8.7.sif funannotate test \
                                                        -t predict \
                                                        --cpus 10
```
10 core, メモリ合計150GB確保して投入しました. なお, 80GBでは途中でコアダンプしました.
20分くらいで終了します. 標準出力ログに以下が出力されていれば, たぶん本番データでも動くんじゃないかな...
(本番データではまだ試していないので,うまく動けば追記します)

```
#########################################################
SUCCESS: `funannotate predict` test complete.
#########################################################
```
ちなみに,このテストコマンドでpredictされるゲノム配列の大きさは約3Mでした.
Saccharomyces属のゲノムの一部だけを取り出しているようです.
小さめの真核生物ゲノム（~500MBくらい？)だとストレスなく動くと思います.

### 余談

実行テストにfunannotateのデフォルトではなく, SARS-CoV2ゲノムを使おうとして撃沈.

```
 0 valid BUSCO predictions found, validating protein sequences
```
こんなエラーメッセージが出てきました.　まあそうだよね, 真核生物じゃないもの.
E.coliでテストしてみるつもり.
Laravelのルーティング

#ルーティング(web.php)

/<font color="Red">アプリ名</font>/routes/web.php


取得するパスは【/sample_action】で、<font color="Red">SampleController</font>の<font color="Red">sampleAction</font>というメソッドを利用する

```php
<?php
 
Route::get('/sample_action', 'SampleController@sampleAction');

```




ルートパスを指定

```php
<?php
 
Route::get('/', function () {
    return 'シンプルなルーティング！';
});

```

ルートパス/other/のパスを指定

```php

<?php
 
Route::get('/other', function () {
    return 'ここは/otherです。';
});

```

/<font color="Red">アプリ名</font>/resources/<font color="blue">views</font>/samples/<font color="Red">blade_example</font>.blade.phpのパスを指定


```php

<?php
 
Route::get('/blade_example', function(){
    return view('samples.blade_example');
});

```

<font color="Red">blade_example</font>/パスを指定する

resources/<font color="Red">view</font>ディレクトリの
<font color="Red">samples</font>ディレクトリの
<font color="Red">blade_example</font>.blade.phpファイル

が呼び出される
inkscapeでSVG画像にtransformが入っちゃう！の解決方法

はじめまして。ゴリラドットと言います。

inkscape、めっちゃいいですよね。ぼくは主にSVG画像を作るときにinkscapeを使っています。ただ、画像をドラッグするとSVGの中身、XMLにtransformっていうのが勝手に入ってしまって、cssやHTMLにパス値を直に入れ込んだときにtransformの分だけズレて表示されてしまいます。

これは困った。

ということで今回はそんなinkscapeとSVG画像に関する解決方法を。

# XMLエディターでドラッグ！
inkscapeにはXMLエディターなるものが標準でついています（編集→XMLエディター）。
このXMLエディターを使えば簡単にtransformついちゃう問題を解決できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1572104/a00c80a4-db9b-6048-4ff2-60b2fe5c420d.png)
↓これをこう！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1572104/3bf8b5a1-4e38-51d2-603f-bf0817cf9f70.png)


こんな風にlayer1の上にドラッグするだけ。
これでXMLに自動追加されちゃうtransformがきれいさっぱり消えます。

# というかlayerに対してtransformがついてる
というかinkscapeでは画像をドラッグしたタイミングでlayerが移動して、んでその移動量に応じてtransformが入っちゃうんです。layerに対して。

だからlayerの外に画像を出してあげればSVG画像を出力してもtransformがつかなくなるんです。

# まとめ
inkscapeでSVG画像、HTMLの幅が広がってすっごいいい！ですよね。
DockerでReactのホットリロードが効かない

#はじめに
Docker上でReactとTypeScriptと使って開発をしている時に、ファイル保存時に自動的にブラウザに反映(hot reload)されなくなったので、その解決策をここに備忘録として書き残します。

#開発環境
Windows10
Docker for windows
React 17.0.2
TypeScript 4.3.2

#解決策
create-react-app/Trouble shootingに書かれている通りに、.envファイルを作成し、polling modeをtrueと記述しました。が直りませんでした。おそらくDockerに何かありそうです。
>If the project runs inside a virtual machine such as (a Vagrant provisioned) >VirtualBox, create an .env file in your project directory if it doesn’t exist, and >add CHOKIDAR_USEPOLLING=true to it. This ensures that the next time you run npm >start, the watcher uses the polling mode, as necessary inside a VM.

 [React-create-app/Trouble shooting](https://create-react-app.dev/docs/troubleshooting/#npm-start-doesnt-detect-changes)

##Dockerにも追加
docker-compose.ymlに.envと同様の記述しました。そしたら、ちゃんとhot relodeが効くようになりました。

```docker-compose.yml
environment:
      - CHOKIDAR_USEPOLLING=true
```

#あとがき
普段macで開発をしているので、windowsで何かあるとwindowsのせいにすることをやめようと思います。しっかりと問題の本質を見極める必要がありそうですね。
Rubyの例外とは？例外処理の流れ(未経験エンジニアにおすすめ)

# はじめに

例外処理について学ぶタイミングってなかなかないですよね〜。
とはいえ、実務になると普通によく遭遇します。
ということで、これからエンジニアになりたい人、エンジニアになりたての人に向けて、例外とは何かというところから丁寧に解説した記事です。
ぜひご覧ください。

#そもそも例外とは
プログラミングにおいていわゆるエラーと呼ばれるものには2種類あります。

1つは、シンプルに**エラー**。もう一つは**バグ**。
この二つの違いは以下です。

□エラー → 開発者が想定していなかったエラー
□バグ → 開発者が認識しているエラー

※エラーには構文(Syntax)エラーと論理エラーがありますが、ここでは詳細を割愛します。

前提として、開発者はバグを治す必要があります。
そこで、「ここでエラーが起こるかもしれないなぁ」と思う箇所に、エラーが発生した場合の対処法をコードに落とし込んでおいたり、エラーメッセージをログに残すことで、開発者がエラーの改修をすばやく行うことができるようになります。
それこそが、**例外処理**であり、そのエラーが発生した時の情報をログで残しつつ、救済処置を用意しておくことで、**エラーが発生した時は例外処理で対処しつつ、今後そのエラーを減らしたり、対策したりするためにログで情報を残すことができます**。

ここからはRubyの例外処理です。

#Rubyの例外とは

まず、Rubyの例外とはどのようなものなのか。

Rubyでは例外も**オブジェクト**である。
オブジェクトなので例外オブジェクトはメソッドを持っています。このメソッドを使うことで発生した例外の情報を抜き出すことができます。
具体的な情報の抜き出し方は後ほど説明します。

まずは、例外発生の具体例を見てみましょう。

```ruby:example.rb
def method_1
  puts 'メソッド処理スタート！'
  1 / 0 #ゼロ除算で例外を発生させる
end
```

```ruby:出力
  メソッド処理スタート！
  ZeroDivisionError: divided by 0 # エラー発生！プログラムも止まる。
```


このZeroDivisionErrorが例外であり、例外オブジェクトと呼ばれるものです。
また、1 / 0  より前にあるputs はきちんと出力されていますね！

また、例外はオブジェクトなので、以下のようなメソッドを持っています。

```ruby:example.rb
# error は例外が発生した時にできる例外オブジェクトというものです。
error.class # エラーオブジェクトのクラス
error.message # エラーオブジェクトのクラス
error.backtrace # バックトレース
```

これらのメソッドで例外が発生した際の情報が得られます。情報は、エラーオブジェクトのクラスや、エラーオブジェクトのクラス、バックトレース(エラーが発生するまでにたどったコードたち)。
しかし、一つ目の例で見たコードだと普通にエラーを吐いてコードが止まりますね。(1 / 0の部分)
このままではerrorオブジェクトはキャッチできないですし、まず本番コードだと普通にバグでアプリケーションが死んでしまいます笑

# 例外処理

ってことで、ここからは例外処理というものを学びます！
例外処理は以下の記法で書けます。

```ruby:例外処理
begin
  # 例外が起こりうる処理
rescue => error
  # 例外が発生した場合の処理
end
```

これでbeginで発生したエラーのオブジェクトがerrorとしてキャッチでき、プログラムも止まりません。
さっきのゼロ除算を例に見ると以下になります。

```ruby:example.rb
def method_1
  puts 'メソッド処理スタート！'
  begin
    1 / 0 #ゼロ除算で例外を発生させる
  rescue => e # エラーキャッチ！ 例外オブジェクトは、errorじゃなくてもどんな文字列でもおけです。eという記法が良く使われます。
    e.class
    e.message
    e.backtrace
  end
end
```


```ruby:出力
メソッド処理スタート！
ZeroDivisionError # エラーオブジェクトのクラス
divided by 0 # エラーメッセージ
(irb):2:in '/' # バックトレース
(irb):2:in 'irb_binding' # バックトレース
(略)
```

これでプログラムを止めずにエラーの原因を特定する情報も手に入れることができますね！


#まとめ

ここまで例外と例外処理について説明してきました。
しかし、例外処理は積極的に使うべきではありません。
フレームワークのRailsであればエラーが発生した時に、ユーザーをエラー画面に遷移させる例外処理が組み込まれています。
変にいじってしまうと元々の「レール」から外れてしまいかねません。RailsのベストプラクティスはRails側が用意したレールの上を走り続ける事です。
特に初心者の方は、「例外が発生したら即座に異常終了させよう」「フレームワークの共通処理に全部丸投げしよう」と考えましょう！

#参考文献

書籍: プロを目指す人のためのRuby入門(伊藤　淳一)
動画ファイルを animated GIFs （GIFアニメーション）へ変換（シェルスクリプト）

こんにちは。
動画ファイルを animated GIFs （GIFアニメーション）へ変換するシェルスクリプトを作りました。ffmpeg と convert (ImageMagick) コマンドを使いました。

```animatedGIFs.sh
#!/bin/sh

inputfile=$1
outputfile=output.gif
width=600

realpath_f() {
  case "$1" in /*) ;; *) printf '%s/' "$PWD";; esac; echo "$1"
}

inputfile=$(realpath_f "$inputfile")
tmpdir=$(mktemp -d)
cd "$tmpdir" || exit

ffmpeg -loglevel panic -i "$inputfile" -vf scale="$width":-1 -an -r 10 %04d.png
convert -loop 0 *.png $outputfile
rm *.png

echo "$tmpdir"/$outputfile
open "$tmpdir"  ### 出力ファイルのディレクトリを開きます（Mac用）

exit
```
【Swift】APIから画像を取得して表示する

# どういうことか

APIを叩くとレスポンスでURLが返ってくる。
それを元に画像を表示したい。
今回は**マジック・ザ・ギャザリング**のAPIを使ってカード画像を表示しよう。

https://docs.magicthegathering.io/

APIを叩く方法などは割愛。

## Kingfisher

画像の変換にはライブラリのKingfisherを使う。

https://github.com/onevcat/Kingfisher

cocoaPodsでインストールする。

```terminal
pod 'Kingfisher'
```

使い方はカンタン。
今回はcollectionViewに表示させることを想定している。

```swift
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CardCollectionViewCell.reusableIdentifier, for: indexPath) as! CardCollectionViewCell
                
        if let cardImage = cards?.cards[indexPath.row].imageUrl {
            cell.imageView.kf.setImage(with: URL(string: cardImage))
        }
          
        return cell
    }
```

ところがエラーが出て表示しない。
元の画像URLが `https` ではなく `http` であるため使うことができない。
httpが使えるようにする。

https://qiita.com/Howasuto/items/f8e97796c6eb30de4112

これで無事表示されました。

![Simulator Screen Shot - iPod touch (7th generation) - 2021-06-03 at 23.35.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413699/2a0d72c9-5001-1eab-8e26-d1ec35731490.png)

ちなみにこのカードは全カードを取得して1番上にあるカードで思い入れは特に無し。
好きなカードは[走り回るスカージ](http://mtgwiki.com/wiki/%E8%B5%B0%E3%82%8A%E5%9B%9E%E3%82%8B%E3%82%B9%E3%82%AB%E3%83%BC%E3%82%B8/Skittering_Skirge)です。
おわり(´・ω・｀)
【Java】「なんでここequalsなの？」と聞かれた話

上司に「なんでここequalsなの？」と聞かれてなんぞなんぞって思ったことがあったので記事にしてみました。
言われたときは:information_desk_person:「文字列の比較だからだよナ…」という気持ち…

javaに触れ始めてからは~~（というか今この瞬間）~~これで合ってるのかなと思っています。
・intは「==」
・Stringは「equals」
この理解度のままで良いのか自分！！と思ったのでまとめてみます。
#そもそもいつ使ってる？
初歩の初歩とは分かっていますが焦らずここから:raising_hand_tone2:
使用頻度の高い場面はやはりif文ですかね…

```
		String loveAnimal = "dog";
		boolean isdogPerson = false;
		if (loveAnimal.equals("dog")) {
			isdogPerson=true;
		}
        //true
		System.out.println(isdogPerson);
```

~~どうやら筆者は犬派であるということが分かりました。~~
何のひねりもないif文ですが、なんだかんだ使用頻度が高いなと思います。
switchもうまく使えるようになりたい…
##何を比べているの？
いざSEになったからというもの値の比較を目にすることが多いですが、少し初心に帰ってみます。
Javaにはプリミティブ型と参照型があります。
プリミティブ型について表にしてみました。

|型|値
|:---|:---
|byte|-128 ~ 127 の整数
|short|-32768 ~ 32767 の整数
|int|整数
|long|整数
|char|\u0000 ~ \uFFFF のUnicode文字列	
|float|実数(単精度不動小数点数)
|double|実数(倍精度不動小数点数)
|boolean|true, false

こんなにあったなんて…
~~shortなんかは今回調べるまで知りませんでした…~~
参照型はStringが代表的で覚え方がよいかは分かりませんが、ざっくりと値を詰める箱！！と覚えています。

#==っていつ使うの？
脱線しましたが、本題へ！
__==演算子__は~~どうやら~~参照先が同じかどうかを比較するものです。
プリミティブ型(int)を比較してみます。
同じ住所の太郎さんか違う住所の太郎さんかくらいの認識で今は書き進めています。

```
		// プリミティブ型(int)の比較
		int intA = 1;
		int intB = 1;
		// true
		System.out.println(intA == intB);
```

上記の例では1と1の値同士を比較した結果がtrueになります。

次に参照型の比較をしてみます。

```
		// 参照型(Integer)の比較
		Integer integerC = new Integer(1);
		Integer integerD = new Integer(1);
		// false
		System.out.println(integerC == integerD);
```
こちらの結果はfalseになります。
どうやら値の比較を行っていないことが分かります。
参照型における==は変数が保持するインスタンス（箱）が同じであるかを比較しています。

#equalsはいつ使うの？
ここで我らのequalsに迫ります。
~~私の必殺技はjava.util.Objects.equals~~
先ほどのIntegerの比較をequalsでリベンジしてみましょう。

```
        // 参照型(Integer)の比較
		Integer integerC = new Integer(1);
		Integer integerD = new Integer(1);
		// true
		System.out.println(integerC.equals(integerD));
```
equalsを使用することによってインスタンスが持っている値の比較をしていることが分かります。
私は感覚的にequalsは上記のような役割を果たしていると思っていましたが、Integer.Classの中ではこのような処理が走っているようでした。

```Integer.class
        public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }
```
中で==しているのネ…
今回書き始めようと思ったモヤモヤがかなり解消された気がしました。

せっかくなのでString型の中ものぞいてみましょう:skull:

```String.class
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (!COMPACT_STRINGS || this.coder == aString.coder) {
                return StringLatin1.equals(value, aString.value);
            }
        }
        return false;
    }
```
~~こいつも==しとるやんけ…~~
面倒くさがらずに参照型の定義を覗いてみようと心に誓い、この辺で締めたいと思います。
#まとめ
Javaにはプリミティブ型と参照型があり、それぞれの比較に==とequalsが使用されています。
・プリミティブ型は==で比較
・参照型はequalsで比較
∟中では==してる:dancer_tone3::dancer_tone3::dancer_tone3:
~~プリなんたら型と記憶にうっすらでした。~~
・上司のささやかな優しさを感じました…
∟日々精進ですね:dark_sunglasses:



##今回の内容を書きたくなったきっかけの記事様
[【Java】==とequalsの違い](https://qiita.com/mzmz__02/items/343cfa4a07ce868755f2)



:speaking_head:最近は美容師さんに勧められたDEARBOYSを読んでいます。（バスケの漫画はｱﾁﾁﾁ）
森高麻衣ちゃん可愛すぎるな？？
余談はこの辺にして、また日々の業務での疑問や理解が甘いことをピックアップしてまとめてみようと思います。
【ESP32】MACアドレスを使ったAmbientのチャンネル取得

#MACアドレスを使ったチャンネル割り振りの利点
* 全てのプログラムを共通化できる
* Web上(Ambient)から追加・削除できる

#Ambientのアカウント取得
下のリンクから，ページ右上の「ユーザー登録(無料)」を押してアカウント情報を入力．
https://ambidata.io/
![スクリーンショット 2021-06-03 23.17.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251987/2448b5ec-47f0-49ce-6d05-a1e5a1099964.png)
メールが来るので，そこにアクセスするとアカウントが開設されます．

#ユーザーキーを確認
ログイン後に「チャンネル一覧」を見ると左上のユーザーキーが表示されているので，これをコピーしてESP32のプログラム内に書き込みます．
![99354371-9C71-437F-BF66-90669B455C72.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251987/06d1b92b-7f1d-4a59-d162-5a07a362df19.jpeg)

#チャンネル開設
左下の「デバイスキーを設定する」を押すと，以下の画面になるので，指定のチャンネル（チャンネル名は任意で変更できます，チャンネル同士の順番には意味はありません）の「＋」ボタンを押してMACアドレスを入力してください．
Ambientは上記のユーザーキーとMACアドレスで認証して，デバイスにチャンネルIDとライトキーを返します．
![スクリーンショット 2021-06-03 23.26.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251987/90fa27d0-1e0a-fc30-be37-ed5a5de1d0a5.png)
![スクリーンショット 2021-06-03 23.32.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251987/d6e8768f-dbae-917b-0122-f58cd4fdc337.png)

#プログラム実装上のお話は...
Ambientのチュートリアルはこちらです．
https://ambidata.io/docs/getchannel/
Chromeデベロッパーツールでコーディング

# できるようになること
Chromeデベロッパーツールを使用して、コーディング作業ができるようになります。

# 環境
Windows10
Chrome 91.0.4472.77

# 前提
対象ファイルが、自端末で編集可能なファイルであること

# 手順
1. 対象ページをChromeで開く
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1124047/864488ed-3b14-a48c-44f1-df82d1eba935.png)
2. Chromeデベロッパーツールを開く（F12押下）
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1124047/8cb33a99-8dec-076d-44d0-d9781320cf4e.png)
3. Sourcesタブをクリック
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1124047/a706ffa1-3096-31e4-bbe7-d5006cb4d598.png)
4. 「Add folder to workspace」をクリック
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1124047/cb768c39-62c6-05f8-c063-908f590e0ba8.png)
5. 警告が表示されるので「許可」を選択
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1124047/c50bd5d5-4b5f-7d40-f934-0de7d50291cf.png)
6. 対象フォルダを選択
7. 対象ファイルに「同期マーク（緑の○）」がついていたら成功
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1124047/24b64088-63c6-7e86-155c-2b5509a2a0ac.png)

# 使い方
## CSSを編集する場合
ElementsタブでStylesを編集すれば自動的にローカルファイルのcssファイルも編集されます。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1124047/53037628-a070-6a13-db69-cc935cc5e263.png)

## htmlを編集する場合
Sourcesタブで、該当htmlファイルを編集した後F5更新すれば変更が反映されます。
（それならエディタで編集したほうがいい）
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1124047/458dd678-fd5a-2ead-2efd-4d4b70b5375e.png)

# 結果
実画面を見ながらスタイルの調整が可能なので楽

# 感想
なんかワザップみたいな投稿で笑う。
`Cannot find 'JSONEncoder' in scope` の対処

# `Cannot find 'JSONEncoder' in scope`というエラーの対処

あまりに初歩的ゆえに、なかなか見つからず困ったのでメモ。

##環境

| プログラム | バージョン|
|:------:|:--------------:|
| Xcode | Version 12.5|
| swift | Version 5.4|



##状況
Jsonのエンコード・デコードのやり方を調べるために[Apple Developer Documentation](https://developer.apple.com/documentation/foundation/jsonencoder) に記載されている通り、以下のコードをプレイグラウンドで実行したところ`JSONEncoder`のところでエラーが出た。

```swift:MyPlayground.playground
struct GroceryProduct: Codable {
    var name: String
    var points: Int
    var description: String?
}

let pear = GroceryProduct(name: "Pear", points: 250, description: "A ripe pear.")

let encoder = JSONEncoder()　// エラー：Cannot find 'JSONEncoder' in scope
encoder.outputFormatting = .prettyPrinted

let data = try encoder.encode(pear)
print(String(data: data, encoding: .utf8)!)

```
## 原因
フレームワークをインポートしていない。

## 対処
```swift
import Foundation
```
を先頭に追加。
ちなみに、frameworkは[Apple Developer Documentation](https://developer.apple.com/documentation/foundation/jsonencoder)の右側にAvailabilityなどと一緒に記載されている。
【シェルスクリプト】連番かつ0埋めの数字を使う

シェルスクリプトを使って何らかの検証をする時に、連番かつ0埋めの数字を使いたい時があると思います。
例）001 002 003 004 005 ...

シェルスクリプトの書き方がわかっていれば簡単なのかもしれませんが、
普段シェルスクリプトを書き慣れていない私は書き方で苦戦したので書いておきます。

ユースケースとしてわかりやすくするため、ここでは数字の連番を含むファイル名のテキストを作成してみます。

## 普通の連番の数字にする時

```shell
#!/bin/sh
for i in {1..100}
do
touch test-${i}.txt
done

実行結果
test-1.txt
test-2.txt
test-3.txt
.
.
.
test-100.txt
```
桁数が不揃いの数字の連番でも構わない場合はこれでいけます。
`for i in {1..100}`の部分で、1から100の数字が変数`i`に代入され、
for文の中で`${i}`とすることで参照できます。
　※参照する変数の書き方については複数ありますので、一例ということで。


## 桁数を合わせて0埋めの連番の数字にする時

```shell
#!/bin/sh
for i in $(seq -w 1 100)
do
touch test-${i}.txt
done

実行結果
test-001.txt
test-002.txt
test-003.txt
.
.
.
test-100.txt
```

基本は数字の桁数を揃えたいことがほとんどだと思います。
for文の`in`の右のリスト指定の部分ではコマンドの実行結果を指定することもできます。
seqコマンドを使用し、`-wオプション`をつけることで、0埋めの数字になります。
（`seq -w 1 100`の部分）

ちなみにリスト指定の部分でコマンドの実行結果を指定する方法ですが、
~~コマンドを`''`で囲むだけで使用できる場合もありますが、私の場合seqコマンドではできなかったので、
`$()`でコマンドを囲む方法でできました。~~
コメントで指摘していただきました。
シングルクォートではなく「\`」バッククォートで囲む方法でした。

参考：[【シェルスクリプト】（繰り返し）for文](https://www.server-memo.net/shellscript/for.html "【シェルスクリプト】（繰り返し）for文")


## 桁数を指定して0埋めの連番の数字にする時

```shell
#!/bin/sh
for i in $(seq -f '%04g' 1 100)
do
touch test-${i}.txt
done

実行結果
test-0001.txt
test-0002.txt
test-0003.txt
.
.
.
test-0100.txt
```
桁数に指定があり、最大値の数字でも先頭に0を入れたい場合があるかもしれません。
（使う数字的には100までだけど、桁数は4桁指定で「0100」にしたい場合など）

その場合は上記のようにseqコマンドの`-fオプション`を使用することでできます。
-fオプションをつけることで書式が指定できますので、今回のように4桁にしたければ`'%4g'`、
更に0埋めしたければ`'%04g'`とすることで「0100」が実現できます。


参考：[【 seq 】コマンド――数字の列を出力する](https://www.atmarkit.co.jp/ait/articles/1705/18/news033.html "【 seq 】コマンド――数字の列を出力する")


## まとめ
~~すでに同じような記事たくさんあるのですが、for文のリスト指定の部分でコマンドを`''`で囲むやり方の記事ばかりで、
私の環境ではそれでは動かなかったのであえて記事載せます。
`$()`で囲む方法でできました。
なぜ別の方はできて私の環境ではできないのか、理由まではわかっていないのでご存知の方いらしたらご教示いただけると幸いです。
（実行環境はMacでzshです）~~
コメントで指摘していただきました。
「\`」バッククォートではなくシングルクォートでやってしまっているためでした。
普段使用しているPHPやJSではバッククォートを使うことがまずないので、完全にシングルクォートだと思いこんでいました・・・。

## 参考
[【シェルスクリプト】（繰り返し）for文](https://www.server-memo.net/shellscript/for.html "【シェルスクリプト】（繰り返し）for文")
[【 seq 】コマンド――数字の列を出力する](https://www.atmarkit.co.jp/ait/articles/1705/18/news033.html "【 seq 】コマンド――数字の列を出力する")
ワードファイル（.docx）の段落ごとにエクセル（.xlsx）に格納する（Google Colab対応）

#はじめに
ワードに書かれた段落ごとの情報をエクセルに列ごとに格納したいことがあり、手作業でやるには量が多かったのでコード化してみました。毎度ですが、コードは自己責任での利用をお願いします。

#手順
①モジュールとして、docxとopenpyxlを使います。
②まずワードファイル(original.docx)から文書を読み込んでパラグラフごとにリストに格納をしていきます。
③次にエクセルのワークブック・ワークシートを作成します。
④作成したワークシートにリストの内容を順に書き込んでいきます。ただし、改行を２回しているような場合、リストに空の要素が含まれているので、それらは除外するようにします。
⑤最後にワークシートをエクセルファイル（output.xlsx）として保存します。


#Google Colaboratoryを使う場合
モジュールのインストールが必要になるので、以下を実行してください。

```
!pip install python-docx
```

```
!pip install openpyxl
```

また、Google Driveを使うので、あらかじめGoogle DriveとGoogle Colabをつなげておく（マウントする）必要があります。ファイルのところでGoogle Driveのアイコンをクリックしてマウントするか、以下のコードを実行しておきます。

```python
from google.colab import drive
drive.mount('/content/drive')
```



#いざコード
```python
import docx
doc = docx.Document("/content/drive/MyDrive/original.docx")
num = 0
data = []

# wordファイルからの読み込み
for para in doc.paragraphs:
  num = num + 1
  data.append(para.text)

import openpyxl

#  新しいブックの作成
wb = openpyxl.Workbook()

# シートの取り出し
ws =wb.worksheets[0]

# EXCELへの書き込み（ワードファイルの改行の仕方によって空のデータがありうるので、
# それをそのまま書き込まない条件を追加しています。）
num = 0
for i in range(0,len(data)):
  if len(data[i])==0:
    continue
  ws.cell(row=num+1,column=1,value=data[i])
  num = num + 1

#　エクセルファイルとして保存
wb.save('/content/drive/MyDrive/output.xlsx')
```

#最後に
ちょっとしたワード、エクセルファイルの扱いに参考になるのではないでしょうか？このコードで使ったモジュールは大変実用的で、手作業でやっていたことを自動化できます。これらのモジュールを解説したブログなどはたくさんありますので、関心がある方はぜひ検索して覗いてみてください。
RailsでPOSTしようとした時のActionController::InvalidAuthenticityTokenエラー

##Rails4 - 解決法

```/app/assets/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  # protect_from_forgery with: :exception
end
```

protect_from_forgery with: :exception をコメントアウトする

##Rails5.2以上 - 解決法1

```/app/assets/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  skip_before_action :verify_authenticity_token, raise: false
end

```

skip_before_action :verify_authenticity_token, raise: false を追記する

##Rails5.2以上 - 解決法2

```/app/assets/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery
end

```

protect_from_forgery を追記する
Blenderでスカルプトを始める時に役立つ動画リンク集~リトポロジ編~


# リトポロジーとは？
簡単にいうと
__ハイポリをローポリにする作業__。

スカルプトでめちゃ重たいモデルを作ってしまうと、ゲームなどでは動かないんです。。
なので、軽くするためにリトポロジーをします。

これは普通にやると超苦行です。
一枚一枚貼っていくという。笑
それでやってた時代があったと思うと恐ろしい。。
流石にないのかな

# 自動リトポロジー/半自動リトポロジーの違い
リトポを簡単にする方法にアドオンがありざっくり
__全自動__と__半自動(手動を補助してくれる)__で別れます。
各々の違いはざっくり

__自動：アニメーションしないやつむき__
__半自動：アニメーションするやつむき__
ということです。


#まずこれをみるとなんとなく作業わかる
まず、リトポロジーとは何！？
って人は
https://www.youtube.com/watch?v=HPZ3l7JMQWQ
こちらを見てください。
その後↓

#リトポ実践動画
https://www.youtube.com/watch?v=LKr_RQPxrLw&t=21s
こちらがおすすめ。まず作るところからしないといけないので時間はかかりますが、かなり詳しく説明してくれているのでみやすいですし。テンポがいい。
Retopo Flowは使ってないですが、とりあえずこの動画で大体こんなもんかぁとわかると思います。


#とりあえずリトポにはこのアドオンを使え！
リトポがめんどくさそうやから、アドオンないかな〜と思うでしょう。
かなりあるので、全て試すのは骨が折れます。なのでとりあえず評判のいい以下のやつ使ってます。

###半自動(手動でやる方法)
__Retopo-Flow 3__
使い方の日本語動画
https://www.youtube.com/watch?v=EfC4vyfWIkw
これでざっくり理解できます。

なんとこのアドオン神アドオンなのに、無料版があります！
有償版との違いは不明ですが多分、サポートが受けられないという点のみと思います。

https://github.com/CGCookie/retopoflow
こちらを導入するだけ！
アドオンの入れ方はググればすぐに出てきます。

###自動

すいません、これは正直試してないので不明です。
がとりあえず無料の
・Instant meshes Remesh
これを使えばいいと思います。

その他
・DynRemesh
35$
これは、界隈で有名なマスクさんが使ってるようです。

・Quad Remesher
商用だと109$

https://twitter.com/tarava777/status/1182135436245733376?s=21
なん　さんの使用感ツイート

https://exoside.com/quadremesher/

解説記事
https://www.yamato-tsukasa.com/entry/2019/12/23/020044#それ以外ではQuad-Remesherの圧勝
解説動画
https://www.youtube.com/watch?v=IUoaDVSq7ks&t=441s

調べてる感じでは、有料ならこれが一番良さそうです。
いつか試してみた感想また書きます。

###その他代表的なアドオンのちょい説明

代表的な8つを紹介してくれてる動画（英語）↓
https://www.youtube.com/watch?v=8v5YBj_9_QU
・動画のまとめ（上記に書いていないやつのみまとめ）
7 Softwrap
https://blendermarket.com/products/so...
40$
皮を被せていくようにリトポロジーする、一風変わったアドオン
6 Tesselator
https://blendermarket.com/products/te...
8.5$
全自動だが精度はあまり高くない
5 Speedretopo
https://blendermarket.com/products/sp...
無料
RetopoFlowの下位互換っぽい
ペンで描くタイプの半自動
3Dのメモ帳のモンジャさんが解説の中で使ってたやつです。
4 Retopo MT
https://gumroad.com/l/cngnb
無料
ペンで描くタイプの半自動
2 Quadwrap
https://blendermarket.com/products/qu...
29.95$
円が得意なリトポツール


---

###その他動画


キャラクターのリトポロジー
https://www.youtube.com/watch?v=ZGZlwHyUpCA&t=2425s

マスクさんの作業&解説
https://www.youtube.com/watch?v=Kam4PrLuguw&t=1594s

以上まとめでした。
英語はまだまだあると思うので、またいいの見つけたら随時更新します。
残人生のためのプログラミング　第-2回

# コンセプトをば

初回では残り人生の日にちを計算しました．
寿命が81歳だとすると，自分にはあと21915日残されています(初回から2日経過したので残り21913日).
これは人生最後の日を後悔せずに過ごせるようになるためのプログラミングです．

## 徹底的な自己管理

とは言ってもまだ学生ですし，当面の目標は学業で良い成績を収め，よりよい会社に勤めることとなります．そこで大切なのが**自己管理**．それを手助けするタスク管理アプリ作成へ向けて，毎日1歩ないし2，3歩ずつ進んでいきたいと思います．

# CSVで管理する

前回まではTaskクラスを用意して，随時インスタンスを作成しタスクを登録していましたが，今回からCSVファイルに一括登録，pandasで読込を行っています．
pandasをfor文で回すのにitertupleを使ったんですが，その弊害として列の名前で要素を取り出せなくなってます．次回までに何かいい方法見つけたいなぁ．

~~~tasks.csv
タスク名,期限,時間,重要度,備考
Qiitaの記事を投稿する,2021年6月4日,,low,毎日
課題を提出する,2021年6月9日,23:59,high,
Toeicの試験,2021年6月20日,13:00,high,
コインランドリー,2021年6月5日,7:00,mid,毎週
~~~


~~~TaskNotify_csv.py
import requests
import datetime
import pandas as pd

class Task:
	def __init__(self, name, date):
		self.name = name
		self.date = datetime.datetime.strptime(date, '%Y年%m月%d日').date()
		self.sentence = "{}まで残り{}日\n".format(name, abs(self.date-today).days)


def createSend(tasks):
	sentences = "\n"
	for s in tasks:
		if s.date >= today:
			sentences += s.sentence

	return sentences


if __name__ == '__main__':
	today = datetime.date.today()

	csv_tasks = pd.read_csv("tasks.csv", sep=',')
	list_tasks =[]
	for row in csv_tasks.itertuples():
		list_tasks.append(Task(row[1], row[2]))

	send_dict = {'message': createSend(list_tasks)}

	TOKEN = 'hoge'
	url = 'https://notify-api.line.me/api/notify'
	TOKEN_dict = {'Authorization': 'Bearer ' + TOKEN}

	requests.post(url, headers=TOKEN_dict, data=send_dict)
~~~


![TaskNotify_csv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578927/53507b7d-7bd7-2137-4a92-b9b2a5b40d91.png)


# 次回，第-3回は...

単純なタスクとルーティン(習慣的なもの)を分けて実装していきます．Toeicとか課題は使い捨て(期限を過ぎると削除?)，コインランドリーは数日ごとに再登録みたいな感じにしようかな．
cartographer-rosをcatkin buildでbuildする

# 概要
[cartographer-rosの公式ドキュメント](https://google-cartographer-ros.readthedocs.io/en/latest/compilation.html)ではcatkin_make_isolatedを使用してビルドを行っていますが、ここではcatkin buildを用いてビルドを行ってみます。

# 環境

| 項目 | 値 |
| ----- | ----- |
|CPU | Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz|
|GPU |GTX 1650 (Laptop) 4GB|
|Ubuntu	| 20.04 |
|ROS | Noetic |

Noetic、Melodic (docker環境)で動作確認済みです。

# cartographer導入の手順
## インストール、ビルドに必要なものの導入
### Noeticの場合
cartographerのインストール、ビルドに必要

```shell
sudo apt-get update
sudo apt-get install -y python3-wstool python3-rosdep ninja-build stow
```
catkin buildに必要

```shell
sudo apt install python3-osrf-pycommon python3-catkin-tools
sudo apt install build-essential
```

### Melodic以前の場合
cartographerのインストール、ビルドに必要

```shell
sudo apt-get update
sudo apt-get install -y python-wstool python-rosdep ninja-build stow
```
catkin buildに必要

```shell
sudo apt install python-catkin-tools
```

## ワークスペースの初期化
バージョンは適宜変更する

```shell
source /opt/ros/noetic/setup.bash
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws
catkin build
source devel/setup.bash
```

## cartographerのクローン

```shell
wstool init src
wstool merge -t src https://raw.githubusercontent.com/cartographer-project/cartographer_ros/master/cartographer_ros.rosinstall
wstool update -t src
```

## 依存関係の解決

```shell
rosdep install --from-paths src --ignore-src --rosdistro=${ROS_DISTRO} -y
```

## cartographerが利用するabceil-cpp libraryのクローン、ビルド

```shell
src/cartographer/scripts/install_abseil.sh
```

## catkin build

```shell
catkin build
source devel/setup.bash
```

筆者の環境ではcatkin buildの所要時間は4分でした。 

# 動作確認
cartographerの2D backpack demoをダウンロードしてlaunch

```shell
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/backpack_2d/cartographer_paper_deutsches_museum.bag
roslaunch cartographer_ros demo_backpack_2d.launch bag_filename:=${HOME}/Downloads/cartographer_paper_deutsches_museum.bag
```

Rvizが立ち上がり地図生成の様子が確認できればokです。

# 参考文献
[ROS noeticでcatkin buildを使う](https://zenn.dev/suisuiso/articles/08177aacbffc7a)
[ROS catkin buildの簡単な使い方](https://qiita.com/harumo11/items/ae604ba2e17ffda529c2)
[Compiling Cartographer ROS](https://google-cartographer-ros.readthedocs.io/en/latest/compilation.html)
[Migrating from catkin_make](https://catkin-tools.readthedocs.io/en/latest/migration.html)
ログインの有無で条件指定

# authenticate_user!
コントローラーのクラスの下に定義し、ログインしていないユーザーが行えるアクションを制限する。

```○○_controller.rb
before_action :authenticate_user!, only: [:index, :create]
```
# only
指定するアクションのみ

#except
指定するアクション以外
# 終わり
ログイン状態の有無をIF文で定義しようとして時間を使ってしまいました。
authenticate_user!備忘録
後々、mainブランチにマージする時に楽になる方法 => rebaseを使う

# 想定シーン
mainブランチから派生させて作業ブランチでいくつかコミットしている間に、
リモートリポのmainブランチのコミットが進んでいる場合、
作業ブランチをpushする前にmainブランチにpullする際や、作業ブランチをpushしてgithub上でmainブランチにマージする場合、マージコミットが作られてしまうし、マージする際にファイルの変更分をチェックする作業が面倒

=> rebaseを使うとこの面倒な作業を省略できる

# シナリオ① rebaseなし
=>マージコミットが作られるし、面倒
## シナリオ再現手順
git pull origin main
git checkout -b no_rebase_no_conflict
local.txtを作成
git add local_no_rebase_no_conflict.txt
git commit -m "no conflict no rebase on local"
github上でmainブランチでremote_no_rebase_no_conflict.txt作成
github上でmainブランチでcommit
git checkout no_rebase_no_conflict
**git pull origin main(ここで上記で述べた面倒な作業をしなくていはいけないし、マージコミットが発生)**
git log --oneline -all --graph(このコマンドでコミット履歴が分岐して把握しにくくなることが確認できる)
git push origin no_rebase_no_conflict

# シナリオ② rebaseあり
=>マージコミットが作られないし、楽
## シナリオ再現手順
git checkout main
git pull origin main
git checkout -b no_conflict_yes_rebase
local.txtを作成
git add local_no_conflict_yes_rebase.txt
git commit -m "no conflict yes rebase on local"
github上でmainブランチでremote_no_conflict_yes_rebase.txt作成
github上でmainブランチでcommit
git checkout no_conflict_yes_rebase
**git pull --rebase origin main**
git log --oneline --all --graph(このコマンドでコミット履歴が綺麗で把握しやすいことが確認できる)
git push origin no_conflict_yes_rebase
【Dash(python)】table に画像を挿入する

# 1. 概要

Dash のテーブルに画像を挿入したいときありますよね！
Dash に関する記事があまりなく、かつテーブルに画像を挿入する方法もググってもなかったので記事にしておきます。

# 2. 実装
紹介する方法では、**テーブルの元となる pd.DataFrame を作成し、そこへ ​html.IMG を挿入する**という方法です。この際、画像はbase64でエンコードをする必要があります。少々乱暴ではありますが、一番手っ取り早くできました。
*"百聞は一見に如かず"* ということでサンプルコードを載せておきます(※画像へのパスを変更すれば動作することを確認していますので試してみてください）。


```python
# __feture__
from __future__ import annotations

# 組み込み
import os
import base64

# サードパーティ
import dash
import pandas as pd
import dash_html_components as html
import dash_bootstrap_components as dbc


def get_media_type(ext: str) -> str:
    """拡張子からメディアタイプを取得する
    Args:
        ext (str): 画像の拡張子。ex) ".xxx"
    """

    media_type_dict = {
        ".jpeg": "data:image/jpeg;base64",
        ".jpg": "data:image/jpeg;base64",
        ".gif": "data:image/gif;base64",
        ".png": "data:image/png;base64",
        ".svg": "data:image/svg+xml;base64",
    }

    try:
        return media_type_dict[ext]
    except KeyError:
        raise KeyError(f"Not Support Extention → '{ext}'")


def local_img_to_base64(path: str) -> bytes:
    """ローカルの画像をbase64にエンコード"""
    with open(path, "rb") as f:
        img_base64 = base64.b64encode(f.read())

    return img_base64


def base64_to_img_tag(img_base64: bytes, ext: str, height: str = "100px", width: str = "200px") -> html.Img:
    """base64からimg_tagを生成する

    Args:
        img_base64 (bytes): base64。
        ext (str): 拡張子. ec) .png
        height (str, optional): 画像の縦幅. Defaults to "100px".
        width (str, optional): 画像の横幅. Defaults to "200px".

    Returns:
        html.IMG.IMG: 生成したimg_tag.
    """

    img_binary = img_base64.decode()
    media_type = get_media_type(ext)

    img_tag = html.Img(
        src=f"{media_type},{img_binary}",
        height=height,
        width=width,
    )

    return img_tag


def local_img_to_tag(path: str, height: str = "30vh", width: str = "30vh") -> html.Img:
    """ローカルにある画像

    Args:
        path (str): img_tagに変換する画像へのpath
        height (str, optional): 変換後のheight. Defaults to "30vh".
        width (str, optional): 変換後のwidth. Defaults to "30vh".

    Returns:
        html.IMG.IMG: 作成したIMGタグ。
    """
    _, ext = os.path.splitext(path.split("/")[-1])
    img_base64 = local_img_to_base64(path)
    img_tag = base64_to_img_tag(img_base64, ext, height=height, width=width)

    return img_tag


def make_table():
    path = "the_carp_boy.jpeg"
    df = pd.DataFrame({'広島': ["梵", "東出", "栗原", "新井", "嶋", "緒方", "廣瀬", "倉", "黒田"],
                       "巨人": ["高橋由", "谷", "小笠原", "李承燁", "ゴンザレス", "阿部", "小坂", "鈴木尚", "内海"]})

    img_list = [local_img_to_tag(path) for _ in range(df.shape[0])]
    df.insert(0, "img", img_list)

    table = dbc.Table.from_dataframe(
        df,
        className='table-scroll',
        striped=True,
        bordered=True,
        hover=True,
    )

    return table

app = dash.Dash(__name__)
app.layout = make_table()

app.run_server(debug=True)
```

# 3. 結果
![スクリーンショット 2021-06-03 23.08.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349293/2a0a24ce-e2c9-9c51-e382-e6196409aae4.png)


## 参考
https://github.com/plotly/dash-table/issues/383
Laravelのコマンド

# Laravelのアプリを作成

composer create-project laravel/laravel [アプリ名] --prefer-dist 6.*

composer create-project laravel/laravel <font color="Red">laravel_bbs</font> --prefer-dist 6.*


### phpMyAdminの起動

- php -S 0.0.0.0:8880 -t ~/environment/phpmyadmin

### phpMyAdminへのログイン

- ユーザー名: root

- パスワード: secret

# データベースの作成

### データベースにログイン

- mysql -u root -p

### データベースの作成

- CREATE DATABASE laravel_bbs_development;

### 作成したデータベースの確認

- SHOW DATABASES;

### SQL の入力画面から抜ける

- exit;

## Laravel の開発用サーバを起動

- cd <font color="Red">laravel_bbs</font>

- php artisan serve --port=$PORT


- cd laravel_bbs && php artisan serve --port=$PORT

# Laravelのコントローラーを作成

php artisan make:controller <font color="Red">コントローラー名</font>

例

php artisan make:controller <font color="Red">SampleController</font>

php artisan make:controller ShowProfile --invokable

# モデル＆マイグレーションを作成

php artisan make:model Message --migration

# マイグレーションの実行

php artisan migrate

# tinkerの起動

php artisan tinker

$message = new App\Message();
$message->name = 'Taro Yamada';
$message->body = 'This is a test.';

$message->save();

## コマンド

ls
pwd
cd
mv
cp
Ionic Reactでページ遷移をios風にスライドアニメーション付にする方法

## サンプル
`ionic serve`で起動して挙動確認してみてください。
[サンプルソース](https://github.com/harutaka814/tutorial-photo-gallery-react "")

## 大事な部分
①まず、IonApp, IonReactRouter, IonRouterOutletタグがしっかり使われているか確認しましょう。
②`setupConfig({mode: 'ios'})`を指定しましょう。(デフォだと違うアニメーションが適用されてるので、iosを指定する必要がある)

```React
const App: React.FC = () => {
  setupConfig({mode: 'ios'})
  return (
  <IonApp>
    <IonReactRouter>
        <IonRouterOutlet>
          <Route path="/tab1" component={Tab1} exact={true} />
          <Route path="/tab2" component={Tab2} exact={true} />
          <Route path="/tab2/details" component={Details} />
          <Route path="/tab3" component={Tab3} />
          <Route path="/" render={() => <Redirect to="/tab1" />} exact={true} />
        </IonRouterOutlet>
    </IonReactRouter>
  </IonApp>
  );
}
```

③IonPageでしっかりラップする。
④routerLinkで遷移先、routerDirectionで遷移する方向を指定しましょう　"forward" | "back" | "none" "root"

```React
const Tab1: React.FC = () => {
  return (
    <IonPage>
      <IonHeader>
        <IonToolbar>
          <IonTitle>Tab 1</IonTitle>
        </IonToolbar>
      </IonHeader>
      <IonContent>
        <IonHeader collapse="condense">
          <IonToolbar>
            <IonTitle size="large">Tab 1</IonTitle>
          </IonToolbar>
        </IonHeader>
        <ExploreContainer name="Tab 1 page" />
        <IonList>
          <IonItem routerLink="/tab3" routerDirection="forward">
            <IonLabel>tab 3</IonLabel>
          </IonItem>
          <IonItem routerLink="/tab2"  routerDirection="forward">
            <IonLabel>tab 2</IonLabel>
          </IonItem>
        </IonList>
      </IonContent>
    </IonPage>
  );
};
```

## まとめ
何をどうすれば、ページ遷移時のアニメーションが追加されるのかがわかりにくくめちゃくちゃハマった。
よく公式読んだらIonReactRouter, IonRouterOutlet, IonPage, Navigationを全部使わないとダメなんだろうな、、ということがわかった。
https://ionicframework.com/jp/docs/react/navigation#ionrouteroutlet