OmniAICreator/Qiita-1.07M huggingface dataset:
【初心者でもわかる】CSS1行で書ける、文字を目立たせるための7つの方法

# どうも7noteです。たった1行でできる。目立たせたいテキストをCSSで装飾する方法

読みにくい文章、読みやすい文章。それらにはもちろん言葉的な意味で読みやすいものや読みにくいものがあると思います。ですが、どんなに読みやすい文章でもwebサイトでは装飾次第で読みにくいものになってしまうことも。

適切な表現をあわせてあげることで、webサイトの文章はグッと読みやすいものになります。
テキストを目立たせる7つの方法とを紹介していきたいと思います。

また1行でなく組み合わせ次第で様々な見せ方が可能になります！

## テキストを目立たせるための7つのCSS

### ▼下線を引く

```style.css
p span {
  text-decoration: underline;
}
```


![text01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/ac81d0e9-1360-4c54-cf27-5e17b009388e.png)


---

### ▼太文字にする

```style.css
p span {
  font-weight: bold;
}
```


![text02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/cf5e92cf-b22d-7ecc-61f8-f9c36e07de1f.png)


---

### ▼文字色を変える

```style.css
p span {
  color: #f00;
}
```


![text03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/1d0f5866-095b-d7d4-42c2-a5dbe38538b0.png)


---

### ▼文字を大きくする

```style.css
p span {
  font-size: 1.5em;
}
```


![text04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/82cea8de-a6cc-d572-9b18-6ca1d2e358b7.png)



---

### ▼マーカーを引く

```style.css
p span {
  background:linear-gradient(transparent 60%, #ff6 60%);
}
```


![text05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/baf8984b-d579-6f33-b5be-00968f3bdfc5.png)


---

### ▼打ち消し線を引く

```style.css
p span {
  text-decoration: line-through;
}
```


![text06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/563b3631-5cef-a9f3-d9e9-14ad6228b30e.png)

---


### ▼余白をとる

```style.css
.yohaku {
   margin: 50px 0;
}
```


![text07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/2c861d9f-1b4f-a0e9-1a99-1576528ce3a3.png)

## まとめ

7つの方法を紹介してきましたが、これら単体ではデザイン的には少し弱いと思います。
ですが**これらを組み合わせることでしっかり目立たせるようなテキストを作ることができます。**

**例１）「マーカーを引く」 + 「太文字にする」**

```style.css
p span {
  font-weight: bold;
  background:linear-gradient(transparent 60%, #ff6 60%);
}
```

![sample01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/f74ad8fd-add5-9458-f253-5ce2e1007fe0.png)

---

**例2）「打ち消し線を引く」 + 「文字色を変える」 + 「文字を大きくする」**

![sample02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/e5e1d87a-6c8d-e876-303e-bc807b20e1b4.png)

```style.css
p span.a {
  text-decoration: line-through;
}
p span.b {
  color: #f00;
  font-size: 1.5em;
}
```


いろいろな方法があるので、見せたいものはなにか、逆にあまり目立たせたくないものはなにかをしっかり切り分けてCSSを当ててあげることで、見やすいサイトに一歩近づくのかなと思います。

#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
Java Interceptorの有効化

# JavaEEのインターセプターを有効にする方法について
インターセプターが有効になっていないなーと思ったら、Priorityアノテーションを忘れていました。
調べるとbeans.xmlで設定する方法もあるようで、違いはなんだろうと思ったのですけど、特にないようですね。
beans.xmlで定義するとソースコードを修正せずに有効にできたり無効にしたりできる程度ですね。

## 方法は２つあります
1. interceptorに@Priorityアノテーションをつける 
2. beans.xmlにinterceptorを定義する

### 1. Interceptorに@Priorityアノテーションをつけるサンプル

``` java:TraceLogInterceptor.java
package sample;

@InterceptorBinding
@Target({Element.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TraceLogInterceptor {
}
```

``` java:TraceLogImpl.java
package sample;

@Priority(Interceptor.Priority.APPLICATION)
@TraceLogInterceptor
@Interceptor
public class TraceLogImpl {
}
```


### 2. beans.xmlにInterceptorを定義するサンプル

``` xml:beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
       bean-discovery-mode="annotated">
    <interceptors>
        <class>sample.TraceLogInterceptor</class>
    </interceptors>
</beans>
学習記録

こんばんは！taroです！

本日のアウトプットはHTMLとCSSです！
プロゲートにて学習をしました！

HTML
１　<input>要素は１行のテキスト入力を受け取るための要素である。
２　<textarea>要素は複数行のテキスト入力を受け取るための要素である。


CSS
1 CSSで背景画像を指定するにはbackground-imageプロパティを使用。
  background-image: url(画像のURL);のように使います。

2 background-size: cover;を指定すると、1枚の画像で表示範囲を埋め尽くすように画像の大きさが拡大縮小する。

以上で本日のアウトプットを終わります。
ありがとうございました！
フロントエンド、バックエンド、モバイルアプリのボイラープレートを公開します。

弊社で作成中のWebアプリ、モバイルアプリ用のボイラープレートを公開します。

https://github.com/PaykeDeveloper/payke-hinagata

### 公開した経緯
作ったは良いものの、実プロジェクトで使うかは微妙です。
まだまだ完成度は低いですが、完成せずに放置する可能性も出てきました。
個人の時間も使って作ったので、少しでも役立てたいと思い公開の許可を頂きました。

### 使用している主な技術
使用している主な技術はこんな感じです。

| 環境 | 言語 | フレームワーク |
| --- | --- | --- |
| Backend | PHP | Laravel |
| Frontend | Typescript | React, Redux |
| Native | Dart | Flutter, Provider |

### 注意点
- LaravelやFlutterは初めて使ってます。
  - 未熟な部分も多々ありますので、優しく教えていただければ幸いです。
- 実プロジェクトでまだ利用してませんので、有用かは分かりません。
- ボイラープレートを良いことに雑な箇所もあります。。

### 主な特徴
- テスト、静的解析自動化 (Github Actions)
  - Backend -> PHPStan, PHP_CodeSniffer, PHPUnit
  - Frontend -> ESLint, Typescriptのビルド
  - Native -> Flutter format, Flutter test
- ステージング環境へのデプロイ自動化 (Github Actions)
  - Backend -> Heroku
  - Frontend -> Firebase Hosting
  - Native -> Firebase App Distribution
- ステージング環境は激安運用可能 (Freenom, CloudFlare)
- 多言語、タイムゾーンを考慮 (検証不十分です。特にタイムゾーン。)
- フロントエンドやモバイルとバックエンドの繋ぎ込みを極力共通化
  - API呼び出しのローディングやサーバーサイドのエラー反映も共通化

### 詳細
今後、各アプリの詳細や得られた知見を記事にできたらなと思います。

### 画面イメージ
ボイラープレートですので、あえて(?)シンプルです。

#### Webアプリ
![Apr-03-2021 16-55-33.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621435/ae4523af-94cc-000b-5a95-b849433b42a5.gif)

#### モバイルアプリ
![Apr-03-2021 17-30-40.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621435/3c47d074-b1f7-c89c-1053-9b683f3e8d56.gif)
環境変数にサーチパスを追加し、シェルスクリプトを実行する

#初めに

今回は、環境変数(PATH)を用いて、通常のコマンド(lsやcatなど)のようにシェルスクリプト名だけでコマンドを実行できるようにします。

手順は
①サーチパスに設定するディレクトリ、実行ファイルの作成
②環境変数（PATH)にサーチパスを設定
③シェルスクリプトの実行、確認
です。

#環境
■OS
CentOS 8.3.2011
■シェル　
bash

#サーチパスに設定するディレクトリ、実行ファイルの作成

まず、ディレクトリを作成します。

```:/home/shintaro
# mkdir path
# cd path/
# pwd
/home/shintaro/path
```
ディレクトリの名前はなんでも大丈夫ですが、分かりやすくしたかったので「path」という名前にしました。

次に、作成したディレクトリの配下にファイルを作成して設定を記述します。
今回は「qiita」というファイル名にします。


```:/home/shintaro/path
# vi qiita

