OmniAICreator/Qiita-1.07M huggingface dataset:
Railsにおける例外処理

##rails db:seed
rails db:seedコマンドは、db/seeds.rbの記述に基づいて、データベースにレコードを作成するコマンドです。
クローン直後に投入したい初期データがある場合に利用します。
ターミナル

```
# 初期データの投入
$ rails db:seed
```
【例】チケット販売を例とします

```db/seeds.rb
users = []
10000.times do |i|
 # usersに10000件新規ユーザーの情報を格納する
  users << User.new(name: "dummy-#{i+1}", ticket_count: 0)
end
# importメソッドの引数に配列を渡して、まとめてレコードを作成する
User.import users
User.find(500).update(ticket_count: 123456789)
```
今回は初期データの作成に、activerecord-importというgemを利用しています。
これは、通常通り10000回User.createするよりも、高速に大量のレコードを作成できるからです。
参考リンク
https://qiita.com/xend/items/79184ded56158ea1b97a
###例外
例外とは、ある処理を実行した際の結果が、期待されるものと異なる状況を指します。 RubyおよびRuby on Railsでは、Exceptionというクラスを継承する形で様々な例外が定義されています。NoMethodError、SyntaxError などは、全てExceptionクラスの子孫クラスであり、例外です。例外が発生すると、それ以降の処理は中止され、実行されなくなってしまいます。
今回rails db:seedを実行して投入した初期データには、意図的に例外を発生させる値が投入されているものがあります。

```db/seeds.rb
# ticket_countをint型で許容できる最大の値にする
User.find(500).update(ticket_count: 123456789)
```
idが500のユーザーのticket_countを、123456789に変更しています。これは、SQLのinteger型が許容できる最大の値であり、もし123456789より大きな値を保存しようとすると、RangeErrorという例外が発生し、保存に失敗します。ターミナルからrake distribute_ticket:executeを実行してみると、例外の発生するidが500までのユーザーについては、ticeket_countが10増加し、idが500番目以降のユーザーについては、例外が発生してしまったために、処理が中止され、ticket_countが増えていません。
###例外処理
例外処理とは、例外が発生した場合に実行する処理のことを指します。Ruby on Railsの開発を行う際に、よく利用するのがrescueです。
上記のrubyプログラムを実行すると、「1 / 0」の処理を行った際に、ZeroDivisionErrorという例外が発生します。これは、数字を0で割ろうとすると発生する例外です。
beginブロックの内部で例外が発生したため、rescue以下の処理が実行されます。
###rescue
rescueとは、発生した例外を捕捉し、例外が起こった際に呼び出される条件節です。
例外が発生しそうな部分をbeginから始まるブロックで囲み、ブロックの内部にrescueを記述して使用します。
サンプル

```
begin
# 数字を0で割ろうとすると、ZeroDivisionError例外が発生する
  1 / 0
rescue
# 例外が発生した時にrescue以下の処理が呼ばれる
  puts '0で割ることはできません'
end
```
通常、each, times, whileなどの繰り返しの最中に例外が発生した場合、繰り返し処理は途中で中止され、次のループが実行されることはありません。ただし、繰り返し処理の内部にrescueを記述していた場合、例外が発生したとしても、次のループに移ることができます。
大量のレコードを扱う処理で、例外が発生しても繰り返しを続行したい場合には、rescueを使いましょう。
###トランザクション
複数のレコードの更新を1つにまとめて行うことを指します。トランザクションを用いることで、「全て実行されるか、それとも全て実行されないか」という1か0の状況を作ることができます。
サンプル