-------------------------------------------------------------------------------------
#!/bin/bash　　・・・ここを記述　　　
echo test　　　・・・ここを記述　
-------------------------------------------------------------------------------------
```
「#!」はその後ろにあるコマンドを実行するという意味です。
echo testの部分にシェルスクリプトで実行したい処理を記載します。
「-」はコマンドラインとファイルの内容を分かりやすくしているだけなので、実際には記載しなくて大丈夫です。

また、何も設定していない場合はファイル名「qiita」を実行すると「コマンドが見つかりませんでした...」とエラーが出ます。

```
# qiita
bash: qiita: コマンドが見つかりませんでした...
```

この後は、どのディレクトリからでも「qiita」と実行すれば、「test」と返されることを目指して設定を行います。

#環境変数（PATH)にサーチパスを設定

先ほど作成したディレクトリを、環境変数に設定します。
「/etc/profile」は全ユーザーがログインした時に読み込まれるファイルです。
今回は「/etc/profile」に記述します。

「~/.bash_profile」に記述した場合でも、環境変数の設定が成功しました。
「~/.bash_profile」も、「/etc/profile」同様にログイン時に読み込まれるファイルですが、ユーザーごとに設定を行う必要があります。

本来であれば、読み込まれる順番が遅い「~/.bash_profile」に記述を行うべきですが、「~/.bash_profile」では、ユーザーごとに設定が必要で少し手間がかかります。
今回はQiita用の設定のため、「/etc/profile」に設定を行います。


ファイルの読み込み順に関しては下記サイトを参照させていただきました。(ちなみに、CentOSはRedHat系です。)
https://pasela.hatenablog.com/entry/20090209/bash

```
# vi /etc/profile
PATH=$PATH:/home/shintaro/path
```
viで先ほど作成したディレクトリのパスを環境変数に追記しました。

/etc/profileはログイン時に読み込まれるファイルのため、ファイルの記載をして直ぐには反映されません。

再度ログインするか、下記のコマンドを実行して読み込ませます。

```
# source /etc/profile
```
これで、設定が完了しました。

#確認


最後に、rootユーザーと一般ユーザーで確認します。
「/etc/profile」は全ユーザー共通でログイン時に読み込まれるため、rootユーザー、一般ユーザーのどちらともに設定が反映されているはずです。

```:rootユーザー
# qiita
test
```

```:一般ユーザー
$ qiita
test
```
先ほど「qiita」と入力した時はエラーが出ましたが、設定後は「test」と出力されています。
これで成功です。

以上になります。
ありがとうございました。
【Ruby】配列の最初の要素を削除するshiftメソッドの使い方

#プログラミング勉強日記
2021年4月3日

#shiftメソッドとは
　配列の先頭の要素を削除した要素を返すメソッド。ただし、shiftメソッドを使用すると元となる配列自体が変更されるので注意しないといけない。
　引数を指定することもでき、指定した場合にはその個数だけ取り除いてそれを配列で返す。空の配列で指定した場合は`nil`を返す。

```ruby:使い方
配列オブジェクト.shift
配列オブジェクト.shift(num)
```

#サンプルプログラム

```ruby:引数を指定しない場合
# 配列を定義
num = [0, 1, 2, 3, 4, 5]

puts "削除前：#{num}"

# 配列の最初の要素を削除する
puts "削除した要素：#{num.shift}"

puts "削除後#{num}"
```

```:実行結果
削除前：[0, 1, 2, 3, 4, 5]
削除した要素：0
削除後：[1, 2, 3, 4, 5]
```

```ruby:引数を指定する場合
# 配列を定義
num = [0, 1, 2, 3, 4, 5]

puts "削除前：#{num}"

# 配列の最初の要素を削除する
puts "削除した要素：#{num.shift(2)}"

puts "削除後#{num}"
```

```:実行結果
削除前：[0, 1, 2, 3, 4, 5]
削除した要素：[0, 1]
削除後：[2, 3, 4, 5]
```


#参考文献
[instance method Array#shift](https://docs.ruby-lang.org/ja/latest/method/Array/i/shift.html)
.NET Framework 4.5でTLS1.2対応

とあるサービスの保守対応を忘備録としてまとめ。

##### 問題
Azure Cloud Services (クラシック)にデプロイして、サーバ間通信を行っているが、
相手サーバがTLS1.2対応した事で通信が行えなくなった。
こちら側は、.NET Framework 4.5でAPIを実装しており、
デフォルトではTLS1.1，1.2は無効化されている。
##### 対処
対応として、デフォルトでTLS1.1，1.2が有効化されている
.NET Framework 4.6へのバージョンアップが検討されたが、
影響範囲の懸念から次のコードでTLS1.1，1.2を有効化する事になった。

```
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
                                     | SecurityProtocolType.Tls11
                                     | SecurityProtocolType.Tls12;
```
Ultra96V2(Debian)とUSB3.0(device)でWindows10に繋いでみる

# はじめに

Ultra96V2の@ikwzm氏の[Debianイメージ](https://qiita.com/ikwzm/items/0c6f110aa19e368af03d)で、Ultra96V2とPC(Windows10)をUSB3.0で繋いでみた際の備忘録です。

# windows10側の準備

[こちらのサイト](https://www.catalog.update.microsoft.com/Search.aspx?q=Acer%20Incorporated.%20-%20Other%20hardware%20-%20USB%20Ethernet%2FRNDIS%20Gadget) から

Acer Incorporated. - Other hardware - USB Ethernet/RNDIS Gadget
Windows 7,Windows 8,Windows 8.1 and later drivers 

を選んで

20342322_4b9970e3174b23b5cb2371af0837f939a71271ea.cab

を解凍して、出てきた「rndis.cat」を右クリックでインストール

# Ultra96V2 側の準備

rootで

```
modprobe g_ether
ifconfig usb0 169.254.10.10 up
```

でつながったようです。

Windows側は[APIPA](https://ja.wikipedia.org/wiki/APIPA) (Automatic Private IP Addressing) でそのまま繋いでいます。

時々

NOHZ: local_softirq_pending 08 

と出てるけど、とりあえず動いているっぽいです。


# 参考にさせて頂いたURL

- https://qiita.com/chromabox/items/d4368ccebb0f8822ce74
- https://qiita.com/gpsnmeajp/items/126fadd3e47cdd4a6c00

# おしらせ

2020/10/30 にて Qrunch がサービス終了したので移転してきた記事となります。
一時退避場所：https://github.com/ryuz/qrunch_blog
Ultra96V2(debian)への有線LANをUSB接続したメモ


# 接続機器
例によって@ikwzm氏の[Debianイメージ](https://qiita.com/ikwzm/items/0c6f110aa19e368af03d)での環境構築です。
接続したのは手元にあった [USB-LAN100R](https://www.planex.co.jp/products/usb-lan100r/) となります。

# ドライバインストール

realtekからドライバをダウンロード
https://www.realtek.com/ja/component/zoo/category/network-interface-controllers-10-100-1000m-gigabit-ethernet-usb-3-0-software

rootで入って

```
tar xvf r8152.53.56-2.12.0.tar
cd r8152_2.12.0/
make modules
make install
```

```
INSTALL /home/ryuji/downloads/r8152_2.12.0/r8152.ko
DEPMOD  4.19.0-xlnx-v2019.2-zynqmp-fpga
Warning: modules_install: missing 'System.map' file. Skipping depmod.
make[1]: Leaving directory '/usr/src/linux-headers-4.19.0-xlnx-v2019.2-zynqmp-fpga'
modprobe r8152
modprobe: FATAL: Module r8152 not found in directory /lib/modules/4.19.0-xlnx-v2019.2-zynqmp-fpga
make: *** [Makefile:42: install] Error 1
```

というエラーが出ましたが

```
sudo depmod -A
```

したところ通ったようです。

ところが
dmesg | grep eth

```
[    0.000000] psci: probing for conduit method from DT.
[    2.480750] usbcore: registered new interface driver cdc_ether
[   12.056114] r8152 1-1.1:1.0 eth0: v2.12.0 (2019/04/29)
[   12.061266] r8152 1-1.1:1.0 eth0: This product is covered by one or more of the following patents:
[   12.245177] r8152 1-1.1:1.0 enxXXXXXXXXXXXX: renamed from eth0
```

で、名前が enxXXXXXXXXXXXX (XX部分はMACアドレス) になってしまったので

[こちら](https://raspberrypi.stackexchange.com/questions/43560/raspberry-pi-3-eth0-wrongfully-named-enx)を参考にさせて頂いて

/lib/udev/rules.d/73-usb-net-by-mac.rules

の NAME="$env{ID_NET_NAME_MAC}" 部分を NAME="eth0" に書き換えてリブートしたところ無事ネットワークにつながりました。

# 後日追記

2019.2にバージョンアップして再ビルドしたところ make install で

```
Warning: modules_install: missing 'System.map' file. Skipping depmod.
```

と言われましたが、depmod を実行したら解決したようです。


# おしらせ

2020/10/30 にて Qrunch がサービス終了したので移転してきた記事となります。
一時退避場所：https://github.com/ryuz/qrunch_blog
【Rails】途中でアプリ名を変更する方法

#結論
-手順-
① renameのgem を記述して % bundle install
② 旧名のDBを削除 % rails db:drop
③ アプリ名の変更 % rails g rename:into (新しいアプリ名)
④ 新しいアプリ名のディレクトリへ移動　％ cd ../(新しいアプリ名)
⑤ 新しいDBを作成 % rails db:create 
⑥ 新しいDBのテーブル作成 % rails db:migrate
⑦ 再起動 % rails s
⑧ GitHubの旧アプリ名を変更

全体の流れは上記の手順です。
 下記よりそれぞれ細かく説明していきます。

#手順
#①renameのgemを追加

```ruby:Gemfile
  gem 'rename'