```
# ECサイトの購入処理を模した架空のコード
ActiveRecord::Base.transaction do 
  current_user.pay!(@product.price)
  current_user.confirm_purchase!(@product)
end
```
上記のサンプルは、購入処理を模した架空のコードです。pay!メソッドで商品の料金を払い、confirm_purchase!メソッドで商品の注文を確定させています。料金の支払いと、商品の購入の確定は、常に1つのまとまりとして考えます。トランザクションを用いることによって、「料金の支払いに失敗したけど、商品は購入できた」「料金は支払ったけど、注文の確定に失敗し商品が届かなかった」といった事態を防ぐことができます。
###参考リンク
例外と呼んでいたものは、全てこのExceptionクラスを継承しています。
[Ruby Exceptionクラス ドキュメント]
(https://docs.ruby-lang.org/ja/latest/class/Exception.html)
[ActiveRecord Transactions ドキュメント(英語)]
(http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html)
IQ Botのカスタムロジック：スプリット（口座情報から銀行名や支店名だけを取り出す）

OCRの読み取り結果(`field_value`)が「あいうえ銀行かきくけ支店普通1234567」だった場合に、
ここから銀行名と支店名をそれぞれ別の項目として分けて出力したい、という場合はどうすればいいでしょうか？

そんなときに使えるのが、スプリットです。

#やりかた（チートシート）

答えを先に言ってしまうと、`field_value`が「あいうえ銀行かきくけ支店普通1234567」の場合に、
銀行名だけを取り出す処理は以下のとおりです。

```python:スプリットを使って銀行名を取り出す
#銀行名を取り出す
field_value = field_value.split("銀行")[0]
```

こんなかんじ↓で、「あいうえ」が取り出せたのがわかります。

|![銀行名の取り出し.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/aae7f08b-1e17-75d7-45bd-027ae2ce39d2.jpeg)|
|:-:|



また、同じく`field_value`が「あいうえ銀行かきくけ支店普通12345678」の場合に、
支店名だけを取り出す処理は以下のとおりです。

```python:スプリットを使って支店名を取り出す
#銀行の支店名を取り出す
field_value = field_value.split("銀行")[1]
field_value = field_value.split("支店")[0]
```

こんなかんじ↓で、「かきくけ」が取り出せたのがわかります。

|![支店名の取り出し.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/f81c6607-4de0-58d1-88cd-117dcb7a6d61.jpeg)|
|:-:|

#仕組みの説明

上記の処理をすると、なぜ銀行名や支店名が取り出せるのかの説明です。

わかる人は読み飛ばしてください。

##スプリット

スプリットは、「文字列をある区切り文字で区切って、リストにする」という処理です。

……うっ……急にハードルが上がったぞ……と思った方は、[文系初心者でもわかるsplitの説明](https://qiita.com/IQ_Bocchi/items/4e9fb40f9a69b22c301a)をご参照ください。

pythonにおけるスプリットの処理は、`処理対象.split(区切り文字)`　の要領で行うことができます。

`field_value.split("銀行")`という処理は、
「`field_value`を`"銀行"`という文字で区切ってリストにしてね」という意味です。

この処理をやると、以下のようなリストが取り出せます。
`["あいうえ","かきくけ支店普通1234567"]`

上記は２つの要素を持つリストで、
１番目の要素が`"あいうえ"`、２番目の要素が`"かきくけ支店普通1234567"`です。

##リストの中身を取り出す

上記の処理で、晴れて文字列を「リスト」にしたわけですが、
今度はそのリストから要素を取り出す処理です。

`リスト[インデックス]`　の要領で、これができます。

「インデックス」はざっくり言えば、**リストの何番目にその要素が入っているかを示す番号**なのですが、**開始はゼロから**になるというのがちょっとした注意点です。

##改めて、銀行名を取り出す処理を見てみましょう

今までの話を踏まえて、改めて銀行名を取り出す処理を見てみましょう。

```python:スプリットを使って銀行名を取り出す
#銀行名を取り出す
field_value = field_value.split("銀行")[0]
```

これはつまり、「`field_value`の中身を`"銀行"`という文字で区切ってリストにしてね。そしてそのリストの１番目の要素（＝インデックスはゼロ！）を取り出して、そいつを`field_value`に入れてね」

「`field_value`の中身を`"銀行"`という文字で区切ってリストにしてね。」が`field_value.split("銀行")`、

「そしてそのリストの１番目の要素（＝インデックスはゼロ！）を取り出して」が`[0]`、

「そいつを`field_value`に入れてね」が`field_value = `に、

それぞれ該当します。


##改めて、支店名を取り出す処理を見てみましょう

ここまで押さえらえれていれば、支店名の処理もすぐに理解ができると思います。

```python:スプリットを使って支店名を取り出す
#銀行の支店名を取り出す
field_value = field_value.split("銀行")[1]
field_value = field_value.split("支店")[0]
```

１行目は、「`field_value`の中身を`"銀行"`という文字で区切ってリストにしてね。そしてそのリストの２番目の要素（＝インデックスは１！）を取り出して、そいつを`field_value`に入れてね」という意味です。

なので、この時点で`field_value`の中身は`"かきくけ支店普通1234567"`になっています。

その`field_value`に対して、２行目では、

「`field_value`の中身を`"支店"`という文字で区切ってリストにしてね。そしてそのリストの１番目の要素（＝インデックスはゼロ！）を取り出して、そいつを`field_value`に入れてね」

という処理を行っています。

「`field_value`の中身を`"支店"`という文字で区切ってリストにしてね」の時点で、

`["かきくけ","普通1234567"]`　というリストができているので、

こいつの１番目の要素を取り出すことで、「かきくけ」という支店名が取り出せたというわけです！

##エラー制御や、テーブルに適用するときは？

上記の説明を見て、以下も知りたい！　と思った方は、[こちら](https://qiita.com/IQ_Bocchi/items/f363d4b2b848b6425a80)の記事をご参照ください。

- 「銀行」や「支店」といった文字が含まれていなかったらどうなる？　（エラー制御）
- テーブル項目にSplitをかけたいときはどうする？
Androidアプリ開発中にバーションアップで調べようと思うと（個人的に）ちょっと面倒なものまとめ

日々更新していきます...

## Fabric Gradle Plugin

https://docs.fabric.io/android/changelog.html#fabric-gradle-plugin

## 合わせて読むとおすすめ

[よくチェックするAndroidアプリ開発で重要なRelease Notesリンクまとめ](https://qiita.com/operandoOS/items/d2feb53cd55e94c4e9a6)
While の基本

##環境,前提
Ruby 2.5.1
MacOS Mojave Ver.10.14.6

本記事はRubyがインストールされた前提の記事です。
Rubyをインストールしたあと、とにかくRubyをいろいろ触ってみて慣れていくための記事です。お役に立てば幸いです。


# whileの基本


```sample.rb
while 条件 do
   // 繰り返す処理
end
```



では1から10までの合計をwhileを用いて算出してみます。


```sample.rb
sum = 0
i = 1
while i <= 10 do
sum += i
i+=1
end
puts sum
```

実行結果は以下のように55となります。


```:Tarminal
55
```

#whileとforの使い分け
どちらも繰り返し処理の際に用いられるものですが、どういった使い分けが良いでしょうか？以下のように使い分けるのが良いと思います。

**・繰り返し回数が決まっておらず、条件を満たす限り回すのはwhile**
**・回数が明確に決まっている場合はfor**
TortoiseGitでSquashを使わずにコミットログをまとめる方法

Gitを使っていると、ローカルブランチで作業することが多い関係上、コミットログを整理したいことがよくあります。

ローカルブランチは好き勝手にログを書いちゃいますからね。
それがマスターブランチに記録されてしまったら目も当てられません。

通常はマスターブランチ等にマージする際にSquash mergeを使えばよいのですが、GitLabのバージョンなどによってはマージリクエスト時にSquash merge非対応のケースがあります。
また、Hook Scriptの都合などでレビュー前にログをまとめたいケースもあるでしょう。

その場合、Squash用のローカルブランチを作って、そこでログを整理した後にマスターブランチにMergeするという少々手間な方法をとらなければなりませんでした。

しかしながらTortoiseGitを使って、もっと簡単にログをまとめる方法がありますので、紹介します。
＊コミット間でConflictが起こっていないケースを想定しています。

1. ログウィンドウを開き、まとめたいログをCtrlキーを押しながら複数選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267148/d786a22d-bad0-a610-a926-6c9b73ba38a8.png)

2. 右クリックを押して、「Combine to one commit」（英語）
（これが表示されない場合は、競合が発生したりしてまとめられないログになります）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267148/e23b5ab9-3d19-6370-2c79-996a5a810c38.png)

3. コミット画面になるので、コミットログを記入します。
4. 結果をコミットして、Pushします。

これで、ログをまとめられます。
ローカルで簡単にできますので、活用してみてください。
Raspberry Piにmackerel-agentを入れて監視する

何番煎じか分かりませんが、自分用の備忘録として残しておきます。。。

# Mackerelとは

株式会社はてなが提供する、エージェント型サーバリソース監視・可視化システム。
何台かまでは無償で利用できる。

[Mackerel公式サイト（特徴）](https://mackerel.io/ja/features/)


x86/x64環境であれば、公式のリポジトリよりパッケージ管理システム経由で簡単にインストール可能だが
Raspberry Pi(Armv7l) に対応したリポジトリは存在しない。

その代わり、GitHubにてコンパイル済みのバイナリを公開してくれているので、それを利用する。

[Github mackerelio/mackerel-agent Release](https://github.com/mackerelio/mackerel-agent/releases)


# 環境

* Raspberry Pi 3B +
* FedoraServer 31 ARM

```bash
$ uname -a
Linux localhost.localdomain 5.5.13-200.fc31.armv7hl #1 SMP Wed Mar 25 22:51:07 UTC 2020 armv7l armv7l armv7l GNU/Linux
```

# Mackerel-agentのダウンロードとインストール

[GitHubのリリースページ](https://github.com/mackerelio/mackerel-agent/releases)より、「`mackerel-agent_linux_arm.tar.gz`」を探し、ダウンロードする。

下記は `v0.67.1`をダウンロードする例。

```bash
$ wget https://github.com/mackerelio/mackerel-agent/releases/download/v0.67.1/mackerel-agent_linux_arm.tar.gz
```


アーカイブを展開し、バイナリファイルと設定ファイルを配置する。

```bash
$ tar xfz mackerel-agent_linux_arm.tar.gz
$ sudo cp mackerel-agent_linux_arm/mackerel-agent /usr/local/bin/

$ sudo mkdir /etc/mackerel-agent
$ sudo cp mackerel-agent_linux_arm/mackerel-agent.conf /etc/mackerel-agent/
```

# Mackerel-agentの設定

## agentの設定

APIキーを設定する。

```bash
$ sudo mackerel-agent init -apikey="YOUR API KEY"
```

APIキーは、Mackerelログイン後画面の「オーガニゼーション詳細」ページにある。


## サービスの設定

`/etc/systemd/system/mackerel-agent.service` というファイルを作る。

※ファイル名、`Description`は任意。
ファイル名はそのままサービス名になるので、他と被らない名前にする。


```text:mackerel-agent.service
[Unit]
Description=Mackerel Agent Service
After=network.target

[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/mackerel-agent
Restart=on-failure

[Install]
WantedBy=multi-user.target
```



ファイルを作った後は、設定ファイルの再読み込みを行う

```bash
$ sudo systemctl daemon-reload
```

## サービス起動テスト

```bash
$ sudo systemctl start mackerel-agent.service
$ sudo systemctl status mackerel-agent.service
● mackerel-agent.service - Mackerel Agent Service
   Loaded: loaded (/etc/systemd/system/mackerel-agent.service; disabled; vendor preset: disabled)
   Active: active (running) since Mon 2020-04-06 16:46:02 JST; 11s ago
 Main PID: 7261 (mackerel-agent)
    Tasks: 9 (limit: 4915)
   Memory: 5.6M
      CPU: 301ms
   CGroup: /system.slice/mackerel-agent.service
           └─7261 /usr/local/bin/mackerel-agent

```

`Active: active (running)` と表示されているので、正常に起動している。

しばらく待って、Mackerelの画面にメトリックが表示されれば、正常に動作している。

## サービス自動起動設定

問題なさそうなら、自動起動設定を行う

```bash
$ sudo systemctl enable mackerel-agent.service 
Created symlink /etc/systemd/system/multi-user.target.wants/mackerel-agent.service → /etc/systemd/system/mackerel-agent.service.
```
tee　

#欲張りなコマンド　
コマンドの結果を標準出力したいし、ファイルにも出力
したいと思った時に使えるコマンド

######実行例

```
echo "どっちにも表示できる" | tee test1.txt
```

---

標準出力エラーも保存して、画面表示したときに使うやつ

```
ping host8888 2>&1 | tee pinglog.txt
 ping: unknown host host8888
cat pinglog.txt 
 ping: unknown host host1234
```


---
-aをつけると上書きされないで追加できる。

```
tee [オプション]ファイル名
```
Arduinoでlcdディスプレイにhello world

# 以下を参考
https://iot.keicode.com/arduino/arduino-project-lcd.php
#完成図

https://files.slack.com/files-pri/TPU9ADEJG-F011BGEFDK3/ios__________.jpg

#まとめ
詳細な回路図とかは随時編集したいとおもうが、今のところは上記の記事を参考にしていただきたい。実行した感想としては、回路を組むのが結構めんどくさい。今後ディスプレイと他の電子部品を組み合わせてみたい。
SNMPv3について

#前提
・古いタイプの人間なので今までSNMPv2cしか触ってこなかった
・SNMPv3での監視方法は知らない

SNMPマネージャはzabbixサーバ

zabbixサーバの設定
・Red Hat Enterprise Linux Server release 7.7
・zabbix 3.0

#やりたい事
SNMPv3でポーリング監視及びトラップ監視を実装する

#この記事での言及範囲
・SNMPv3でsnmpwalkができるようにする
・SNMPv3でtrapをエージェントから送信しマネージャで正常に受信できるようにする
・MIBインポートはここでは触れない　以下参照
　[プライベートMIBインポート手順](https://qiita.com/Masahikoueda/items/956bb2845982144aaa0a)

##１. snmpエージェント側での設定

設定しなければいけないものは以下

**①ユーザ名**
**②パスワード**　 
**③セキュリティレベル** 
**④認証方式** 
**⑤暗号化方式**
**⑥暗号化するためのパスワード**

これが埋まればコマンドも打てるし、管理画面からの設定もできる

しっかり理解して決めなければいけないのは
**③④⑤⑥**

**③セキュリティレベル**
**1.noAuthNoPriv**　ユーザ名だけを使用して認証
**2.authNoPriv**　HMAC-MD5 HMAC-SHAを使用し認証。暗号化はなし
**3.authPriv**　HMAC-MD5 HMAC-SHAを使用し認証　暗号化する

**④認証方式 ※③の2. 3のみ関係あり**
HMAC-MD5　HMAC-SHAを選択する
コマンドで打つ際は短縮したりするので注意

**⑤暗号化方式　※③の3のみ関係あり**
DES or AESを選択する

**⑥暗号化PW　※③の3のみ関係あり**
パスワードは禁止文字あるので注意（②についても同様）

※禁止文字
\ , / : ; * ? " < > | & % ^

エージェント側の設定はこれでOK


##2. snmpwalkでengineIDを取得してみる

trap設定でengineIDが必要になるのでコマンドサンプルの様な書き方

ユーザ名　hello
パスワード　password
エージェント機器IPアドレス 192.168.10.11
セキュリティレベル authNoPriv　
認証方式　HMAC-SHA

コマンドサンプル

```
# snmpwalk -v3 -u hello -l authNoPriv -a SHA -A password 192.168.10.11 .1.3.6.1.6.3.10.2.1.1.0
```

上記コマンドを実行するとengineIDが表示される
trap設定において必要になるため控えておく

<font color="Red">**※注意　監視対象機器によってはengineIDを機器側で設定する必要がある（複数台同じ機器を利用する場合初期設定のままだとenginIDが重複する可能性がある）ので、機器のベンダや説明書をしっかり確認すること**</font>

engineIDは以下の様に書き換える

例：80 00 41 Z6 03 11 E0 D8 1D D3 B4 → 0x800041Z60311E0D81DD3B4

（頭に0xをつけて空白を消す）

##3. snmpマネージャサーバ側での設定

/etc/snmp/snmptrapd.conf に以下記述を追加する

**例**

```
#ユーザ情報を追加している
createUser -e 0x800041Z60311E0D81DD396 hello SHA password　#UPS 1号機
createUser -e 0x800041Z60311E0D81DD3B4 hello SHA password　#UPS 2号機

#helloのユーザで送信されてくるtrapをsyslog出力、コマンド実行、転送
authUser log,execute,net hello
```

設定追加したら、snmptrapd.serviceを停止、起動

※systemctl restart snmptrapd.service  では設定読み込みしてくれないみたいなので

```
# systemctl stop snmptrapd.service
# systemctl start snmptrapd.service
```

これにより

/var/lib/net-snmp/snmptrapd.conf にユーザが追加される

この状況であれば /etc/snmp/snmptrapd.conf のユーザ情報は必要なくなるので
createuserの行は削除してOK

(トラップが正常に飛んでいることを確認してから削除推奨ではあるが
　確実に反映されている自信があるならここで削除して問題ない)


**設定完了**
gitの雑多メモ

結構gitにも慣れてきたけどそろそろqiitaに自分用にまとめてみる。
脳死でも読めるようにまとめます。

## gitとはなにか？
分散型バージョン管理システム。wiki見よう。
https://ja.wikipedia.org/wiki/Git

**最近の環境構築**
mac環境
https://qiita.com/Chita_s0le/items/cdb9dd0af679845768e1

### gitコマンド


`git clone [gitHubからもってきたURL]`
gitリポジトリからローカルにダウンロードするやつ

`git pull`　＝　`git fetch`　+　`git merge`
最新のものをローカルリポジトリの今のブランチに落とす作業、基本的にはpullでいい

`git checkout [移動したいbranchName]`
移動したいブランチに移動するコマンド

`git checkout -b [branchName]`
現在いるブランチを元にして新たなブランチを切り分ける

`git add .`
ステージングに変更を上げる

`git commit -m "コミットする時のコメント"`
上がった変更点をコミットする

`git push -u origin [branchName]`
リモートリポジトリの同じブランチに上げる

`git stash`
今変更してるやつコミットしないけど他ブランチに移動したい！ってときにエラー出たらとりあえずこれ。
`git stash pop`　すれば元に戻る。

develop(branchの元)に変更があった場合
`git  checkout develop`
`git pull`
`git checkout [いじったbranchName]`
`git rebase develop`　→　gitの歴史がぐちゃぐちゃにならないようにするやつで便利
で、conflictの解消して`push`

### GitHub
https://github.co.jp/

### GitLab
https://about.gitlab.com/

### 使ってきて
gitLabめちゃめちゃ楽。
Sequel Proで踏み台サーバー経由接続

## 概要
Sequel Pro特有の些細な理由でしばらく詰まったのでメモです。

## 環境

### 認証方式

パスワード認証方式

### 構成

- PC
	- MacBook Pro
- サーバーA
	- 接続したいサーバー
	- サーバーBからSSH接続可能
- サーバーB
	- 踏み台サーバー
	- PCからSSH接続可能
- MySQLサーバー
	- サーバーAから接続可能

## 自分PC設定ファイル

`~/.ssh/config`にサーバーAに接続する設定を記述。

```:例
# ふみだい
Host server_B
  HostName XXX.XXX.XXX.XXX
  Port XXX
  User B_user

Host server_A
  HostName XXX.XXX.XXX.XXX
  Port XXX
  User A_user
  ProxyCommand ssh -CW %h:%p server_B
```

## Sequel Proの設定

接続するとサーバーAとサーバーBのパスワードを求められます。
接続情報画面では**SSHのパスワード(サーバーAのパスワード)を入力しているとエラーになります。**
これでしばらく詰まりました。

`permission denied (publickey,password)`としか出ないです。

<img width="485" alt="ssh.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489139/8529ca02-291d-2bea-b081-3279a0eb8839.png">
SSLHでSoftether(SSTP)とApacheを共存

#SSLHでSoftether(SSTP)とApacheを共存
　443番ポートへのアクセスをプロトコルによって判別して、複数のサービスに振り分けることで443番を共有可能にする手段としてSSLH(https://github.com/yrutschle/sslh) がありますが、対応しているVPNプロトコルはOpenVPNのみです。
　Sofetherの独自プロトコルやSSTPプロトコルをSSLHのバックで使用する設定を模索して、ベターではありますが動作しましたので記載します。

SSLHのヘルプ

```bash
sslh -h
sslh 1.18-1
usage:
        sslh  [-v] [-i] [-V] [-f] [-n] [--transparent] [-F <file>]
        [-t <timeout>] [-P <pidfile>] -u <username> -p <add> [-p <addr> ...]
        [--ssh <addr>]
        [--openvpn <addr>]
        [--tinc <addr>]
        [--xmpp <addr>]
        [--http <addr>]
        [--ssl <addr>]
        [--tls <addr>]
        [--adb <addr>]
        [--anyprot <addr>]
        [--on-timeout <addr>]
```
設定は下記のように各サービスサーバのIPを --ssh hogehoge.com の形で列挙していきますが、この中に <b>--anyprot</b> として指定したポートにはSSLHが対応していないプロトコルのパケットが全て転送されます。

ここにSoftetherの待ち受けポートを記載することでSoftetherの対応する全てのVPNプロトコルがSSLHのバックで使用可能になりました。


```bash
sudo nano /etc/default/sslh

RUN=yes

# binary to use: forked (sslh) or single-thread (sslh-select) version
# systemd users: don't forget to modify /lib/systemd/system/sslh.service
DAEMON=/usr/sbin/sslh

#softetherのポート:8080 (localhost)
DAEMON_OPTS="--user sslh --listen 192.168.1.1:443 --anyprot 127.0.0.1:8080 --ssl 127.0.0.1:8443...
```

SSLHのソースに、その他のプロトコルの判別ルールを追記するのがベストですがそのような知識が現状ありませんので取り急ぎの手段としては使えるかなとは思います。
macOS環境構築雑多メモ

macの最近の環境構築。winもほぼ変わらないと思うのでURL見つけておこう。

- homebrew
- git
- nodebrew
- npm

###インストール内容
**homebrew**

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

...
  ==> The Xcode Command Line Tools will be installed.

  Press RETURN to continue or any other key to abort
```

RETURNして自分のPC開く時のpassword入力

```
  Already up-to-date.
  ==> Installation successful!
```

**git**

```
$ brew install git
```

参考にしたサイト
https://qiita.com/micheleno13/items/133aee005ae37c28960e

**nodebrew**

```
$ brew install nodebrew
```

参考にしたサイト
https://qiita.com/mame_daifuku/items/373daf5f49ee585ea498
pythonでフォルダ内の大量のCSVファイルを統合する(ヘッダー無しデータ）

#はじめに
- 大量のCSVファイルを１つのCSVファイルに統合します。

#事前準備
- CSVファイルのヘッダーは無しのデータを用意する。
- 統合したいCSVファイルをフォルダにまとめておく。
- 統合した結果の出力ファイル名を指定する。

#コード

```python

import csv, os
import pandas as pd

#CSVファイルがあるフォルダを指定 (1)参照先
csv_folder_path = os.path.join(".","csv_folder", "headerRemoved")

#ファイル名の一覧をリスト形式で取得
csv_files_list = os.listdir(csv_folder_path)

#全てのcsvファイル内の行を格納するリストを作成
csv_rows=[]

#読み込むファイルリストからファイル名を指定し、全行をcsv_rowsリストに格納する。
for csv_filename in csv_files_list:
    csv_file_obj = open(os.path.join(csv_folder_path, csv_filename))
    reader_obj = csv.reader(csv_file_obj)
    for row in reader_obj:
        csv_rows.append(row)
csv_file_obj.close()

#リストをdataframe型に変換.
df = pd.DataFrame(csv_rows)

#書き出す列の範囲を指定する（0～44番のみ） (3)書き出し範囲
df = df.iloc[:,range(0,44)]

#dataframeをcsvに変換して保存 (2)出力ファイル名
df.to_csv(os.path.join(".","merged_file.csv"), index=False)
```

#解説
- CSVファイルがあるフォルダからファイル名のリストを取得
- ファイル名リストに沿ってファイルごとにファイルオブジェクトを作成、さらにそこからReaderオブジェクトを作り一行ずつファイルから行を読み込む
- すべてのファイルで繰り返し、最終的に１つのリストの全ファイルの全行を集める
- 書き出す前にリストをDataFrame型に変換する。
- ここでは書き出す前に必要な列の範囲を指定している。
- 最後にpd.to_csvで指定したファイル名のCSVファイルに書き出す。このときindex=Falseとすることでindexは書き出さない。

#感想
- ちなみにdfに変換されているので任意の列だけを表示を取り出すことができる。
下記のようにすれば12列目、38列目をこの順序で指定できる。

```python
df.iloc[:,[38,12]]
```

- 次はdfから色々なグラフをプロットしたい。
ブロックを使う配列のメソッド

####mapメソッド
戻り値をそのまま新しい変数に入れることができる。

```ruby:ruby

numbers = [1,2,3,4,5]
new_numbers = numbers.map { |n| n * 10 }
puts new_numbers  #=> [10,20,30,40,50] 
```
<br>

####selectメソッド
各要素を評価し、真の要素を戻り値として配列にして返すメソッド
rejectメソッドはselectの反対で真になった要素を除外した配列を返す。

```ruby:ruby
numbers = [1,2,3,4,5]
even_numbers = numbers.select { |n| n.even? }
puts even_numbers  #=>   [2,4]
```
<br>
【メモ】Nuxt + Vuetify でSSR時だけ一部のUIが機能しなくなる問題

# 現象
Vuetifyの `<v-expansion-panel>` を使用しているページで、
SSR時のみ他のUIが動作しなくなる現象が発生したのでメモ。

# 再現コード
最小の再現コードを探った結果、どうやら、`<v-expansion-panel-header>` の中で、`<div>`と`<v-btn>` を使用していると発生するらしい。

```html
<v-expansion-panel-header>
  <div>
    <span>title</span>
    <v-btn>Button</v-btn>
  </div>
</v-expansion-panel-header>
```

# 対応
`<div>`の中に`<v-btn>`という条件下のみ発生するようなので、<div>を`<p>`や`<section>`に置き換えると問題は解決した。

```html
<v-expansion-panel-header>
  <section>
    <span>title</span>
    <v-btn>Button</v-btn>
  </section>
</v-expansion-panel-header>
```

あるいは、SSR時限定の現象なので、`<client-only>`を使うことでも回避できる。

```html
<v-expansion-panel-header>
  <div>
    <span>title</span>
    <client-only><v-btn>Button</v-btn></client-only>
  </div>
</v-expansion-panel-header>
```

`<client-only>`で回避しておくのが安全か。



コンソールにもサーバー側のログにもエラーが出ないので原因を特定するのに困った。
……なんだコレ？
さくらのクラウドに「Jitsi Meet」を導入してみた

最近はテレビ会議の仕組みとしてZoomの勢いがすごいですね。
あまりにもZoom一強というような状況もあまり良くないと個人的に思うところや、会社によっては外部のクラウドサービスを利用することが困難なケースもあると思います。

オンプレミスやプライベートなクラウド環境上にデプロイしプライベートに利用できるオープンソースのテレビ会議システムがないかと思ったらとてもいいものがありました。

[Jitsi Meet](https://jitsi.org/jitsi-meet/)

Jitsi Meetの特徴として
* アカウント発行の必要なし
* 専用なクライアントのインストール不要（モダンなブラウザであればそのまま利用可能）
というめんどくさい諸々の作業が必要なくすぐに利用できます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614574/91f25039-0dd9-0c38-a085-dde57d98ae4d.png)

UI自体は日本語化されていないですが、操作感としてはとてもシンプルです。
適当にルームの名称を入力し「Go」を押下するとすぐにルームが作成されてビデオ会議が始まります。ルームのURLを展開参加してほしい人にお伝えすることで、モダンなブラウザであればすぐに参加できます。
※AndroidやiOSの場合にはクライアントもあるようです。

また、クライアントのインストールの必要なく画面共有することもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614574/b6b5ca9c-b972-aaac-37a4-159c3afb5631.png)


# インストール方法

インストールの手順自体もとても簡単です。
今回はさくらのクラウド上にUbuntuにデプロイしそれにインストールするようにしてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614574/5b3e2208-129b-ac10-44d7-d13eb522e2f2.png)

今回はUbuntu Server 18.04のイメージを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614574/bd049a7e-be39-f660-114a-c90d36be0fcc.png)

サーバプランは物は試しなので2コア2GBを選んでみました。
（適宜負荷状況に応じてプラン変更していただければと思います）
FQDNの設定が必要となるので、サーバ作成後に払い出されたIPアドレスとDNSを紐付けをおこないます。
※今回はクラウドのDNSを利用しました。ドメインは別途取得が必要です。

今回はサンプルとして「jitsi.example.com」のFQDNを設定するものとします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614574/aa3c1264-e016-2155-ea9f-0d6962df2c25.png)


DNSの設定が完了したらサーバにターミナルなどでSSH接続し設定を行ってゆきます。

```bash
$ sudo su -
# apt-get -y install gnupg2
# echo 'deb https://download.jitsi.org stable/' >> /etc/apt/sources.list.d/jitsi-stable.list
# wget -qO - https://download.jitsi.org/jitsi-key.gpg.key | apt-key add -
# apt-get update
# apt-get -y install jitsi-meet
```
FQDNの設定画面が表示されますので、上記で設定したFQDNの「jitsi.example.com」 を入力します。

インストールが完了した後にLet's Encryptの設定を行う必要がありますので、以下を実行します。

```bash
# /usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh
```

Let's Encryptの設定のためメールアドレスの入力が求められますので入力しEnterします。

以上でインストール完了です。
ね、簡単でしょ。

# 利用方法

発行したFQDNにウェブブラウザからアクセスします。

https://jitsi.example.com　（これは上記FQDNの場合のサンプルなので実際にはアクセスできません。）

一番最初の画面が表示されてすぐに利用開始可能です！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614574/91f25039-0dd9-0c38-a085-dde57d98ae4d.png)

なお、このままではインターネット環境にさらされている状態になるので、さくらのクラウド上で利用するのであれば、当該サーバに「パケットフィルタ」を設定しアクセス元を制限する、VPCルータのファイアウォールやリモートアクセスを使いセキュリティを担保可能です。

クラウドサーバにビデオ会議のソフトウェアをインストールすると大量のトラフィックで想定しないコストが発生する場合があるかと思いますが、さくらのクラウドではデータ転送料は無償なのでクラウド破産の心配なく、明瞭会計に利用できると思います:relaxed:
plunkerでtensorflow.js その27

#概要

plunkerでtensorflow.jsやってみた。
関数フィッティングやってみた。

#写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/f47d4734-2869-6233-4ded-e0d687ad6c18.png)


#サンプルコード


```
function predict(x) {
  return tf.tidy(() => {
    return tf.div(tf.exp(tf.mul(tf.mul(x.sub(a), x.sub(a)), tf.neg(b))), c)
  });
}
function loss(pred, label) {
  return tf.losses.meanSquaredError(pred, label).mean();
}
function train(xs, ys, numIterations) {
  for (let iter = 0; iter < numIterations; iter++) 
  {
    optimizer.minimize(() => {
      const pred = predict(xs);
      return loss(pred, ys);
    });
  }
}
const a = tf.variable(tf.scalar(Math.random()+5));
const b = tf.variable(tf.scalar(Math.random()));
const c = tf.variable(tf.scalar(Math.random()));
const learningRate = 0.01;
const optimizer = tf.train.adamax(learningRate);
const numIterations = 150;
const yy =  [3, 8, 28, 75, 221, 291, 255, 235, 190, 125, 70, 28, 12, 5];
const xs = tf.tensor2d([[1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14]], [14, 1]);
const ys = tf.tensor2d([[3], [8], [28], [75], [221], [291], [255], [235], [190], [125], [70], [28], [12], [5]], [14, 1]);
train(xs, ys, numIterations);
const aa = Number(a.dataSync());
const bb = Number(b.dataSync());
const cc = Number(c.dataSync());
var values = [];
for (var i = 0; i < 14; i++)
{
  values.push({
    x: i, 
    y: yy[i],
    pred: Math.exp((i - aa) * (i - aa) * - bb) / cc
  });
}
const spec = {
  '$schema': 'https://vega.github.io/schema/vega-lite/v2.json',
  'width': 300,
  'height': 300,
  'data': {
    'values': values
  },
  'layer': [{
    'mark': 'point',
    'encoding': {
      'x': {
        'field': 'x', 
        'type': 'quantitative'
      },
      'y': {
        'field': 'y', 
        'type': 'quantitative'
      }
    }
  }, {
    'mark': 'line',
    'encoding': {
      'x': {
        'field': 'x', 
        'type': 'quantitative'
      },
      'y': {
        'field': 'pred', 
        'type': 'quantitative'
      },
      'color': {
        'value': 'tomato'
      }
    }
  }]
};
vegaEmbed('#vis', spec);



```

#成果物

https://embed.plnkr.co/plunk/08g4GJS8D7lv9bB6

以上。
pythonで複数のフォーマットCSVファイルから見出しを削除する

#はじめに
- 大量のcsvファイルの見出し数行を全て削除したい
- 使ってるのはJupyter Notebook

#事前準備：
- 本ファイルはをカレントディレクトリにおく
- カレントディレクトリにあるMachine11_trdフォルダにヘッダー処理したいcsvファイルを入れておく。

```python
import csv, os

#処理したいフォルダのパスを作成　(1)参照先
csv_folder_path = os.path.join(".","InputFolder")

#アウトプット先のフォルダのパスを作成 (2)保存先
headerRemoved_path = os.path.join(csv_folder_path,"headerRemoved")

#ヘッダー削除したファイルを入れる新規フォルダを作成する。
os.makedirs(headerRemoved_path, exist_ok=True)

#カレントディレクトリ以下にある指定フォルダの全ファイルをループする
#指定フォルダ内のファイル名リストを取り出す
for csv_filename in os.listdir(csv_folder_path):
    if not csv_filename.endswith(".csv"):
        continue #csvファイルでなければスキップする
    #print("見出し削除中"+ csv_filename + "...")
    
    #CSVファイルから一行ずつ読み込む(最初の行をスキップする)
    csv_rows=[]
    csv_file_obj = open(os.path.join(csv_folder_path, csv_filename))
    reader_obj = csv.reader(csv_file_obj)
    
    for row in reader_obj:
        #一行目または二行目のときは追加しない, そのほかは追加する (3)ヘッダー条件
        if reader_obj.line_num == 1 or reader_obj.line_num == 2:
            continue #対象行をスキップする
        csv_rows.append(row)
    csv_file_obj.close()
    
    #CSVファイルを指定フォルダ内に書き出す
    csv_file_obj = open(os.path.join(headerRemoved_path, csv_filename),"w",newline="")
    csv_writer = csv.writer(csv_file_obj)
    
    for row in csv_rows:
        csv_writer.writerow(row)
    csv_file_obj.close() 
```
# やってること
- 一行目と二行目をスキップしてすべての行をcsv_rows[]に保存する(必要に応じて変える)
- カレントディレクトリ内に新しく作るheaderRemoveフォルダに新しくCSVファイルを作成し書き出す
- これらを対象フォルダにある全てのCSVで行う。

# 考察
- はじめdataframでやろうとしたが、カラム数が違うものはうまく読み込むことができなかったので、一行ずつリストを読み込み、リストからdataframe型に変換した。
【Rails】simple_formatで簡単にテキストの改行を実装（+CSSの適用、htmlエスケープも）


##simple_formatの使い方
「railsでtext_areaの改行をviewへ反映させたい！」「改行して打ち込んだのになんか長い一文になっちゃう！」なんてことありますよね！
テキストの改行をviewへ反映する際はヘルパーメソッドのsimple_formatが有効です。

使い方は至って簡単。
`simple_format(任意のテキスト)`
これだけで改行をviewへ反映させることが出来ます。

```:例
text = '…ああああ！！

あああ……'

<%= simple_format(text) %>
```

```:出力

…ああああ！！

あああ……

```

simple_formatなだけに非常にシンプルですね。

##なんか<>で囲ったら出力されないんだけど…
そうなんですよ。困りましたね。

通常、railsではデフォルトでテキストがhtmlエスケープされています。
つまり

```:例
text = '<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>'
<%= text %>
```

```:出力
<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>
```
こうやってちゃんとhtmlタグをエスケープして出力してくれています。
これ、truncateメソッドとかも同じね！

でもでも、実はこの`simple_format`メソッドは
表示させたい文字列を`<p>`で囲ったり、改行は`</br>`で置き換えたりすることで出力してくれています。
つまりそのままだとhtmlエスケープしてくれないんです。

なので以下のように書いてしまうと…

```:例
text1 = '<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>'
text2 = '<急募！>
         うちの犬の躾方法！'

<%= simple_format(text1) %>
<%= simple_format(text2) %>
```

```:出力
すごくわるいホームページ
うちの犬の躾方法！

# 悪いホームページへの直リンが貼られてしまう…
# <急募!>がhtmlタグだと認識されてしまう…
```

<急募!>が消えたどころか、すごく悪いホームページへのリンクも貼られてしまいます。

##じゃあどうすんの！
textをhメソッドでhtmlエスケープしましょう！
`h(text)`でテキストをhtmlエスケープできます。
htmlエスケープされたテキストをsimple_formatすれば解決です。

```:例
text1 = '<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>'
text2 = '<急募！>
         うちの犬の躾方法！'

<%= simple_format(h(text1)) %>

<%= simple_format(h(text2)) %>
```

```:出力
<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>

<急募！>
うちの犬の躾方法！
```

これで一件落着です。

##classとかオプションも使えるの？
`simple_format(h(text), class: 'hogehoge', style: 'color: red;')`

こんな感じでclassやstyleのオプションも設定できます。

##参考
https://railsdoc.com/view
https://qiita.com/mojihige/items/c01682774e8ef29b361f
（こっちのほうが詳しいとか言わない）
MySQLで特定のカラム名を持つテーブルを検索

今回はメールアドレスがありそうなカラムを調べたかったので、likeで検索しました。
column_nameのところに検索したいカラムの名前、table_schemaはDB名です。

```
SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%mail%' AND table_schema = 'hoge';
```
Amazon AWS CloudWatch Logs Insights で 指定したキーワードにヒットしたログを1分単位でグループ化して抽出する

自分用

```
fields @timestamp, @message
| filter Records.0.cf.request.body.data = "★キーワード★"
| stats count(*) as polling_count by datefloor(@timestamp, 1m) as ts
| sort ts asc
```
[Ruby]ワンライナーへのリファクタリング

# 対象読者
プログラミング初学者

# リファクタリングとは
外部から見た時の挙動は変えずに、プログラムの内部構造を整理すること
構造の階層化やプログラム内の要素につける名前を簡潔なものに書き換えるなどがある

## リファクタリングのメリット
1. コードの煩雑さ（性能劣化）が低減するため、トラブルを起りにくくなる
2. コードを理解しやすくなり、引き継ぎ時の手間が減る
3. 修正、追加をより早く、正確に行えるため、トラブル時の対応が速くなる

## リファクタリングのデメリット
チーム開発の場合、メンバーが同じ修正方法の認識を持っていないと、各々が考える方法での修正となり、結局ソースコードを全体でみるとバラバラのままになる

# 本題：ワンライナーへのリファクタリング
以下のコードに関して、リファクタリングを行っていきます。

```ruby
array = [1, 2, 3, 4, 5].map do |el| 
  if el.odd?
    el 
  end
end.compact!
```

## 前提知識
■ mapメソッド

```ruby

オブジェクト.map { |変数|
  # 実行したい処理
}
```
配列やハッシュオブジェクトの要素がひとつずつ順に配列内から取り出され、変数に要素が代入され、指定した変数名をブロック内で使用することができる。また、ブロック引数の値を新たな配列（= 既存の配列の書き換え（mutate）をしない）にして返す。

■ ブロック
do ～ end で囲まれた引数

■ odd?メソッド
奇数かどうかをtrue or falseで判定するメソッド
偶数の場合は、even?メソッドがある

```ruby
2.odd?    # => false
3.odd?     # => true

2.even?    # => true
3.even?     # => false
```


■ compact!メソッド
自身から破壊的に nil を取り除き、変更が行われた場合は self を、そうでなければ nil を返す
また、compact メソッドは自身から nil を取り除いた配列を生成して返す

```ruby
## arrayがnilを含んでいる時
array = [1,2,3,4,5,nil]

# compact
array.compact
=> [1, 2, 3, 4, 5]

# compact!
array.compact!
=> [1, 2, 3, 4, 5]


## arrayにnilがない時
array = [1,2,3,4,5]

# compact
array.compact
=> [1, 2, 3, 4, 5]

# compact!
array.compact!
=> nil

```

## 以上を踏まえたリファクタリング結果

```ruby
#1
array = [1, 2, 3, 4, 5].map { |el| el if el.odd? }.compact!

#2
array = (1..5).to_a.delete_if { |el| el.even? }

#3
array = (1..5).to_a.delete_if(&:even?)

#4
array = [1, 2, 3, 4, 5].select{ |el| el.odd?}
```

###上記以外のメソッド
■ delete_ifメソッド
要素を順番にブロックに渡して評価し、その結果が真になった要素をすべて削除する 
delete_if は常に self を返す

```ruby
array = [0, 1, 2, 3, 4, 5]
array.delete_if{|x| x % 2 == 0}
p array #=> [1, 3, 5]
```

■ to_aメソッド
ハッシュ、範囲オブジェクトなどを配列に変換するメソッド

```ruby
(1, 2, 3, 4, 5).to_a # => [1, 2, 3, 4, 5]
```
mapメソッドを使用した場合は自動で配列を作成してくれていたので、to_aメソッドは不要でした

"a"はarray（配列）なので、"to_a"で"配列に（変換する）"メソッドですね

■ 範囲演算子

```ruby
p (1..5).to_a  # => [1, 2, 3, 4, 5]
p (1...5).to_a # => [1, 2, 3, 4]
```

■ array.method(&:method)
 
```ruby
# array.method(&:メソッド名)の記法
['a','b'].map(&:upcase) #=> ["A", "B"]
```

■ selectメソッド
各要素に対してブロックを評価した値が真であった要素を全て含む配列を返す
真になる要素がひとつもなかった場合は空の配列を返す
ブロック({})を省略した場合は、各要素に対しブロックを評価し真になった値の配列を返すような Enumerator を返す

```ruby
[1,2,3,4,5].select                      # => #<Enumerator: [1, 2, 3, 4, 5]:select>
[1,2,3,4,5].select { |num| num.even? }  # => [2, 4]
```

#今回参考にさせていただいたサイト
[Ruby 2.7.0 リファレンスマニュアル](https://docs.ruby-lang.org/ja/latest/doc/index.html).
IQ Botのカスタムロジック：固定値の代入

IQ Botのカスタムロジックで、[置換処理](https://qiita.com/IQBotter/items/b1e7a75439fede2171e6)や[数値の取り出し](https://qiita.com/IQBotter/items/b380ab96e5bf8b0b1e57)ほどの使用頻度はないものの、
意外とパワフルに使えるのが「固定値の代入」です。

#固定値の代入

固定値の代入に関しては、処理自体はとても簡単なのでほぼ解説不要と思います。

```python:固定値の代入（フィールド項目）
field_value = "代入したい固定値"
```

「こんな処理をいつ使うんですか？」という疑問の方が多いと思いますので、それを書いていきます。

#使い道その１：分類されたグループを出力する

IQ Botには帳票の自動分類の機能がデフォルトでついていて、同じインスタンスの帳票をフォーマットごとに、AIが分類してくれます。

こんなかんじ↓　
![グループ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/9c17cb8a-ffab-1ba8-dcf8-4630e4b943f7.jpeg)

帳票の中身が見えないのでイメージわかないかもしれませんが、Group1とGroup2にはそれぞれ、
「フォーマットは違うけど取り出したい項目は同じ」という帳票がグループ分けされて入っています。

イメージでいうと、Group1はA社の請求書で、Group2はB社の請求書というかんじ。

ふたつとも請求書なので取り出したい項目は同じだけど、フォーマットが違うので別グループになっています。

処理が完了すると、今度はグループに関係なく、インスタンスごとにひとつのフォルダにCSVが出力されます。

つまり処理が終わってしまうと、どのグループに分類されて処理されたかがわからなくなります。

別にそれはそれでいいじゃん、という人は特に問題ないのですが、「通ってきたグループをぜひ知りたい！」みたいな場合は、
項目設定のときに「処理グループ」のような項目を作っておいて、そのグループに対して、固定値代入でグループの名称を入れます。

Group1の「処理グループ」には`field_value = "Group1"`
Group1の「処理グループ」には`field_value = "Group2"`

という要領で、ロジックを埋め込んでいくイメージですね。

#使い道その２：分類を根拠に一意に決まる項目の設定

使い方その１と本質的には同じことかもしれませんが、実務で使うのは主にこちらだと思います。

先ほどの例と同じく、Group1はA社の請求書、Group2はB社の請求書だと考えます。

このケースで、読み取り項目の中に「請求元社名」「請求元住所」「送金先口座番号」のような項目があったとします。

真っ当にいけば、これらの項目はすべてOCRの読み取り結果をベースに出力していくわけですが、
OCRはどうしても、100％の精度にはなりません。

Group1に分類されたということは、「請求元社名」はA社だとわかりきっているのに、
OCRの結果を使ったがゆえに、ノイズが混入して「\A社」みたいになったり、
印字のちょっとしたカスレで「H社」になったりということがありえます。

また、社名の欄などは印影との重なりにより、OCRで読みづらいというケースもあります。

そうした項目に関しては、いちいちOCRの結果を使わずに、カスタムロジックで固定値を入れてしまうというのも手だったりします。


##注意点

使い方その２を採用する場合は、**IQ Botの自動分類を固定値代入の根拠にしていいか**を事前に十分検証する必要があります。

つまり、A社とすごくよく似たフォーマットで請求書を出してくるX社という会社があって、
その会社の請求書がうっかりGroup1に分類されたりしないか、ということですね。


#まとめ

- 固定値の代入を使って、以下のことができるよ
    - その１：処理されたグループを出力する
    - その２：分類を根拠に一意に決まる項目には固定値を入れてしまう
- その２の使い方をする場合は、分類を固定値代入の根拠にしていいかどうかを事前にしっかり検証してね
GitHub Actions(+Heroku)を使用してLaravelのCI/CD環境を作成する

# 前提条件

- GitHubにLaravelの環境が設定済み
- HerokuにLaravelアプリケーションが構築済み

## GitHub Actionsの設定を行う

Laravel用のテンプレートがあるのでこれを選んでカスタマイズする。

[![Image from Gyazo](https://i.gyazo.com/82e26e455da3002f7841a57db05e0c73.png)](https://gyazo.com/82e26e455da3002f7841a57db05e0c73)

```example.yml
name: example

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  laravel-tests:

    runs-on: ubuntu-latest
    
    services:
      postgres:
        image: postgres:10.8
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: test
        ports:
        - 5432:5432
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
    
    steps:
    - uses: actions/checkout@v2
    - name: Copy .env
      run: cp .env.ci .env
    - name: Install Dependencies
      run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist
    - name: Generate key
      run: php artisan key:generate
    - name: Directory Permissions
      run: chmod -R 777 storage bootstrap/cache
    - name: Execute Migration
      run: php artisan migrate --force
    - name: Execute Seed
      run: php artisan db:seed --force
    - name: Execute tests (Unit and Feature tests) via PHPUnit
      run: vendor/bin/phpunit
```

- PostgreSQLのバージョンとかは任意

## `.env.ci`の作成

```.env.ci
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=test
DB_USERNAME=postgres
DB_PASSWORD=postgres
```

## Heroku側の設定

[![Image from Gyazo](https://i.gyazo.com/2e8ebf4633540f0d4ccb5bb53949ca3a.png)](https://gyazo.com/2e8ebf4633540f0d4ccb5bb53949ca3a)

- Heroku側の管理画面から`App connected to GitHub`でボタンをぽちぽちして、GitHubとの連携をONにする。


[![Image from Gyazo](https://i.gyazo.com/b5e8e440ba0429bc38987d9e599f866c.png)](https://gyazo.com/b5e8e440ba0429bc38987d9e599f866c)

- Heroku側の管理画面から`Automatic deploys`でボタンをぽちぽちして、GitHubとの連携をONにする。

## Procfileの編集

-  `Procfile`を編集してマイグレーションとかSeederを自動化する

```Procfile
release: php artisan migrate --force && php artisan db:seed --force
web: vendor/bin/heroku-php-apache2 public/
```

後はPull Request時にGitHubActionsでTestの結果を待つ。

[![Image from Gyazo](https://i.gyazo.com/7906fb1372fdd7948de0c317c9ecf31f.png)](https://gyazo.com/7906fb1372fdd7948de0c317c9ecf31f)

続いてMergeしてHerokuのデプロイ状況が確認できればOK。

[![Image from Gyazo](https://i.gyazo.com/6264391f6eab23570c3549fb086d7bd9.png)](https://gyazo.com/6264391f6eab23570c3549fb086d7bd9)

[![Image from Gyazo](https://i.gyazo.com/ea976c5fda2b30c31a5b99ab6d7a295c.png)](https://gyazo.com/ea976c5fda2b30c31a5b99ab6d7a295c)

## 参考

[Using Github Actions to setup CI/CD with Laravel (and MySQL)](https://kirschbaumdevelopment.com/news-articles/using-github-actions-to-setup-ci-cd-with-laravel-and-mysql)
How to backup and restore PostgreSQL using Docker

# How to backup and restore PostgreSQL using Docker

## Let's backup data

When managing Sentry.io on premise,
I encountered an issue.

**I need to backup data.**

## Sentry v10 is ready

Sentry v10 has been released (https://blog.sentry.io/2020/01/07/self-hosted-sentry-10-is-ready-to-serve-get-it-while-its-hot),
and I was trying to upgrade from v9.1.2

It should be simply done by below command.

```sh:upgrade
git pull origin master
./install.sh
```

But I should care about failure cases
so that I started investigating how to rollback.

## Handle PostgreSQL version's diff

Sentry v9.1.2 uses PostgreSQL v9.5,
and v10 is based one psql v9.6

First I tried to checkout to tag9.1.2 after version up.
and downgrade on perpose.

But one error was shown.
I'm not sure about the cause,
but only thing I can say is that
backup data before up grade and restore after rollback should be good idea.

So I started investigation how to backup and restore data of PostgreSQL with Docker.

## Here it is

Backup current all data.

```sh:Backup
$ docker exec -t -u postgres onpremise_postgres_1 pg_dumpall -c > dump_`date +%d-%m-%Y"_"%H_%M_%S`.sql
```

Let's prune volume and then reinstall.

```sh:reinstall
$ docker volume prune
$ ./install.sh
```

Let's initialize db (drop all tables) before restoring data.

```sh:initializedb
$ docker exec -it onpremise_postgres_1 bash #into psql container
$ su postgres #default user: postgres
$ psql -U postgres #login to psql
  drop schema public cascade;
  create schema public;
  grant usage on schema public to public;
  grant create on schema public to public;
ctrl+D
ctrl+D
```

Finally restore data.

```sh:Restore
$ cat <backup file>.sql | docker exec -i onpremise_postgres_1 psql -U postgres
```
基本・応用情報試験のための整列アルゴリズムのメモ①

#Pythonでバブルソート

##はじめに
ここでは、基本・応用情報処理技術者試験を受ける際に学ぶ基本的な整列アルゴリズムについて、実際に自分で手を動かしながら理解した過程を自身への整理も兼ねてまとめています。
私同様にpythonで勉強をされている初学者の方の参考になれば幸いです。また私自身も初学者ゆえ、書き方、アルゴリズム等至らない点があると思いますので、細かいことでもご指摘頂ければ幸いです。
宜しくお願い致します。

##問題
リスト　[11, 42, 5, 63, 37, 54, 4]
について、３つの基本整列法を用いて昇順で整列させなさい（自作問題）
・バブルソート
・単純選択法
・単純挿入法

本スライドでは、バブルソートを扱う。

##バブルソート
隣り合う全ての要素を比べ、大小関係が違う逆の場合、交換する。この比較・交換が必要なくなるまで繰り返す。

####プログラムの手順①
先頭の要素から最後の要素まで、配列の要素が逆のとき、入れ替える。

```python:bubble.1.py
item = [11,42,5,63,37,54,4]

#整列前の配列
print(item)

for i in range(len(item)-1):
    if (item[i] > item[i+1]):
        a = item[i]
        b = item[i+1]
        item[i] = b
        item[i+1] = a

#整列後の配列
print(item)
```

実行結果

```
#整列前の配列
[11, 42, 5, 63, 37, 54, 4]

#整列後の配列
[11, 5, 42, 37, 54, 4, 63]
```

※注意点
4行目「for i in range(len(item)<font color="Salmon">-1</font>):」
大小比較をする際、自身と一つ後の要素とを比べているため、ループを1つ減らす。



この実行結果をみて分かること、


＞＞＞配列の中の最大値が最後の要素になった。
＞＞＞最後の要素「63」はもう整列しなくてよい。
＞＞＞残りの6つの要素で同じことを行い、繰り返せばよい！！

####プログラムの手順②
すでに整列された要素以外で①を行い、繰り返す。

```python:bubble.2.py
item = [11,42,5,63,37,54,4]

#整列前の配列
print(item)

for i in range(len(item)-1):
    for j in range(len(item)-1-i):
        if (item[j] > item[j+1]):
            a = item[j]
            b = item[j+1]
            item[j] = b
            item[j+1] = a

#整列後の配列
print(item)
```

実行結果

```
#整列前の配列
[11, 42, 5, 63, 37, 54, 4]
#整列後の配列
[4, 5, 11, 37, 42, 54, 63]
```

以上がバブルソートのアルゴリズムプログラムである。
また、「どのように整列が推移しているのか」「何回整列を繰り返しているのか」などについては、以下の「bubble_sort.py」で確かめることができる。

###確認用プログラム

```python:bubble_sort.py
item = [11,42,5,63,37,54,4]

count_compare = 0
count_change  = 0
#整列前の配列
print(item)
print("")
for i in range(len(item)-1):
    for j in range(len(item)-1-i):
        count_compare += 1
        if (item[j] > item[j+1]):
            a = item[j]
            b = item[j+1]
            item[j] = b
            item[j+1] = a
            count_change += 1
        print(format(count_compare, "02d"), "回目", item)
#整列後の配列
print("")
print(count_compare, "回比較し、",count_change, "回入れ替えました。")
```

実行結果

```
[11, 42, 5, 63, 37, 54, 4]

01 回目 [11, 42, 5, 63, 37, 54, 4]
02 回目 [11, 5, 42, 63, 37, 54, 4]
03 回目 [11, 5, 42, 63, 37, 54, 4]
04 回目 [11, 5, 42, 37, 63, 54, 4]
05 回目 [11, 5, 42, 37, 54, 63, 4]
06 回目 [11, 5, 42, 37, 54, 4, 63]
07 回目 [5, 11, 42, 37, 54, 4, 63]
08 回目 [5, 11, 42, 37, 54, 4, 63]
09 回目 [5, 11, 37, 42, 54, 4, 63]
10 回目 [5, 11, 37, 42, 54, 4, 63]
11 回目 [5, 11, 37, 42, 4, 54, 63]
12 回目 [5, 11, 37, 42, 4, 54, 63]
13 回目 [5, 11, 37, 42, 4, 54, 63]
14 回目 [5, 11, 37, 42, 4, 54, 63]
15 回目 [5, 11, 37, 4, 42, 54, 63]
16 回目 [5, 11, 37, 4, 42, 54, 63]
17 回目 [5, 11, 37, 4, 42, 54, 63]
18 回目 [5, 11, 4, 37, 42, 54, 63]
19 回目 [5, 11, 4, 37, 42, 54, 63]
20 回目 [5, 4, 11, 37, 42, 54, 63]
21 回目 [4, 5, 11, 37, 42, 54, 63]

21 回比較し、 11 回入れ替えました。
```


一度自分で手を動かしてみると、どう動いているのかよく見えます。

##ポイント
基本情報、応用情報で頻出な比較回数に関しては、アルゴリズムをみれば一目瞭然であり、等差数列の和の公式で求めることができる。
S ＝ 1/2*n*(n-1)

##まとめ
以上です。いかがだったでしょうか？間違いや改善点など多々あると思いますので、ご指摘よろしくお願いいたします。
また、Qiita初心者でもあるので、見やすいスライドのつくり方などあれば教えてください。

##関連資料
[単純選択法](https://qiita.com/cutni-san/items/5eaa3bf49b4361714d20/)
[単純挿入法](https://qiita.com/cutni-san/items/956f9ef53c0089445ca9/)
java.util.Stack の pop() と peek() の違い

# java.util.Stack の pop() と peek() 動作確認メモ

挙動確認に関するブログ等が無かったため、メモ。

API 上で確認出来ることを以下に。

## public E pop()
> スタックの先頭のオブジェクトを削除し、そのオブジェクトを関数の値として返します
> 戻り値:スタックの先頭にあるオブジェクト(Vectorオブジェクトの最後の項目)。
> 例外:EmptyStackException - このスタックが空の場合
> (https://docs.oracle.com/javase/jp/8/docs/api/java/util/Stack.html#pop--)

## public E peek()
> スタックの先頭にあるオブジェクトを取り出します。このときオブジェクトはスタックから削除されません。
> 戻り値:スタックの先頭にあるオブジェクト(Vectorオブジェクトの最後の項目)。
> 例外:EmptyStackException - このスタックが空の場合
> (https://docs.oracle.com/javase/jp/8/docs/api/java/util/Stack.html#peek--)

```peekの場合.java
public static void main(String[] args) {
  try {
    Stack<String> stack = new Stack();
    stack.push("Good Morning!");
    stack.push("Hello!");
    stack.peek();
    stack.stream().forEach(System.out::println);
    // Good Morning!
    // Hello!
  } catch (EmptyStackException e) {
    System.out.println("stack が空です");
  }
}
```
```popの場合.java
public static void main(String[] args) {
  try {
    Stack<String> stack = new Stack();
    stack.push("Good Morning!");
    stack.push("Hello!");
    stack.pop();
    stack.stream().forEach(System.out::println);
    // Good Morning!
  } catch (EmptyStackException e) {
    System.out.println("stack が空です");
  }
}
```

pop の場合は stack から取り出され、 peek は stack から取り出されません。
peek の API を見ると戻り値を返しますので、 値を検証しながら pop することが可能です。

```検証しながらpopする.java
public static void main(String[] args) {
  try {
    Stack<String> stack = new Stack();
    stack.push("Good Morning!");
    stack.push("Hello!");
    if (stack.peek().equals("Hello!")) {
      stack.pop();
    }
    System.out.println(stack.peek());
    // Good Morning!
  } catch (EmptyStackException e) {
    System.out.println("stack が空です");
  }
}
```
How to print struct variables data?

```
package main
 
import "fmt"
 
type Employee struct {
    Id int64
    Name string
}
 
func main() {
    emp := Employee{Id:1200, Name: "hoge fuge"}
    fmt.Printf("%+v\n",emp) // Print with Variable Name
    fmt.Printf("%v\n",emp)  // Without Variable Name
    fmt.Printf("%d\n",emp.Id)
    fmt.Printf("%s\n",emp.Name)
}
```
PowerAutomate のカスタム コネクタで LINE WORKS の監査ログを自動保存する

LINE WORKS の監査ログは管理画面から 180 日分を参照できます。定期的に保存することで 180 日を越えて監査ログを保存することができます。

監査 API を Microsoft PowerAutomate で実行するカスタム コネクタを作りました。これを利用して自動で定期的に監査ログを保存する方法を説明します。

## PowerAutomate のカスタム コネクタ作成

LINE WORKS 用のコネクタは PowerAutomate にないので、カスタム コネクタとして登録します。手順は以下のとおりです。

https://github.com/iwaohig/LINEWORKSAuditlogConnector の LINEWORKSAuditlogConnector.json をダウンロードする。

Microsoft PowerAutomate の [カスタム コネクタ] にアクセスし、[+ カスタム コネクタの新規作成] をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/b60a0fef-72d7-752e-5222-97376a7382c4.png)

[OpenAPI ファイルをインポートします] をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/39aa38a6-c8d5-9b52-8d85-655c6a514afa.png)
 
任意のコネクタ名を入力し、ダウンロードしたファイルを選択。[続行]をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/e9dd6fa8-9df3-7e73-a11c-45cbeb0200ee.png)

必要に応じて、任意のコネクタ アイコンと背景色を指定。[コネクタの作成] をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/027a8f25-81c2-77f2-ed26-9dad5aed07b3.png)

カスタム コネクタとして登録されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/b2cfafbd-a67f-52c4-bec8-3cbce5218d9d.png)

## PowerAutomate のフロー作成
定期的にカスタム コネクタを利用して監査ログを取得し、OneDrive に保存するフローを作成してみます。

定期的な取得のため、スケジュールをトリガーとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/04f98e0b-fa48-3225-3822-ab3672984b9f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/85ada15c-5ede-d5a1-1da7-7f4d46d8f26b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/50559ba8-43b9-c210-22c6-b41e9c2f1235.png)

作成したカスタム コネクタを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/27ec3480-b9b3-ca12-4b7b-224e9cf94f1c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/11d79fa9-75d3-ec37-b95c-fd872c39b05a.png)

接続名と API キーを入力する。
APIキーは、"Bearer [Server Token]" を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/ceda1a3d-730d-bf3c-9766-39047a4acbd8.png)

各パラメータを指定します。
_statDate ログの開始日
_endDate ログの終了日
_tenandid テナント ID
_domainid ドメイン ID
consumerKey サーバー API コンシューマー キー

ログの開始/終了日は前日の値が入力されるよう指定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/e4e51aad-80e5-2de2-ddaa-2a07e861c946.png)

OneDrive for Business にファイルで保存するようアクションを追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/a7e75168-2f2e-f626-9965-138bcef6811b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/b309e171-f65b-e7a4-015e-d46eb9d24f3b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/9debe9c9-23c6-cef0-e7bf-a4d0a8675c54.png)

## 動作確認
フローの作成画面からテストを行い、ログ ファイルがダウンロードされることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/b5e2ae28-5236-7385-6665-993944c3995b.png)
Vue.jsのinput or Vuetifyのtext-fieldで数値を入力したのにv-modelのバインド先では文字列になってる問題

# 結論
- `v-model.number="numberData"`で解決
- Vuetifyは関係無い
- `type="number"`しても数値にはならない
- Vue.jsの修飾子に解決策がある

## 解決: Numberに自動変換する修飾子`.number`

ご覧の通りVuetifyは関係ありません。

下記のリンクで確認ください
[Vue.js/フォーム入力バインディング/修飾子/Number](https://jp.vuejs.org/v2/guide/forms.html#number)

```vue
<template>
  <!-- 色々と省略 -->
  <!-- vue.jsならこう -->
  <div>
    <input v-model.number="numberData"/>
  <div>
  <!-- Vuetifyのtext fieldならこう -->
  <div>
    <v-text-field v-model.number="numberData"/>
  <div>
</template>
```

## 余談: 数字 + 文字列を入力してみた
### まずは数字だけ入力
ちゃんとNumberになってていいですね！
![スクリーンショット 2020-04-06 16.27.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206542/b3b4b995-5e54-7812-d6cc-e55537760e18.png)
![スクリーンショット 2020-04-06 16.27.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206542/f8c68041-cdc2-b1ae-ac2c-35c016194e65.png)

### 文字列を含んで入力
ちょっと嫌がらせで色んな文字列を入力してみました。
うまく数字だけバインドされているみたいです！素晴らしい！！
![スクリーンショット 2020-04-06 16.28.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206542/eb99ec8e-ae7f-efe9-77d4-c11ac9b4b28d.png)
![スクリーンショット 2020-04-06 16.29.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206542/755bdfb6-261d-e7e8-ed1b-bac995ada67f.png)

### その他のテスト

#### 間に文字列
"100 hoge 100" → Number 100
のように微妙な位置に数字を入れてもバインドされた値は変わりませんでした。

#### ↑の先頭100を200に書き換え
"100 hoge 100"を"200 hoge 100"にしようとした所
バインドの結果がNumber 2 に一度切り替わって無事200と入力することができました。

ソースを追いかけてはいませんが、**おそらく数字に変換できるものが入力された時だけバインドしている**のだと思います。


## 余談: 空白を取り除く修飾子`.trim`

https://jp.vuejs.org/v2/guide/forms.html#trim
Vue.jsには入力から自動的に空白を取り除くトリミング機能まであるとは！
最近の開発はVue.js様様ですね！！

```vue
<template>
  <!-- 色々と省略 -->
  <div>
    <input v-model.trim="text"/>
  <div>
</template>
```
ffmpegで wavをmp3に変換し音量をUP

* input.wav を input.mp3 に変換

```sh
ffmpeg \
 -i "input.wav" \
 -vn -ac 2 -ar 44100 -ab 256k -acodec libmp3lame \
 -f mp3 \
 "input.mp3"
```

* 音量UP

```sh
ffmpeg -i input.mp3 -af volume=10dB output.mp3
```
Vim: 複数ウィンドウの上下左右交換

vimで複数ウィンドウ開いている時の上下／左右交換/移動についてのメモです．

### ◆やり方
**C-W + {J,K,H,L}**  → 今いるウィンドウを**「jkhl方向」**のウィンドウと交換．
　※JKHLは大文字注意．

1. 横分割(上下に分かれてる)の場合．
    -  いま上側にいる → **C-WJ**  → 下側と交換 → 下側にいく
    -  いま下側にいる → **C-WK** → 上側と交換 → 上側にいく
2. 縦分割(左右に分かれてる)の場合．
    -  いま左側にいる → **C-WL** → 右側と交換 → 右側にいく
    -  いま右側にいる → **C-WH** → 左側と交換 → 左側にいく

### ◆同じコマンドで縦横分割変換も
*  縦分割で左にいる時 → **C-WK** → 横分割して上に．**C-WJ** → 横分割して下に  
*  横分割で上にいる時 → **C-WH** → 縦分割して左に．**C-WL** → 縦分割して右に

### ◆分割ウィンドウの「列」または「行」で回転するには、**C-wC-r**

2画面だけだったら，こっちの方が単純です．
ただし行き先のウインドウがさらに分割されていると断られます．

### ◆実際にやってみた．
1. とりあえず，横分割からスタート．※カーソルがあったりなかったりはご愛嬌♪
![vim分割交換01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441159/1e5a44b5-a256-2478-4ee1-e4d8417b34c3.png)

2. 横分割: 上側にいる → **C-WJ**
![vim分割交換02-WJ後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441159/0318646e-b403-831a-d3c3-9002bd1bf50a.png)

3. ↑からの，**C-WK** → 上に戻る
![vim分割交換03-WK後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441159/4d2a9bc1-92c9-ef20-f9c4-8a300987bf51.png)

4. ↑からの，**C-WH** → 縦分割の左側に
![vim分割交換04-WH後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441159/0f647d8b-2a35-d972-d05e-64f63928dedc.png)

5. ↑からの，**C-WL** → 縦分割の右側に
![vim分割交換05-WL後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441159/1feb4caf-06b9-4fc8-ec9d-a95b04fcc456.png)

6. ↑からの，も一度**C-WK** → 横分割の上側に戻る
![vim分割交換06-WK後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441159/12bb6c3b-7c32-dedf-be49-31b77d919daa.png)


以上です．

※参照：[vimでウィンドウを反転する方法は？](https://ja.coder.work/so/vim/28809)
　　↑文がわかりにくい．(^^;)
reactでボタンクリックでコピーさせる | JavaScript

```js
  const copyText = (): void => {
    navigator.clipboard.writeText(hoge);
  };
```

```js
          <Button
            onClick={(): void => copyText()}
            value='コピー'
          />
```

## 備考

`navigator.clipboard.writeText(hoge); ` のしたでAlertとかするとコピーできなくなる
さくらサーバープラン間移動

さくらサーバーのプラン間を移動したい。



Rlogin を使って　サーバーに ssl でログイン

まずは圧縮
tar -zcvf chuukodomain.tar.gz chuukodomain

圧縮ファイルのできあがり chuukodomain

Rlogin の ファイル転送機能を使って一度ダウンロードし、
移行したいサーバーにファイルをアップロード。

解凍
tar -zxvf chuukodomain.tar.gz


・SSLの移動

数時間、SSLが切れるのは覚悟しとく。

まずは証明書と秘密鍵をダウンロードしておく。
そしてSSLの全削除。

これで現在設定されているドメインを削除することが可能。

・移行後のサーバーにて

ドメインを追加し、SSLの設定
これで、1時間以内には有効なり、利用できるようになる。