```
```
  % bundle install
```

#②旧名のDBを削除

```
  % rails db:drop
```
旧名のDBを残すなら不要ですが、アプリ名変更の前に削除していた方が簡単です。

#③アプリ名の変更

```
  % rails g rename:into (新しいアプリ名)
```
①で作成したrenameのgemを使用してアプリ名の変更します。

#④新しいアプリ名のディレクトリへ移動

```
  ％ cd ../(新しいアプリ名)
```

#⑤新しいDBを作成

```
  % rails db:create
```

#⑥新しいDBのテーブル作成

```
  ％ rails db:migrate
```

#⑦再起動

```
  ％ rails s
```
正しく起動するか確かめます。

#⑧GitHubの旧アプリ名を変更
1.GitHubを開いた後、旧アプリ名で利用していたリポジトリを開き、**Settings**を選択。
2.**Repository name**を変更
3.新アプリ名を入力後、**Rename**をクリック

これで完了です。

#注意点
- 【アプリ名変更後】元々、旧アプリ名が必ず使用されていた箇所はgemによって修正されましたが、個別に名称を使用した箇所に関しては変更されてない為、自身で修正する必要があります。
- アプリ名をモデルやコントローラーなどの名称と同じにするとエラーが発生します。

下記のコマンドで旧アプリ名が含まれている箇所を探すことができます。

```
% grep -rn (新しいアプリ名) . --exclude-dir={.git,tmp,log}
```

#Rubyバージョン
ruby 2.6.5

#参考リンク
[Railsのアプリ名を変更して、GitHubのリポジトリ名を変更するまで -Qiita](https://qiita.com/TeppeiMimachi/items/d0176c4ec5d4b4fad895)

[Railsアプリの名称を変更したい！できるだけ楽に安心して行える方法を解説 -blog](https://www.autovice.jp/articles/38)
【MQL4】externとinputの違い

# 概要
古い本や古いサンプルで勉強していたので今までは宣言前に`extern`で指定していました。
というよりほぼコピペ。
で、本腰入れるようになってから見かけたのが`input`です。
どちらも外部パラメータを使用する値を宣言する際に付する変数ですが微妙に違いがることに気づきました。

# ドキュメントの一部を抜粋
ドキュメントだとつらつら書かれて読みにくかったので改行を入れて、重要な部分に背景色を入れました。


## input変数
inputストレージクラスは、外部変数を定義しています。
input修飾子は、データ型の前に示されます。
`input修飾子を持つ変数はMQL5プログラム内で変更することはできず、読み込み専用でアクセスすることが出来ます。`
input変数の値はプログラムのプロパティウィンドウから、ユーザによってのみ変更することが出来ます。

## extern変数
externキーワードは変数名の宣言に静的ストレージクラスとグローバルライフタイムの識別子として使用されます。
`これらの変数はプログラムの先頭から存在し、メモリはプログラムの開始直後に割り当てられ初期化されます。`

複数のソースファイルで構成されたプログラムを作成することは可能です。
この場合、プリプロセッサに指示する#includeディレクティブが使用されます。
`同じ型と識別子を持つexternと宣言された変数は、プロジェクト内の複数のソースファイルに存在することが出来ます。`

`プロジェクト全体をコンパイルする時、同じ型と識別子を持つ全てのextern変数は、グローバル変数プールのメモリの一部に関連しています。`
Extern変数は、ソースファイルの分割コンパイルするのに便利です。
Extern変数が初期化出来るのは一度だけです。
`同じ型と識別子を持つextern変数の複数の初期化は禁止されています。`

# 違い
ざっくり言えばinputはプログラムによる書き換えが不可でexternは書き換えが可能という点が大きな差です。
inputは定数でexternはグローバル変数のようなイメージですね。
定数は#defineで宣言するから定数ではないですが、、、


# 結論
わざわざユーザーが入力している値なので、特別な理由がない限り入力パラメータを使用する際はinputの方が無難そう。

# 参考
・公式ドキュメント
[Input変数](https://www.mql5.com/ja/docs/basis/variables/inputvariables)
[Extern変数](https://www.mql5.com/ja/docs/basis/variables/externvariables)

・その他
[外部変数・・・MT4（メタトレーダー4）のEA（自動売買）プログラミング講座](https://www.oanda.jp/lab-education/fx_on/%E4%B8%8A%E7%B4%9A%E8%80%85/3666/)
[[MT4プログラミング]小ネタ inputとexternの違いやsinputのお話し](http://mt4program.blogspot.com/2015/11/mt4-inputexternsinput.html)
Ruby で解く AtCoder ABC 197 D

# はじめに
*[AtCoder Problems](https://kenkoooo.com/atcoder/#/)* の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。

# 今回のお題
*[AtCoder Beginner Contest D - Opposite](https://atcoder.jp/contests/abc197/tasks/abc197_d)*
<font color="green">Difficulty: 831</font>

今回のテーマ、座標の変換

`(x, y)`を回転させた座標が答えとなります。
公式解説およびユーザ解説を`ruby`にトランスします。
# 公式解説
```public.rb
include Math
n = gets.to_f
xy0 = gets.split.map(&:to_f)
xy2 = gets.split.map(&:to_f)
p = 2 * PI / n
q = [(xy0[0] + xy2[0]) / 2, (xy0[1] + xy2[1]) / 2]
r = sqrt((xy0[0] - q[0])**2 + (xy0[1] - q[1])**2)
t = atan2(xy0[1] - q[1], xy0[0] - q[0]) + p
puts [cos(t) * r + q[0], sin(t) * r + q[1]].join(' ')
```
```Math.rb
include Math
```
`Math`モジュールを呼び出しています。毎度、`Math.PI`などと書かず`PI`と省略できます。
`atan2`は普段使わないし、公式解説はコードが載っていないので、[AtCoder Beginner Contest 197 (Sponsored by Panasonic) 参戦記](https://qiita.com/c-yan/items/871c5a984437261f47ce)を参照しました。
# ユーザ解説
```user.rb
require 'complex'
include Math
n = gets.to_f
xy0 = gets.split.map(&:to_f)
xy2 = gets.split.map(&:to_f)
c0 = Complex(xy0[0], xy0[1])
c2 = Complex(xy2[0], xy2[1])
q = (c0 + c2) / 2
a = q + (c0 - q) * Complex.polar(1, 2 * PI / n)
puts [a.real, a.imag].join(' ')
```
```Complex.rb
require 'complex'
```
こちらは`複素数`を用いた解法です。
*[class Complex](https://docs.ruby-lang.org/ja/latest/class/Complex.html)*
`Complex.polar`で回転させています。
# 自分のコード
```my.rb
include Math
n = gets.to_f
xy0 = gets.split.map(&:to_f)
xy2 = gets.split.map(&:to_f)
p = 2 * PI / n
q = [(xy0[0] + xy2[0]) / 2, (xy0[1] + xy2[1]) / 2]
xa = cos(p) * (xy0[0] - q[0]) - sin(p) * (xy0[1] - q[1]) + q[0]
ya = sin(p) * (xy0[0] - q[0]) + cos(p) * (xy0[1] - q[1]) + q[1]
puts [xa, ya].join(' ')
```
公式解説の半径を使用していないバージョンです。

||RubyP|RubyU|RubyM|
|:--:|:--:|:--:|:--:|
|コード長 (Byte)|306|267|310|
|実行時間 (ms)|63|66|63|
|メモリ (KB)|14640|14596|14712|
# まとめ
+ ABC 197 D を解いた
+ 座標変換 に詳しくなった
Amazon Lightsail とは

## 勉強前イメージ

初めて聞いたサービス名・・・わからない

## 調査

### Amazon Lightsail とは

VPS(仮想プライベートサーバー)サービスになります。
コンピューティング環境やストレージ、ファイアウォール、DNS機能などWebサービスに必要な機能をまとめてパッケージで提供されています。
手軽にwebアプリケーションを構築したいときなどの用途に向いています。

### 特徴

- 低価格

月額 3.50 USDからと謳ってる通り、低価格になります。
気軽に使うことが出来ます。

- 簡単なサーバをすぐに作成することが出来る

予め用意されているOSから、アプリケーションまでワンクリックで作成することが出来ます。
比較的知識がなくても使うことが出来ます。

- 細かくカスタマイズが出来ない

ある程度用意荒れているので、細かくカスタマイズできないので、柔軟度は低いです。

### EC2との違い

同じようなサービスでEC2があります。
EC2との違いは以下になります。

- Amazon Lightsail と違い、コンピューティング環境のみなのでアプリケーションは自分で設定しないといけない
	- EC2は自分でアプリケーションの設定やインストールが出来るので、自由度が高いです。
- EC2は従量課金制なので、稼働した時間で費用がかかります。

## 勉強後イメージ

このサービス初めて知った！
めっちゃ便利やん・・・
Wordpressとかする人にはかなりいいかもしれない(まだやったことないけど)

## 参考

- [「Amazon Lightsail の特徴」](https://aws.amazon.com/jp/lightsail/features/)
- [Amazon Lightsailとは？4つの特長やEC2との違い](https://www.fenet.jp/infla/column/technology/188-2/)
- [【VPS】Amazon Lightsailとは？](https://www.acrovision.jp/service/aws/?p=1910)
Android studioでbuild後にINSTALL_FAILED_INSUFFICIENT_STORAGEと表示されたときの対処法

急に下記のメッセージが表示された。Android Emulatorのストレージが足りなくなっているという意味らしい。

```
adb: failed to install E:\xxxxx\build\app\outputs\flutter-apk\app.apk: Failure 
[INSTALL_FAILED_INSUFFICIENT_STORAGE]
Error launching application on Android SDK built for x86.
```


対処法 Androidでの通常のアプリの削除と同様のことをすれば良い

1.左クリックで削除したいアプリを掴んで、トップ画面のゴミ箱にドラッグ＆ドロップ

2.設定>アプリで該当のアプリを選択して、削除
可変フォントサイズの指定方法

リキッドさせるみたいなコーディングで悩んだことってありますよね。

デザイナーが1600pxのカンバスサイズで作ったものをそのままのフォントサイズでコーディングするとノートPCなどの小さい端末で見たときにフォントサイズが大きすぎたり、デザインが崩れます・・。

font-sizeをvwで指定するやり方がありますが、ブレイクポイントの調整がめんどくさく効率的ではありません。

#remでフォントサイズを指定
rem指定は主流ですよね。remで指定しているサイトが多いかと思います。

>remとは「root」+「em」という意味で、
root要素（html要素）に対して相対的にフォントサイズが指定できます。​

```css
html {
 font-size: 62.5%;
}

p {
 font-size: 1.3rem;
}
```

基準となるサイズを「62.5%」とした場合、「font-size: 1.3rem;」は「font-size: 13px;」に相当します。

#解決策
root要素（html要素）に対してvwを指定します。
下記のようなCSSを記述すると、
1600pxまでは画面の幅に合わせてレイアウトがそのままで可変ということが実現できます。

```css
html {
	font-size: 0.625vw;
	@media screen and (min-width: 1601px) {
		font-size: 62.5%;
	}
	@media screen and (max-width: 1000px) {
		font-size: 39.0625%;
	}
	@media screen and (max-width: 750px) {
		font-size: 62.5%;
	}
}
```

ただそのままvwだと1600px超えてからも大きくなり続けるのでデザインが崩れます。逆に小さい幅だと小さくなり続けるので上記のような指定にするのがベストです。​
AWSでWebアプリをデプロイする方法(Java)②

#ユーザーを追加する
AWSアカウント自体を普段から利用ことは、パスワードが漏洩などした場合に契約や支払いを含め全権限があるため危険です。
普段利用としては、そう言った情報を扱わないアカウントを作成し、利用することが一般的です。

###利用環境
OS:MacOS
ブラウザ:Chrome

###前提条件
AWSアカウントの取得が完了している状態
まだ、アカウントを追加していない方は[こちら]
(https://qiita.com/kunrenyouAcount/items/97e0008942aea4e191b4)

##IAMユーザーを作成する
サインインすると下記の画面が表示されます
![スクリーンショット 2021-04-02 1.16.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/6389def4-f948-23f1-a749-8d2a74117510.png)

画面上部の検索欄、もしくはサービスからIM検索し「IAMダッシュボード」を開きます
![スクリーンショット 2021-04-03 17.50.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/abcefeec-b2e7-084b-cb66-b5288ad14116.png)

[ユーザー]を選択
![スクリーンショット 2021-04-03 17.51.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/ddac994c-e2f1-1846-e29e-4df4fd7954d6.png)

###ユーザー詳細の設定
[ユーザーの追加]を選択し、表示された画面を以下のように入入力し、[次のステップ]を選択
![スクリーンショット 2021-04-03 17.54.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/ea1788ca-3da0-e3bb-bf32-1f9cbb05d37f.png)

###アクセス権限の設定
[既存のポリシーを直接アタッチ]を選択し、ポリシーを選美、[次のステップ]を選択
今回は全権限を持ったユーザーを追加するため、[AdministratorAccess]にチェックを入れる
![スクリーンショット 2021-04-03 17.57.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/4b94319f-5bee-4662-7470-a612601ff8b5.png)

###タグの追加
何もせず、[次のステップ]を選択
![スクリーンショット 2021-04-03 17.59.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/3d105d7d-fe2c-3c06-c354-0e97c4cdc943.png)

###作成の確認
内容に間違えがなければ、[ユーザーの作成]を選択
![スクリーンショット 2021-04-03 18.00.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/91104539-4342-f6c6-7fbd-4615881463ad.png)

###パスワードとサインインのURLの確認
[表示]を選択
この画面で先ほど自動生成したパスワードを確認し、保存します
※注意：以降再確認はできない
記載されているURLでコンソールへサインインができるので、こちらも保存します
![スクリーンショット 2021-04-03 18.01.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/1851f866-dcfe-5cfc-cfec-0291f0a3ca62.png)

##IAMユーザーでのサインイン
作成したIAMユーザーで初めてサインインすると、パスワードの変更が求められます
任意のパスワードを設定してください
パスワードの変更ができたら、コンソール画面に戻ります
右上のユーザーの表示が切り替わっていることを確認してください

#AWSでWebアプリをデプロイする方法③
[請求情報を管理する](https://qiita.com/kunrenyouAcount/items/68f8fde1c96dc139f434)
git cloneしたあと、変更をステージできなくなってしまった

narumiと申します。

git cloneの後、意図せずGit submoduleが作成されてしまい、変更をステージに上げることが出来なくなってしまいました。原因と解決方法について自分の備忘録という意味でも記事にしたいと思います。
解決の過程をあまり覚えていないので分かりづらい点も多いと思いますが何卒ご了承ください。

gitをcloneしてからadd -Aとし、commitしようとしたときに下記のエラーが出ました。


```エラー```
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
  (commit or discard the untracked or modified content in submodules)
 modified:   （ファイル名） (modified content)
```
この時点で原因が全く分かりませんでした。
git add -Aを行っているのに変更がステージされていない？という状況が初めてでした。

git statusで詳細を見てみる

```エラー```
...省略
(※abcdefg12345は適当な文字列です)

-Subproject commit abcdefg12345
+Subproject commit abcdefg12345-dirty

```
dirtyという記載を始めてみたのでこれについて調べてみると、dirtyと書かれている方がsubmoduleで登録しているリポジトリのようです。
ですがsubmoduleという言葉を初めて聞き、なおかつsubmoduleを登録した覚えがない(そもそもやり方を知らない)

色々と試行錯誤しましたがなかなかは上手くいきませんでした。幸いにも同様の症状で困っていた方の記事を見つけ問題解決に至りました。

<a href="https://teratail.com/questions/185893">参考にした記事</a>

cloneする前、もしくはした後にgit initをしてしまった覚えがあります。
cloneするタイミングからやり直すことで無事解決しました。

gitは難しいですが、色々試しながら知識を深めていきたいと思います。

以上です。お読みいただきありがとうございました。
narumi
C++で、Lua側から呼び出された関数の戻り値にtableを設定する方法

# 動機
自分のプログラムにLuaを組み込もうと思い、さすがにCインターフェースを使うのは嫌だなぁと思っていい感じのライブラリを探して見つけて使ってみたら良さそうな感じだったので採用したが、tableの返し方が分からずハマってしまったので、忘れないように解法を残しておく

https://github.com/ThePhD/sol2

# 要するに

https://github.com/ThePhD/sol2/issues/167

同じようなことで悩んでたissue見つかって、親切にもやり方が書いてあったので解決

````C++
sol::object multiply(sol::this_state thislua) {
     sol::state_view existing_state = thislua;
     auto table = existing_state.create_table();
     table["test"] = "好きなように";
     return table;
}

lua["multiply"] = multiply;
````

要するにこんな感じでtableを作って返す関数を登録して

```lua
function ShowTable(t)
    for key, val in pairs(t) do
        if type(val) == "table" then 
            print("key: " .. key .. " table ->")
            ShowTable(val)
        else
            print("key: " .. key .. " val: " .. tostring(val))
        end
     end
end

ShowTable(multiply())

````

Lua側で登録した関数を呼んであげれば、C++側で作ったtableが返る

コツとしては、登録する関数の引数に "sol::this_state"を受け取るようにすること
そうすることによって、なんやかんやした後に"existing_state.create_table();"を呼び出してtableを作ることが可能になります
QNAP NAS 暗号化の仕組みと解除方法

# はじめに

QNAP NASに障害発生。volume1が破損し何も出来なくなった。
volume1は後で対処するとして、volume2の暗号化ファイルシステムに保存したデータを急ぎ読み出したい。
volume1が破損すると利用不能に陥る残念な仕様のQNAP NAS。
これはアプリやその設定情報がvolume1に入っているからで、volume2以降は正常だとしてもNASとして利用不能だから結果アクセス出来なくなってしまう。
LinuxベースのNASなんだからコマンドラインからアクセスしたり、ディスクを取り外し他のNASやサーバで読み出したりできるはず。
しかし、正しいパスフレーズを入力しても読み出せない！？
QNAPの暗号化の仕組みを調べ解除するまでの話。


# LUKS のはずなのに？

QNAPのNASはLinuxベースでファイルシステムの暗号化はLUKSのはず。
ディスクのセクタをダンプして確認してもやはりそうだ。
しかし正しいパスフレーズを入力しても復号化できない。

一筋縄にはいかないか。暗号化の仕組みを調べる。

インターネットを彷徨っていると同じ悩みを抱えた人がちらほらと。
どうやら storage_util というQNAP独自ツールで入力したパスフレーズをハッシュ化し、実際にはハッシュをパスフレーズとして使用している模様。
https://forum.qnapclub.de/thread/39047-anleitung-schl%C3%BCsseldatei-nicht-auf-nas-speichern-backup-zwischen-zwei-verschl%C3%BCss/
http://www.linux-howto.info/mount-qnap-encrypted-volume/

これは人間が入力した文字列では暗号化の種(seed)としては偏りがあって好ましくないからハッシュしているのだろう。
そりゃ暗号化解除出来ないわけです。早速storage_utilを試す。


# しかしそれでも解除出来ない

storage_utilへ正しいパスフレーズを入力して解除キーを生成してもだめ。
なんでやねん！

# パスフレーズは32文字

これにたどり着く迄にかなりの時間を要した。
設定していたパスフレーズは50文字を超えている。
そもそもパスフレーズ長って無制限なのか？
実験を繰り返すとパスフレーズが50文字でも60文字でも暗号化の内容が同じである事に気付く。

それだ。

コンピュータ的に32文字か16文字にしているのだろう。
storage_utilへパスフレーズの先頭32文字のみを入力して解除キーを作成。
マウント成功。

なるほど、storage_util自体は何文字でも入力できるがQNAP NASのWeb操作画面では33文字以上は内部で捨てて32文字としてstorage_utilへ値を引き渡していたようで。
謎は解けた。


# 具体的なコマンド入力方法

実際に解除に使用したコマンドを以下に示す。
パスフレーズは上記の通り先頭32文字（32文字以下の場合は全て）
デバイス名は適宜読み替える事。

```
storage_util --encrypt_pwd pwd=パスフレーズ | sed 's/Encrypted passwd is://g' | cryptsetup -v luksOpen /dev/mapper/vg288-lv1 CE_CACHEDEV2
mount -t ext4 -o ro /dev/mapper/CE_CACHEDEV2 /share/CACHEDEV2_DATA/
```

あとは他のNASをNFSマウントしてコピーするなりなんなりバックアップを。


# まとめ

- QNAP NAS の暗号化ファイルシステムはLinux標準のLUKSベース
- しかしパスフレーズは storage_util でハッシュ化した値を使用
- 入力パスフレーズは32文字まで。33文字目以降は内部で捨てられ32文字。

この情報、ベンダに問い合わせても開示されないんですよね。
有志が解析した結果が世に出回っているけど故障時に困るからこういう情報は公開情報にして欲しい。
Slack APIのメッセージ投稿でのアイコンの変更方法

#結論:chat:write.customizeが必要

ドキュメントを見ると、iconの変更、usernameの変更には、as_user:falseが必要と書いてある
https://api.slack.com/methods/chat.postMessage

が、その通りにするとエラーになる。

>{"ok":false,"error":"invalid_arguments","deprecated_argument":"as_user"}

上記のドキュメントの下の方に、さらっと

>Please note that the as_user parameter may not be used by new Slack apps. Read more about Authorship to understand how as_user works for classic Slack apps.

とかかれており、この方法は正しくない。

>This is a powerful ability and must only be used when the user themselves gives permission to do so. For this reason, this ability is only available when an app has requested and been granted an additional scope — chat:write.customize.

というわけで、as_userは使わず、Slackアプリに chat:write.customize 権限を付加すれば、usernameの変更、iconの変更(icon_emoji, icon_url)が可能になる。

## おまけ:　アイコンの英語名の表示の仕方
Slackのアイコンは日本語名がついている場合、それが表示される。Slack APIで使う場合は英語名が良いので、それを表示する方法。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221204/8c93e000-8b34-8a8d-8e65-7ed994a135c9.png)

まずはメッセージ書き込みウインドウでアイコン選んで入力する。入力されたアイコンにマウスカーソルを重ねると、アイコンの英語名が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221204/3694aff4-ec3c-d5bc-2d5b-c4d37642a21b.png)
Big SurでBetterTouchToolの設定画面が突然開かれる問題のための設定

MacOSをBig Surにアップデートして以来、
Macを使用中に突然BetterTouchTool（BTT)の設定画面がポップアップ表示される、という現象が頻発するようになりました。
BTTフォーラムでの回避方法を試して改善しましたので、共有します。

## 対応
ターミナルで以下のコマンドを実行する。

```sh
defaults write com.hegenberg.BetterTouchTool BTTDontShowPrefsOnReopen YES
```

## 補足: 現象、環境、対応経緯

参考までに

* BetterTouchToolの古いバージョン(2.x系？)を使用
    * グローバル ショートカットキー設定
    * タッチバー カスタマイズ
    * 外付けマウス 設定
        * ホイールでのスクロールを逆に
* 2020年12月 OSをBig Surにアップデートした
* OS使用中に、突然BetterTouchTool（BTT)の設定画面が表示される
    * 現象のトリガは不明
    * BTTに設定されたショートカットキーを **実行していない＊＊
    * 1日８時間程度Macを使用しているとすると、その間に３〜5回は本現象が発生する
* 2021年2月 その後、BTTを3.5系にバージョンアップ
* しかし、改善せず。現象が発生する
* 2021年3月中旬 対応コマンド実行
    * `defaults write com.hegenberg.BetterTouchTool BTTDontShowPrefsOnReopen YES`
* その後(約２週間)、現象は発生せず

## 参考URL

* [Random appearing and disappearing of configuration window - Bug Reports - BetterTouchTool Community](https://community.folivora.ai/t/random-appearing-and-disappearing-of-configuration-window/21388)
* [BTT keeps opening itself randomly... ?? - Discussion & Questions - BetterTouchTool Community](https://community.folivora.ai/t/btt-keeps-opening-itself-randomly/20547)
* [構成ウィンドウが突然表示されます-バグレポート-BetterTouchToolコミュニティ](https://community.folivora.ai/t/configuration-window-appears-out-of-the-blue/19807/18)
配列

# 配列（要素を取得）
```php
let fruits = ['もも','りんご','バナナ','みかん','ぶどう'];

//１番目の要素
console.log(fruits[0]);  //fruits[0]:もも

//4番目の要素
console.log(fruits[3]); //fruits[3]:みかん

//6番目の要素(空っぽ)
console.log(fruits[6]); //fruits[5]:undefined
```

# indexOf
- 配列データに存在する場合にその場所を「インデックス番号」で取得


```php
let fruits = ['もも','りんご','バナナ','みかん','ぶどう'];
let fruits2 = fruits.indexOf('りんご');
console.log(fruits2);//1
```



# push

- 配列要素の追加


```php
let fruits = ['もも','りんご','バナナ','みかん','ぶどう'];
fruits.push ('梨');
console.log(fruits);//(6) ["もも", "りんご", "バナナ", "みかん", "ぶどう", "梨"]
```

# delete

- 要素の削除

```php
let fruits = ['もも','りんご','バナナ','みかん','ぶどう'];
delete fruits[2];
console.log(fruits);//(5) ["もも", "りんご", empty, "みかん", "ぶどう"]
```
ローカルでmasterブランチへのgit pushを禁ずる方法

タイトルは嘘。

リモートへのgit pushを禁ずるために、ローカルでmasterブランチに*git commit*ができないようにした。
以下を、gitレポジトリ内に配置すればよい。


```bash:.git/hooks/pre-commit

branch=`git symbolic-ref HEAD`
if test "$branch" = "refs/heads/master" || test "$branch" = "refs/heads/main"; then
    echo "Direct commits to the master branch are not allowed."
    exit 1
fi

```

executableにする。

```bash

$ chmod +x .git/hooks/pre-commit      
```


すると、以下のようなエラーが出るようになった。


```bash
$ git commit -m 'test' --allow-empty    

Direct commits to the master branch are not allowed.
```

よし。


## 参考

- https://gist.github.com/vlucas/8009a5edadf8d0ff7430#gistcomment-2060400
iOS/macCatalystアプリで、指定されたフォルダの中にファイルを書き出す

# 概要
* iOS 13以降では、`UIDocumentPickerViewController`で`documentTypes`に`kUTTypeFolder`を指定すると、フォルダを選択させることが可能になっている。
* 選択されたフォルダに対して`startAccessSecurityScopedResource`を呼び出すと、そのフォルダの下にファイルを書き込むことができる。

# Permissionの設定
App Sandboxで「User Selected File」を「Read/Write」に設定する。

# UIDocumentPickerViewControllerで書き込み先フォルダを選ぶ
iOS 13以降では`UIDocumentPickerViewController`で`documentTypes`に`kUTTypeFolder`を指定することで、フォルダの選択が可能となっている。

```swift
import MobileCoreServices // kUTTypeFolderを参照するために必要

...

let documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypeFolder as String], in: .open)
documentPicker.delegate = self
present(documentPicker, animated: true, completion: nil)
```

# 選択されたディレクトリの下にファイルを書き込む
```swift
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
    guard let directoryURL = urls.first else {
        return
    }
    debugPrint(directoryURL)

    guard directoryURL.startAccessingSecurityScopedResource() else {
        // Handle the failure here.
        return
    }
    defer { directoryURL.stopAccessingSecurityScopedResource() }
        
    do {
        try "Hello World".write(to: directoryURL.appendingPathComponent("hello.txt"), atomically: true, encoding: .utf8)
        try "Good Morning".write(to: directoryURL.appendingPathComponent("morning.txt"), atomically: true, encoding: .utf8)
    } catch let error {
        debugPrint(error)
    }
}
```

`startAccessingSecurityScopedResource()`を呼び出さないと、ファイルの書き込みができないので注意。

```
Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “hello.txt” in the folder “com~apple~CloudDocs”."
```

# 参考
https://developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories
Spreadsheet 複数セルの各文字列を結合する! CONCATENATE関数

## 初めに
この記事では、タイトルの通りスプレッドシート上で複数のセル内にある各文字列を結合して一つの文字列にする方法を記載します。
文字列結合は、Googleが関数で用意してくれているのでうまく活用しましょう。
この記事は[営業の私がGoogle Apps Script【GAS】を使って営業の業務を自動化・効率化していく話](https://qiita.com/ryoichi_ben/items/892a3034b46b58167e00)の備忘録です。
こちらも是非ご覧ください。

## 文字列結合にはCONCATENATE関数を活用しよう。
googleが文字列結合関数を要してくれてるので、こちらを活用しましょう。


```
=concatenate("セル1","セル2",....)
```

##基本的な使い方
例えば、以下の様に、A1に"あいうえお",A2に"かきくけこ"という文字列が。入っているとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573711/4539f509-37b0-8dbb-46f2-adbf08bc20d9.png)

B1に、A1とA2の文字列を結合した結果を入れたい場合は、B1に以下の様に関数を入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573711/013d8e96-1ae5-e66a-935f-24a993696217.png)

そうすると、以下の様な結果になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573711/288b81a0-e4ce-9975-2030-a321c55757a7.png)

##文字列を好きな順序で結合する。
concatenate関数は、引数で指定したセルの順序で文字列を結合してくれます。

例えば、以下のようにB2に、A2,A1の順序で引数に入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573711/a1e9960d-87d1-8fce-7884-d795a9f3fe31.png)

すると結果は以下の通り、結合結果は"かきくけこあいうえお"になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573711/38c7cb93-c4c8-a23b-d686-f84ae9275620.png)

## 改行を入れて結合する。
文字列結合結果に改行を入れたい場合がありますよね。そういう時は以下の方法で可能です。

###1.結合するセル内で改行させておく。
A5に"さしすせそ",A6に"たちつてと"という文字列が入っていますが、A6は改行を入れております。(２行になっていますよね)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573711/d9cfaa71-8d88-2299-9eed-92ca0be1fc23.png)

この状態で文字列結合を行うと、改行されたまま文字列は結合されるので、以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573711/be2a0924-e674-a9fc-bd39-252de3af9acf.png)

###2.引数にCHAR(10)を入れる
concatenate関数の引数に CHAR(10)を代入しても改行ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573711/e411737f-0439-2096-021b-f617ab07d9c1.png)

以下の様に改行されて文字列が結合されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573711/5b5d47b3-f0eb-f450-3e50-ef59f4de58c4.png)


#おわりに
concatenate関数を活用すれば簡単に文字列結合できますので、普段の業務に是非活用してみてください。
私も営業業務でなんとか業務を自動化できないか模索中で、以下にまとめておりますので、是非ご覧ください。
[営業の私がGoogle Apps Script【GAS】を使って営業の業務を自動化・効率化していく話](https://qiita.com/ryoichi_ben/items/892a3034b46b58167e00)
VLC for Android：アルバム管理画面データの流れを解析

# はじめに

VLC for Androidの楽曲管理画面のデータの流れを理解する。

# 各種リンク

[アプリ](https://play.google.com/store/apps/details?id=org.videolan.vlc&hl=ja&gl=US)
[GitHub](https://github.com/videolan/vlc-android)
[公式サイト](https://www.videolan.org/index.ja.html)


# アルバム管理画面のスクリーンショット

WIP

# 大まかな流れ


# アルバム管理画面、データ生成のコミュニケーション図

PagedListクラスのマナーにそってデータの流れを設計している。

![リレーションの構築.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39706/bec6e0b3-b7a8-bccf-f040-956a565eaffe.png)


# アルバム管理画面、一番下までスクロールした時のコミュニケーション図

PagedListが範囲外のデータを要求されるとMLDataSourceのメソッド呼び出す。
MLDataSourceはAlbumsProvider経由でDBに更新をかけてMLDataSource経由でPageListへ通知、AudtioBrowserAdapter経由でReclyclerViewの表示を変更する。

![下までスクロールした時.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39706/db61f7f8-6786-4ed2-b70b-3ac908ecd692.png)

# まとめ
【Rails】 親モデルと子モデルを同時に削除する方法 [dependent: :destroy]

#結論
dependent: :destroy を記述することで、「親モデルを削除した際にその子モデルも同時に削除」できます。

投稿内容を削除する場合、その投稿に紐づくコメントなども同時にテーブルから削除する時に使用します。

#Rubyバージョン
ruby 2.6.5

#dependent: :destroyの記述場所
dependent: :destroyは親モデルのアソシエーションのみに記述します。

```ruby:(親モデル)　post.rb
class Post < ApplicationRecord
  has_many :comments, dependent: :destroy 
```

```ruby:(子モデル)　comment.rb
class Comment < ApplicationRecord
  belongs_to :post
```

#モデルが複数存在する場合
子モデル(comment)に紐づいて、さらに子モデル(like)が存在する場合、追加で「親モデル」にdependent: :destroyを記述します。

```ruby:comment.rb
class Comment < ApplicationRecord
  has_many :likes, dependent: :destroy
```

#参考リンク
・[Active Record の関連付け](https://railsguides.jp/association_basics.html)
Puppeteer（パペティア）でcsvファイルをダウンロードする

# 概要

ずっとやりたかったPuppeteerでファイルダウンロードをやってみた。
世の中いろんなやり方が書かれていて混乱したが、やってみたら簡単にできたので共有。

参考 - 公式issue
https://github.com/puppeteer/puppeteer/issues/299

# 環境
* Ubuntu18.04
* Node.js v14.15.1
* Puppeteer 8.0.0

# ソース

意外と普通にできました！
何か罠が待っている気もしなくもなく。

```javascript
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require("path");

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    const width = 1980;
    const height = 1080;
    await page.setViewport({ width, height });
    await page.goto('https://portal.local/');
    // gotoの後は、waitしなくてよさげ

    // ファイルダウンロード
    const downloadPath = path.resolve('/hoge/fuga/'); // ここは絶対に絶対パス
    await page._client.send('Page.setDownloadBehavior', {
        behavior: 'allow',
        downloadPath: downloadPath 
    });

    // csvダウンロードボタンクリック
    await page.click('.csvDownload');
    await page.waitForTimeout(5000);

    await browser.close();
})();
```


# 参考

https://qiita.com/yoshi0518/items/0685700861fb7fd3f97b

https://qiita.com/kanoe/items/9043a81d28a1b733b2e2
Twitterで投稿した勉強記録をPixelaで可視化

## 作ったもの

Twitterで、ある日の、特定のワードを含むツイートを収集し、その数をPixelaに反映させるアプリ。

例えば、本を読んだよとか、勉強したよとかをTwitterで報告する。
その時、何か特定のワードを含ませるようにしておく(例えば「#勉強記録」)。

それを毎日収集し、Pixelaに記録して、可視化する→さらなる勉強モチベの向上を狙う。

例えばこんな感じ
https://twitter.com/veFrkC841DN0I8Q/status/1378200472213811200?s=20

## 必要なもの/こと

* [TwitterAPIアカウント作成](https://developer.twitter.com/en/docs/twitter-api/getting-started/getting-access-to-the-twitter-api)
* [Pixelaアカウント](https://pixe.la/ja)
* [記録用のPixelaグラフ](https://docs.pixe.la/entry/post-graph)

## 手順

まずは、TwitterAPIを使用するための登録をする
これは[公式ドキュメント※英語](https://developer.twitter.com/en/docs/twitter-api/getting-started/getting-access-to-the-twitter-api)が参考になる

次にPixelaの諸々の事前準備を済ませる  
これは、[公式サイト](https://pixe.la/ja)の下の方「使い方」が参考になる

そして、TwitterAPIとPixelaの利用に必要な情報を環境変数に登録する
コード※下記参照 にベタ打ちでも良いが、git管理とかするなら、環境変数に登録したほうがセキュア  
というより、ベタ打ちするとGitGuardianから怒られるはず

最後に、以下のコードをcronなり、手打ちなりで実行する  

```sample.py
import tweepy
from os import environ as env
from pixela import Pixela
from datetime import datetime


def get_twitter_api(
        api_key,
        api_secret_key,
        access_token,
        access_secret_token):
    auth = tweepy.OAuthHandler(api_key, api_secret_key)
    auth.set_access_token(access_token, access_secret_token)
    return tweepy.API(auth)


def get_target_str_num(twitter_api, user_id, date, target_str):
    user_tweets = twitter_api.user_timeline(user_id)
    date_str = date.strftime("%Y%m%d")

    target_str_num = 0
    for tweet in user_tweets:
        tweet_date = tweet.created_at.strftime("%Y%m%d")
        if ((date_str == tweet_date) and (target_str in tweet.text)):
            target_str_num += 1

    return target_str_num


def create_pixel(user_name, token, graph_id, quantity, date):
    pixela = Pixela(username=user_name, token=token)

    pixela.create_pixel(
        graph_id=graph_id,
        quantity=quantity,
        date=date)


if __name__ == "__main__":
    pixela_user_name = "box16"
    pixela_graph_id = "study-record"
    graph_url = "https://pixe.la/v1/users/box16/graphs/study-record.html"
    target_str = "勉強記録"
    today = datetime.today()

    twitter_api = get_twitter_api(env.get("TWITTER_API_KEY"),
                                  env.get("TWITTER_API_SECRET_KEY"),
                                  env.get("TWITTER_ACCESS_TOKEN"),
                                  env.get("TWITTER_ACCESS_SECRET_KEY"))

    target_str_num = get_target_str_num(twitter_api,
                                        env.get("TWITTER_MY_ID"),
                                        today,
                                        target_str)

    create_pixel(pixela_user_name,
                 env.get('PIXELA_TOKEN'),
                 pixela_graph_id,
                 target_str_num,
                 today)

    twitter_api.update_status(
        f"本日の記録数 : {target_str_num} \n {graph_url}")

```
https://github.com/box16/StudyRecord/blob/main/study_record.py
【WebIOPi】スマホでサーボモーターを制御！③

#スマホでサーボモータを制御！

今回は、スマホでサーボモータを制御するシリーズの第３回目です。

Raspberry Piを用いて簡単にIoTを作成できるライブラリ、WebIOPiを使用し、スマホからサーボモーターを制御します。

これまでの記事は以下を参考にしてください。
[1. WebIOPiのインストール](https://qiita.com/happanosumide/items/2b151e2250953de3a258)
[2. HTML/CSSファイルの作成](https://qiita.com/happanosumide/items/7d8bf4b2d537188d9929)
[3. JavaScriptファイルの作成](https://qiita.com/happanosumide/items/cee747e27926f482b0df)


#サーボモーター
サーボモーターを動作させるPythonスクリプトを作成します。

サーボモーターは、パルスの周期に応じて回転します。それぞれの仕様によりますが、制御パルスは1.0ms ~ 2.4msの範囲だと思います。

ちなみに、[SG90](https://akizukidenshi.com/catalog/g/gM-08761/)というサーボモータは、0.5ms~2.4msだそうです。

サーボモーターを動作させるために、`pigpio`というライブラリを使用します。

#pigpioインストール
サーボモータを動作させるときに、安定したパルスを生成できるように、pigpioというライブラリを使用します。
Raspberry Piのターミナルで以下のコマンドを打ちます。

```bash
sudo apt install pigpio
```
pigpioを使用する場合は、以下のコマンドで起動（デーモン）します。

```bash

sudo pigpiod
```

#Pythonスクリプト作成

まず、全体は以下のようになります。

```pyfile.py
import webiopi
import pigpio

webiopi.setDebug()      # WebIOPiのデバッグをセット
pi = pigpio.pi()

# サーボモーターへのパルス出力ピンを指定
SV_1 = 12       # SERVO1
SV_2 = 19       # SERVO2

"""以下、サーボ動作"""

# SERVO1
@webiopi.macro
def GET1(val):
    value1 = int(val)
    pi.set_servo_pulsewidth(SV_1, value1)
    webiopi.debug(value1)


# SERVO2
@webiopi.macro
def GET2(val):
    value2 = int(val)
    pi.set_servo_pulsewidth(SV_2, value2)
    webiopi.debug(value2)
```

WebIOPiでは、デバッグを行う際、`webiopi.setDebug()`という記述をします。
そして、`webiopi.debug(表示したいパラメータ)`と記述することでデバッグの際、そのパラメータの値を確認することができます。

#webiopi.macro
ところで、JavaScriptで作成した`webiopi.callMacro()`関数を覚えていますか？

```js
webiopi().callMacro('GET1',value1)
```

この第一引数は、実行したいPython関数、ここでは`def GET1(val):`です。
また、JavaScriptより引数`val`を受け取ります。互いの関係は下の写真を参考にしてください。
![webiopi4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689410/0bf67b04-aae7-cd34-356c-6256feae215d.png)

ここで、webiopiで実行するPython関数には、関数名の上に`@webiopi.macro`という記述が必須です！


あとは、受け取った値を数値型に変換し、pigpioによりサーボを動作させます。

#最後に
次回が最終回です。

WebIOPiを使用してサーバーを起動させます。
【Pandas】日付や時間に関するモジュールについての概要 no.28

![見出しを追加 (66).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/de1cea39-2337-4eec-9df5-d8b2ad3e8e8c.png)

こんにちは、まゆみです。

Pandasについての記事をシリーズで書いています。

今回は第28回目になります。

今回から少しの間、<font color="Red">Pandasにおける日付や時間についてのデータの扱い方</font>について書いていこうと思います。

時間に関するモジュールを使えば、例えば

>ある期間のトレンドを追跡したり

>ある日曜日から次の日曜日までのデータを取ったり

>会社の四半期のデータを取ったりと

上記のようなことができるようになり、大変便利です。

Pandas の時間に関するモジュールを今回の記事から少しずつ書いていきます

では始めていきますね。

#PythonのdatetimeとPandas のTimeStampは何が違うの？

Pythonを学ばれた方なら、<font color="Red">datetime モジュール</font>は使った事があると思います。

datetimeモジュールから作る、date/datetimeオブジェクトと比べて、PandasのTimeStampオブジェクトがどれくらいパワフルであるか比較していきたいと思います。


まずは、date/datetime オブジェクトから見ていきます


#.date() .datetime()
datetimeモジュールから作られるオブジェクトにはdateオブジェクトもしくはdatetimeオブジェクトがあります。

>date は　年月日のデータを

>datetime は　年月日に加えて、時・分・秒のデータを持つことができます

dateメソッドでdateオブジェクトを作ります

![スクリーンショット 2021-04-03 124741.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/3d3700fc-ce2a-fa46-0abc-22d5d0c369bb.jpeg)

もし、オブジェクトの中の『年』を取り出したい時は『.year』、『月』を取り出したい時は『.month』、『日』を取り出したい時は『.day』アトリビュートを使うことなります。


次に、datetimeメソッドでdatetimeオブジェクトを作ります。

datetime オブジェクトは『年月日』に加えて、『時・分・秒』も含まれるので、もし『時・分・秒』の値を入れないと、<font color="Red">デフォルト値の０時</font>が表示されます。

![スクリーンショット 2021-04-03 124944.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/54b02be8-0298-5d39-c63d-6d8a41a790e3.jpeg)

![スクリーンショット 2021-04-03 125022.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/ad60f36c-e663-e30c-2ca2-a5f054bb8727.jpeg)

では次に、PandasのTimeStampについてみていきましょう

#PandasのTimeStampオブジェクト

![スクリーンショット 2021-04-03 160241.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/4dd350cd-fde6-d46d-b8a5-193f1b48de1c.jpeg)
引用元：[Pandasドキュメント](https://pandas.pydata.org/docs/reference/api/pandas.Timestamp.html)

ドキュメントに、<font color="Red">TimeStampオブジェクトはpythonのDatetimeと同等の物だ</font>と書いていますが、もちろん<font color="Red">TimeStamp ならではの特徴</font>もあります。

![スクリーンショット 2021-04-03 161030.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/515f5220-a4db-4a31-2154-6dd1b705407a.jpeg)
上記のコードの実行結果のスクショからも分かるように、TimeStampは、Pythonのdatetimeよりも、<font color="Red">広範囲の種類の引数を受け取ること</font>ができます

![スクリーンショット 2021-04-03 161759.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/eb45d90b-5af7-a612-fff9-d773bda97d7c.jpeg)

また、8：7：35　PM と書くだけでちゃんと24時間表記にも解釈しなおしてくれます。

PandasのTimeStampオブジェクトの方が

>よりパワフルで

>よりフレキシブルで

>より特徴のある

オブジェクトということが分かっていただけたと思います。

#まとめ

今回の記事はこのあたりで終わりにします。

今回は、PythonのDatetime オブジェクトとPandasのTimeStamp の違いについてさらっと、紹介させていただきました。

次回の記事では、TimeStampの特徴をさらに活かせるような使い方を紹介していきたいと思います。<(_ _)>
TalendジョブのOutOfMemory

#はじめに
Talendジョブを作成する際、コンポーネントの使い方によってOutOfMemryとなってしまう可能性があり、気を付ける必要があるコンポーネントについてまとめた記事です。

#Talendバージョン
TalendOpenStudio For DataIntergration v7.2

#OutOfMemoryを起こしやすい処理
###tMapのLookup処理
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1272354/84c8913d-6eba-377c-b2f2-65a4a3ddd47e.png)
tMapのLookup側に設定したデータは、Main側の処理を開始する前にメモリ上に乗せてからMain側の処理を開始する。
そのため「-Xmx size」で指定したヒープサイズを超えるようなデータをLookup側に設定（複数のLookupを設定した場合はその合計）するとOutOfMemoryが発生する。
下記記事にあるように「store temp data」オプションを使うことでOutOfMemoryは回避できるが、メモリとディスク間での出し入れが発生しパフォーマンスが劣化すると考えらえる。
[tMap利用におけるメモリ制限問題の解決](https://help.talend.com/r/aProid9p8_fl_RBowc66Yg/zFie_Nyxdb_7cVvbJYo0ew)
※DataStageのJoinステージのように事前にデータをソートし順次処理にすることで、メモリ上に溜め込まないような処理はできない模様。

###tSortRow
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1272354/40253c46-1293-7e75-71b9-1a6dc6896d38.png)
ソート処理を行うため結果的に全入力データをメモリ上にため込む形になり、ヒープ上限を超えるデータ量で処理した場合はOutOfMemoryが発生する。
「sort on disk」オプションを使うことでOutOfMemoryは回避できるが、やはりパフォーマンスが気になる。

###tAggregateRow
OutOfMemoryになる原理はtSortRowと同じ。
ただし、tAggregateRowには一時ディスクを使用するオプションがない。

#回避策
OutOfMemoryの回避策としては主に下記３つが考えられる。
・実行時に指定するヒープサイズの上限を上げる（メモリに余裕があるならこの選択肢が有力）
・一時ディスクを使用するオプションを使う（処理時間が余裕があるのであれば）
・上記のような処理はTalendジョブ外で実装する（PJルール等で1Tlanedジョブのメモリに上限がある場合は本選択肢が現実的か）

#終わりに
一応実機で確認はしていますが、記載内容の誤り等ありましたらコメントいただけますと幸いです。
VSCodeで「Remote - SSH」を使うと仮想マシンでも問題なくeslintなどのExtensionsが適用される

## 紹介する内容
- VSCodeで「Remote - SSH」を使うと仮想マシンでも問題なくeslintなどのExtensionsが適用される

## 作成理由
仮想マシン（vagrantで作った）でSambaを用いてVSCodeで作業するとeslintなどのVSCodeのExtensionsが `Failed to load plugin '@typescript-eslint' declared in '.eslintrc.js': File URL path must be absolute Referenced from` で動かない
![absolute_referenced_failed.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/0aa2c76b-d24d-cf65-89eb-7df971f0859d.png)


## 結論
- `Remote - SSH` を使うとVSCodeのExtensionsを何も気にせずに使えます
  - Sambaはファイルの編集は可能ですが、VSCodeのExtensionsのpath周りの問題があります
![remote_ssh.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/2731111d-a988-dc4d-1144-a9f2991e9764.png)


- vagrantで作った仮想マシンでvagrantではないユーザー（例 : jiho）で `Remote - SSH` するなら、 `/home/jiho/` の方に `/home/vagrant/` の `authorized_keys` をコピーペーストします
  - vagrantではないユーザーで作業するなら、permission denied を防ぐために必要です


## 紹介始めます
### `Remote - SSH` を使うとVSCodeのExtensionsを何も気にせずに使えます
- Sambaを使うVSCodeの場合
Sambaを使っているからパスに `\\192.168.33.15` などが見えます
![eslint_not_work.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/41fedb97-6377-1cbe-f3f5-52bb0768ce89.png)


- `Remote - SSH` を使うVSCodeの場合
![eslint_work.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/52e4f6c7-65cf-8b15-c164-04cd66d675c2.png)


  - sshで入ったVSCodeのExtensionsは別々でインストールする必要があります（忘れないようにお願いします）
![extensions_in_ssh_env.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/883d0879-2c0d-8b29-08a4-cc672fe982c9.png)



### vagrantで作った仮想マシンでvagrantではないユーザー（例 : jiho）で `Remote - SSH` するなら、 `/home/jiho/` の方に `/home/vagrant/` の `authorized_keys` をコピーペーストします
- vagrant ssh-configで取得した情報を手元の `~/.ssh/config` に追加する時に `User` を `jiho` にする
![vagrant_ssh_config.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/41d3d918-51b3-cda5-5a61-d6b0079b2d35.png)
![host_machine_ssh_config.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/7dee444b-ab7b-eab1-0ac8-2837df0bc546.png)

  
- `vagrant ssh` で仮想マシンに入って、`/home/vagrant/.ssh/authorized_keys` を `/home/jiho/.ssh/authorized_keys` にコピーペーストする

- `/home/jiho/.ssh/authorized_keys` の権限を `sudo chown jiho:jiho /home/jiho/.ssh/authorized_keys` で調整する
VSCodeでtmuxの挙動を再現したい

tmuxでのペインを作ったり消したり切り替えたりの動作を、VSCodeでもそれっぽく再現するために設定した項目をさらします。

tmuxのデフォルトのプレフィクスが`ctrl+b`なので、その設定でtmuxを操作しているときと同じような挙動をするようにkeybindings.jsonに以下の設定を加えました

# ペイン

```js

// エディタとターミナルの移動
{
    "key": "ctrl+b o",
    "command": "workbench.action.terminal.focus",
    "when": "editorFocus"
},
{
    "key": "ctrl+b o",
    "command": "workbench.action.focusActiveEditorGroup",
    "when": "terminalFocus"
},
// ターミナルの分割（縦のみ）
{
    "key": "ctrl+b shift+'",
    "command": "workbench.action.terminal.splitInActiveWorkspace"
},
// 一時的にエディタ、もしくはターミナルを全画面で表示する
{
   "key": "ctrl+b z",
    "command": "workbench.action.toggleMaximizedPanel",
    "when": "terminalFocus"
},
{
    "key": "ctrl+b z",
    "command": "workbench.action.togglePanel",
    "when": "editorFocus"
},
// ペインを閉じる
{
    "key": "ctrl+b x",
    "command": "workbench.action.terminal.kill",
    "when": "terminalFocus"
},
// 上下ペインのリサイズをAlt-UpとAlt-Downに割り当てた場合
{
    "key": "alt+up",
    "command": "workbench.action.terminal.resizePaneUp"
},
{
    "key": "alt+down",
    "command": "workbench.action.terminal.resizePaneDown"
},
```

# ウィンドウ（ターミナルの切り替え）
```js
// 新規ターミナル作成
{
    "key": "ctrl+b c",
    "command": "workbench.action.terminal.new"
},
// ターミナルの切り替え (next, previous)
{
    "key": "ctrl+b n",
    "command": "workbench.action.terminal.focusNext"
},
{
    "key": "ctrl+b p",
    "command": "workbench.action.terminal.focusPrevious"
},
// ウィンドウ一覧（tmuxでいうsessionの一覧）
{
    "key": "ctrl+s",
    "command": "workbench.action.terminal.findNext",
},

```

これで少なくともペインとウィンドウの切り替えはそれっぽく模倣できましたが、tmuxはそもそもsessionが扱えるのが便利なんですが