OmniAICreator/Qiita-1.07M huggingface dataset:
再帰的 zip

# はじめに
`numpy.ndarray`には [ファンシーインデックス](https://qiita.com/python_walker/items/a0b337b05b458644eb33) という仕組みがある．大変便利であるが，インデックスの入れ子構造が私の直感と逆で使いにくい．例として，先の記事から次のコードを引用しよう．

```python3
import numpy as np

a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
a[[0, 1], [2, 2]] #=> [3, 6]
```

これ，`[0, 2]`要素と`[1, 2]`要素を抜き出すためのインデックスが `([0, 1], [2, 2])` なのであるが，私は `a[[0, 2], [1, 2]]` と書きたい (まあ，多分ブロードキャストやスライスと併用したいからこの入れ子順なんだろうけど，私は直感的に書きたいのだ)．このような入れ子の入れ替えには [zip 関数](https://docs.python.org/ja/3/library/functions.html#zip) が利用できる：

```python3
a[tuple(zip([0, 2], [1, 2]))] #=> array([3, 6])
# zip オブジェクトは直接インデックスにできないので，tuple をかけている
```

しかし，`numpy.ndarray`はより高階のテンソルである場合もあり，単純な`zip`では済まないこともあるので，再帰的に入れ替えていくような関数がほしい．

# 実装
要件を言語化するのが難しいので，試行錯誤の結果を先に示そう．

```python3
import collections

def deepzip(*x):
  if isinstance(x[0][0], collections.abc.Iterable):
    return zip(*map(lambda y: deepzip(*y), x))
  else:
    return zip(*x)
def invert_index(idx):
  return tuple(deepzip(*idx))

a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
a[invert_index(([[0, 2], [1, 2]], [[1, 0], [1, 1]]))] #=> array([[3, 6], [4, 5]])
```

`Iterable`かどうかで判定しているので，インデックスがリストじゃなくてタプルや`ndarray`でもOK．`x[0][0]`はキモいが，深さが揃ってないとかの不正処理は省略した．入力，出力ともに (整合していれば) 好きな階数でいける……はず．

上手く行かないパターンとか，こうした方がいいとかあったら教えて下さい．
Expressのルーティングのパスに正規表現を使う

## ルーティングのパスに正規表現を使う

検証せずに数値（文字列）であることが保証できるので、ルーティングが太ることを回避できます。

``` xxx.ts
router.get("/students/:studentId([1-9]\\d*)", (req: Req, res: Res, next: Next) => {
    const studentId = req.params.studentId;
    const student = await studentsService.find(studentId);
    res.render("students/detail", {
        student,
    });
})
```

ルーティングの正規表現を試したい場合は、以下のサイトがオススメです。

[Express Route Tester](http://forbeslindesay.github.io/express-route-tester/)

##
PHP クオーテーションについて

## クオーテーションの使い分け
phpではシングルクオーテーション「'」とダブルクオーテーション「"」は基本的に自由に使い分けることができます。

```test.php
<?php
	print('Hello World');
	print("Hello World");
?>
```

しかし次のような記述をしたい場合は使い分ける必要があります。
phpが「'」を文章の一部なのか、記号なのか判断できないのが理由です。

```test2.php
<?php
	print('I'm studying'); // エラーとなる書き方

	print("I'm studying"); // 「'」が文字の一部として判断される書きかた
?>
```

また、「"」の場合は変数展開されます。
変数の前後に半角スペースを入れることで変数展開されます。

```test3.php
<?php
	$name = "masuda";
	print('わたしの名前は $name です'); // $nameがそのまま文字列で表示される	
	print("わたしの名前は $name です"); // masudaと表示される
?>
```

変数展開は{}で囲うことで表すこともできます。

```test4.php
<?php
	$name = "masuda";
	print("わたしの名前は{$name}です");
?>
```
### 処理速度について
一般的にはシングルクオートの方が処理速度が速いと言われています。
実際に計測してみました。

```test5.php
<?php
	$time_start = microtime(true);

	for($i = 0; $i <= 1000000; $i++) {
		$str = 'abcdefghijklmnopqrstuvwxyz'; // 「'」,「"」それぞれで計測
	}

	$time = microtime(true) - $time_start;
	echo "{$time} 秒";
?>
```

シングルクオーテーションの結果

```
// 1回目
0.020727872848511 秒

// 2回目
0.020267009735107 秒

// 3回目
0.020632982254028 秒

// 4回目
0.023839950561523 秒

// 平均
0.0213669538498 秒
```

ダブルクオーテーションの結果

```
// 1回目
0.021567106246948 秒

// 2回目
0.023807048797607 秒

// 3回目
0.020891904830933 秒

// 4回目
0.020187139511108 秒

// 平均
 0.0216132998466 秒
```

平均を見るとシングルクオーテーションの方がほんのわずかに早いですが、有意な差は出ませんでした。
試行回数が足りず正確な計測は出来ていませんが、好きな方を使ってもいいと思います。
複数ファイルをsortしたときに元のファイル名もつけておきたい

# 複数のファイルをまとめてsortしたい

下記のように、地域別の複数のtsvファイルがあり、その中には年月に対する何らかの件数が入っていたとします。

```bash
% ls
中国.tsv	中部.tsv	九州.tsv	四国.tsv	東京.tsv	東北.tsv	近畿.tsv	関東.tsv	北海道.tsv

% head *
==> 中国.tsv <==
2019/12	26
2019/11	26
2019/10	30
2019/9	20
2019/8	28
2019/7	12
2019/6	16
2019/5	6
2019/4	22
2019/3	22

==> 中部.tsv <==
2019/12	43
2019/11	37
2019/10	42
2019/9	39
2019/8	36
2019/7	32
2019/6	24
2019/5	36
2019/4	35
2019/3	29

...
```

この複数のファイルに対して、件数が小さいもの10個を表示したいと思います。

# sortコマンドだと元のファイル名がわからない

普通にsortコマンドを複数ファイルに対して実行すると、結果を見ても元のファイル名がわかりません。

```bash
% sort -k 2 -n * | head
2019/2	4
2019/1	5
2019/5	5
2019/5	6
2019/7	7
2019/6	8
2019/2	9
2019/3	9
2019/3	9
2019/3	10
```

# grep & sort で解決

こういう時は、grepコマンドを通してからsortしましょう。そうするとファイル名を各行の先頭につけることができます。

```bash
% grep . * | sort -k 2 -n | head
北海道.tsv:2019/2	4
東京.tsv:2019/5	5
北海道.tsv:2019/1	5
中国.tsv:2019/5	6
東京.tsv:2019/7	7
東京.tsv:2019/6	8
東京.tsv:2019/2	9
四国.tsv:2019/3	9
東京.tsv:2019/3	9
四国.tsv:2019/5	10
```

## 何でgrepをつけるといいのか

何でこうできるかというと、grepを通すとその結果にファイル名がつくからですね。
今回はgrepで行を絞りたくはないので、全ての行にヒットするように `grep .` にしています。

```bash
% grep . *
中国.tsv:2019/12	26
中国.tsv:2019/11	26
中国.tsv:2019/10	30
中国.tsv:2019/9	20
中国.tsv:2019/8	28
中国.tsv:2019/7	12
中国.tsv:2019/6	16
中国.tsv:2019/5	6
中国.tsv:2019/4	22
中国.tsv:2019/3	22
中国.tsv:2019/2	20
中国.tsv:2019/1	23
中部.tsv:2019/12	43
中部.tsv:2019/11	37
中部.tsv:2019/10	42
中部.tsv:2019/9	39
中部.tsv:2019/8	36
中部.tsv:2019/7	32
中部.tsv:2019/6	24
中部.tsv:2019/5	36
中部.tsv:2019/4	35
中部.tsv:2019/3	29
中部.tsv:2019/2	27
中部.tsv:2019/1	31
...
```

実は `grep .` は空白行を無視してしまいますが、今回のような設定の場合は問題ないですよね。
あ、あと、 `grep -H` を暗黙的に使っています。

# 参考

https://teratail.com/questions/31594#reply-49888
[Java]新仕様のYahoo!商品検索API実装

Yahoo!の商品検索APIが新仕様になるのでメモ。
https://developer.yahoo.co.jp/webapi/shopping/shopping/v3/itemsearch.html

検索ワードのエンコードが必要になり、JSONの構造が変わりました。
JSONを扱うためにJacksonを利用します。導入は各自で調べてください。

##やること
1.HTMLから受け取った検索ワードをAPIに送る。
2.JSONを受け取り必要な情報を抜き出してフォワードする。

###1.HTMLから受け取った検索ワードをAPIに送る。
旧仕様からの変更点として、UTF-8エンコードが必要になりました。

```java:java
//アプリケーションID
final String appID = "アプリケーションID";

//検索ワードをUTF-8エンコード
String query = request.getParameter("searchWord");
String encodedQuery = URLEncoder.encode(query, "UTF-8");

//URL作成
String url = "https://shopping.yahooapis.jp/ShoppingWebService/V3/itemSearch"
               + "?appid=" + appID + "&query=" + encodedQuery;
URL conUrl = new URL(url);

//接続
HttpURLConnection con = (HttpURLConnection)conUrl.openConnection();
con.connect();

```


###2.JSONを受け取り必要な情報を抜き出してフォワードする。
JSONの構造が旧仕様と異なるので注意。
今回は検索結果から先頭10件の商品名と値段を抜き出します。


```java:java
//json文字列の読み取り
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
String json = br.readLine();
br.close();

//json文字列をJsonNodeに変換
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(json);

//JavaBeansを格納するArrayList
ArrayList<DataBeans> list = new ArrayList<>();

//10件分の情報を取り出してリストに格納
for(int i = 0; i < 10; i++){
  //hitsのvalueは配列なので整数で要素番号を指定する
  String name = node.get("hits").get(i).get("name").textValue();
  int price = node.get("hits").get(i).get("price").asInt();
  
  //情報をJavaBeansにセット
  DataBeans bean = new DataBeans();
  bean.setName(name);
  bean.setPrice(price);

  list.add(bean);
}
request.setAttribute("resultData", list);
request.getRequestDispatcher("searchResult.jsp").forward(request, response);
```
【GCS】gsutil rmコマンドの処理時間について

## はじめに
GCSのオブジェクトを gsutilコマンドで削除することがあったので、以前から気になっていた処理速度について以下の2点を検証しました。

1.  **処理速度はオブジェクト数とサイズ、どちらに影響されるのか？**
2.  **-m (マルチスレッド処理) は有効なのか？**

今回の検証はとてもざっくりとしたもので、上記の2点を確認することだけを目的としています。
ですので、比較対象や条件、計測方法などは精密ではないのでご了承ください。

## 結論
A. オブジェクト数
>1. 処理速度はオブジェクト数とサイズ、どちらに影響されるのか？

A. 有効
>2. -m (マルチスレッド処理) は有効なのか？

## 検証
### 処理速度はオブジェクト数とサイズ、どちらに影響されるのか？

使用したコマンドは以下の通りです。

```common-lisp
$ gsutil rm -r gs://バケット名
```
　
3つのバケットを削除しました。各バケットのオブジェクト数とサイズ、処理時間を以下に示します。

||オブジェクト数 (個) |サイズ (GB) |処理時間 (秒)|
|---|--:|--:|--:|
|バケットA |316 |1.17 |8 |
|バケットB |310 |5.73 |7 |
|バケットC |1091 |15.12 |23 |

バケットAとバケットBを比較すると、オブジェクト数はほぼ同じで、サイズが5倍ほど差があります。
しかし処理時間についてはほとんど変わりません。
このことから、処理時間はオブジェクト数に影響されることがわかります。

パターンAとパターンCを比較すると、オブジェクト数の差は3倍ほどあり、処理時間も3倍ほど差があります。
処理時間はオブジェクト数に比例することが示唆されます。

一方で、処理時間とサイズについては特に関係がなさそうです。

以上のことから、**処理速度はオブジェクト数とサイズ、どちらに影響されるのか？** の問いに対しては、**オブジェクト数である** と答えられそうです。


### -m (マルチスレッド処理) は有効なのか？
先ほども使用したコマンドに -mオプションの有無で検証しました。

-m オプションなし

```common-lisp
$ gsutil rm -r gs://バケット名
```

-m オプションあり

```common-lisp
$ gsutil -m rm -r gs://バケット名
```

　
結果は以下の通りです。

||-m オプション |オブジェクト数 (個) |サイズ (GB) |処理時間 (秒)|
|---|---|--:|--:|--:|
|パターンD |なし |154 |2.14 |5 |
|パターンE| あり |154  |2.14 |2 |

パターンDとパターンEで、オブジェクト数とサイズは同じです。
処理時間を見ると 2.5倍差があります。


別のパターンでも検証してみました。

||-m オプション |オブジェクト数 (個) |サイズ (MB) |処理時間 (秒)|
|---|---|--:|--:|--:|
|パターンF |なし |200|521 |6 |
|パターンG| あり |200|521 |2 |

こちらもオブジェクト数とサイズは同じで、処理時間には 3倍差がありました。

以上のことから -mオプションの有無で 2.5～3倍ほど処理時間に差があることが示唆されました。

**-m (マルチスレッド処理) は有効なのか？** という問いに対しては、有効であると答えることができます。

## 最後に
はじめにも書いたように、今回の検証はとてもざっくりしたもので数値に関しては参考程度です。
もちろん、サーバのスペック等ほかの要因でも結果は変わりますし。
(GCSの整理しなきゃいけないしついでに計測してみるか、ぐらいの感じで始めたので...)

ただ gsutilコマンドで GCSのオブジェクトを削除する際に、オブジェクト数が処理時間に影響すること、-mオプションで処理時間を大きく短縮できることがわかっていれば役に立つと思います。

もし自分と同じことに疑問を感じている人がいたら参考にしていただければと思います。

時間があるときにちゃんとベンチマークを測定しよう。。
クラスとインスタントpart2

##前提として

メソッドには２種類
・Rubyに用意されてるもの(gets/puts/chomp/to_iなど）
・自分で作るもの
に分かれる

##クラス

どういうプログラムを作るか、大枠をイメージしたもの
・クラス名
・クラスメソッド
・クラス変数
を峻別して考えましょうね
（峻別できてなかったわよ）

クラスメソッドを作るときは、
共通される処理を繰り返したり、カウントアップするときに使える

##インスタンス
インスタンス変数は個別の処理がなされるので
インスタンス生成は個別に仕分けた処理をしたい時に作る

##self./@/@@/initialize

self.
→クラスメソッド

@
→インスタンス変数

@@
→クラス変数

initialize
→初期設定したいところはここで
msitools の Ubuntu 18.04 でのビルドメモ

.msi ファイルを Linux で扱うツールです.

Ubuntu だととりあえず apt で入りますが, 最新版をビルドして使いたいときもあります.
たとえば, 最新 Windows SDK の展開には msitools v0.100 がいります. Ubuntu 20.04 は v0.100 ですが, 18.04 は v0.97 どまりです.

ただ, v0.100 でも一部壊れるファイルがありました. lessmsi を使うのがよいでしょう.

WINE で lessmsi で msi ファイルを展開する
https://qiita.com/syoyo/items/520bd0fe19c44afeda8b


## 環境

Ubuntu 18.04(x86_64) を想定します.

## 手順

何故か無駄に GNOME 関連のライブラリに依存していてつらい :cry:

msitools は libgfs-1 に依存しています.
ただ, これはなぜか x86 では apt には存在しません
(apt search libgfs だと, fluid flow solver が選ばれてしまう)

まずは libgfs をビルドします.

https://gitlab.gnome.org/GNOME/libgsf

gtkdocize, autopoint を求められるので, まずこれらを apt で入れます.
(gtkdocize はドキュメント関連用っぽいので無視できそうだが, 細かく調べるのめんどいのでとりあえずおとなしく使うようにする)

```
$ sudo apt install gtk-doc-tools
$ sudo apt install autopoint
```

`$HOME/local` にインストールするものとします.

```
$ ./autogen.sh
$ ./configure --prefix=$HOME/local
$ make
$ make install
```

### msitools 

https://wiki.gnome.org/msitools


から 0.100 の tar.gz を取得します.

いくつか依存パッケージを先に apt で入れます.
msitools を一度 configure してから依存パッケージいれると, 

```
./configure: line 13820: `GOBJECT_INTROSPECTION_CHECK(0.9.4)'
```

などとうまくいかないので注意です.

```
$ sudo apt install uuid-dev libgcab-dev
$ sudo apt install gobject-introspection
```

libgfs をインストールしたパスの `lib/pkgconfig` に `PKG_CONFIG_PATH` を通します.

```
$ PKG_CONFIG_PATH=$HOME/local/lib/pkgconfig ./configure --prefix=$HOME/local
$ make
$ make install
```

あとは `$HOME/local/bin` に PATH を通して完成です :tada:

#### git repo からビルド

https://github.com/GNOME/msitools

git repo では, ビルドシステムが meson に移行しています(そしてビルドドキュメントがない!)
とりあえず meson でセットアップして, いろいろ依存するものを apt で入れればコンパイルできます.
ただ, meson install だと libmsi.so をコピーしてくれませんので, 手動でコピーしておきます.
sorceryでtwitterログイン実装中に出会したエラーあれこれ

##前提

```Rails 6.0.3.1```
```ruby 2.6.3```
```sorcery (0.15.0)```
***
sorceryでtwitterログイン認証を実装していたのですが、エラーに四苦八苦していたので、特に苦しめられたエラーについて記録として残そうと思います。

##ActiveSupport::MessageEncryptor::InvalidMessage

```credentials.yml.enc```にtwitterの```key```と```sercret key
```を直書きしていました。
###解決策

そもそも```credentials.yml.enc```なるものをきちんと理解していませんでした。
まずは、以下の記事を参照してみました。

[Rails5.2からsecrets.yml*が廃止されcredentials.yml.encに統合されるよ](https://qiita.com/daichirata/items/da40e205d273ae69fcfc)

読みところによると、Rails5.2.0になる前までは、```secrets.yml```とファイルにsercretsなあれこれを**平文**で記述していたみたいですね。

``暗号化済みのもの``が```credentials.yml.enc```では、記載されているようです。
改めて```credentials.yml.enc```中身を改めて確認してみると、意味不明な羅列がされていました。

確かに、暗号化されている所に、
twitterの```key```と```sercret key```を書いていくのは、おかしいなと思いました。

ってことで、上記の記事を参考に以下のコマンドで```credentials.yml.enc```ファイルを編集できることがわかりました。

```vim

EDITOR="vi" bin/rails credentials:edit
```

```vim
twitter:
  key: keyの値
  secret_key: sercret keyの値


```

上の記述を追加しました。
恥ずかしながら、```Vim```の使い方に慣れていないので、以下の記事を参照させていただきなんとか記述が完了致しました。
大変感謝です。
[よく使う Vim のコマンドまとめ](https://qiita.com/hide/items/5bfe5b322872c61a6896)


##undefined method `sorcery_adapter' for nil:NilClass
こちらは、凡ミスですが、ググっている時に全然参照記事がなくて、時間をくってしまいました。

エラーの原因としては、

```config/initializers/sorcery.rb
.
.
.
config.user_config do |user|
.
.
.
#こちらの記述が抜けていました。
user.authentications_class = Authentication
.
.
.
```

sorceryの[wiki](https://github.com/Sorcery/sorcery/wiki/External)にも記述があったのに、飛ばしていました。
今後きちんと、手順を参照したものを真っ先に確認したいと思います。
一応[こちら](https://github.com/Sorcery/sorcery/issues/127)も参照したので、載せておきます。

##401 Authorization Required

こちらのエラーですが、Twitter認証が完了しリダイレクトする際に表示されました。

以下の記事を参考に、一通り試してみたのですがどれもうまくいかず。。
[OAuth::Unauthorized 401 Unauthorizedなんてエラーがでたら](https://qiita.com/hirokishirai/items/5a43977a38ecd922bfb9)

あまり記事がなかったのですが、たまたま以下の記事があったので目を通してみました。
[Twitterログイン 401 Authorization Required](https://qiita.com/hiro266/items/2d6a3e9c103652d88538)
twitterデベロッパーツールの```Callbacks URLs```に```http://127.0.0.1:3000/oauth/callback```を設定したのですが、いつ使うんだろう？と思っていました。


**結論としては、```localhost:3000```にアクセスせず、```http://127.0.0.1:3000/oauth/callback```にアクセスすることでエラーが解消されました。**

##最後に

外部API認証を初めて、行いますがrailsでの知らないファイルの存在やデベロッパーツールなるものにも触れることができ中々収穫ありでした。
またwikiをきちんと読んで、進める経験ができたのもよかったです。

Twitter認証を進める上[wiki](https://github.com/Sorcery/sorcery/wiki/External)で、参考にさせていただいた記事
  
[【Rails】SorceryでTwitter認証]
(https://qiita.com/aiandrox/items/5435c8b285c7dc0c455f#%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88)
[【Rails】Sorceryでfacebook認証　Sorceryの設定](https://qiita.com/aiandrox/items/ca798da0bca617074795#sorceryrb%E3%81%AE%E8%A8%AD%E5%AE%9A)
iOSのショートカットを利用してApple Musicランダム再生を捗らせる

iOSにデフォルトで入ってるアプリ、[ショートカット](https://support.apple.com/ja-jp/guide/shortcuts/welcome/ios)。

これを活用して、ワンタッチでミュージックの好きな範囲から曲をランダム再生する設定がいい感じになったので共有します。

この方法で検索できる範囲は、iTunesで買った楽曲やApple Musicの楽曲、ミュージックに取り込んだ楽曲などの公式のミュージックアプリで聴ける曲限られますので他のアプリに入ってる曲は対象外なのでこの機能を使いたい場合は移動させることをお勧めします。

#必要なもの

- ショートカットに対応したiOS又はiPadOSの入ったデバイス
- ショートカット

#基本的な設定

ショートカットアプリを開いたら、ショートカットを作成→アクションを追加→**メディア**欄から探すか**ミュージック**で検索すると今回使うアクションたちが出てきます。

![16AE1137-21E6-4AC7-8DBB-3680EE818942.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416356/afabab41-ee48-0713-91c3-0fffd1d70338.jpeg)

主に使うのは**ミュージックを検索**、**プレイリストを取得**、**次はこちらへ追加**、**ミュージックを再生**の四つです。

最終的に**次はこちら**に簡易的なプレイリストみたいなものを作る形になります。

##ランダム再生する曲の範囲の指定方法

これは、二種類あって、既存のプレイリストの中から選択する方法と全てのミュージックから検索する方法です。
###プレイリストから選択する方法

**プレイリストを取得**を追加して**プレイリスト**の部分を選択するとプレイリストが選択できるのでプレイリストを選択します。(ここでは一つしか選択できませんが複数選択する方法を後半で紹介します)

そのすぐ下に**ミュージックを検索**を追加します。
並び順序を選択すると様々な方法がありますがランダムは一番下にあるのでこれを選択し、制限をONにすると曲数を指定できます。1時間だと10〜15曲くらいになると思います。

###すべてのミュージックから選択する方法

**ミュージックを検索**を追加してフィルタを追加から検索条件を指定します。指定方法は3つのパーツからなっていて検索するカテゴリ(アーティストや曲名から等)、条件(完全一致や部分一致)、検索するテキストです。ここがうまく使えると色々できます。

並び順序や制限はプレイリストの時と同じように設定します。

##次はこちらへ追加して再生

**ミュージックを検索**の下に**次はこちらに追加**さらにその下に**ミュージックを再生**を追加して完成です。

↓完成例
![8502EBE9-29ED-4FEA-87A7-96A7CAC9A723.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416356/3dc8e770-e79f-dc8f-9664-09d8dc1769f2.jpeg)

完成したらタイトル横の…からホーム画面に追加したらホーム画面からワンタッチでアクセスできるランダム再生アプリの完成です。

ですがここまでだと複数プレイリストやプレイリストと検索の共存ができていないので実用性に欠けます。

#実用的な応用編

複数プレイリストを選択するのはとても簡単です。
ここで使うのは**変数**です。
**変数**で検索したら出てくる**変数に追加**をそれぞれの**ミュージックを検索**の下に追加して同じ変数名を付けます。このときそれぞれの検索したミュージックに制限を設けなくても良いですが、大きく偏りがある場合は検索結果が少ないものは選ばれづらくなるので、制限を少ないものに合わせると良い感じに混ざります。

最後の変数の下にさらに**ミュージックを検索**を置いて並び順序をランダムにした後は、**次はこちらへ追加**と**ミュージックを再生**を追加すれば完成です。

長い長い完成例↓
![D5B9FFDD-737B-4759-9526-0FFE015AFAC5.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416356/21803beb-3d43-6dc3-d660-3605ec1b404f.jpeg)![367A53DB-1134-4ED6-8093-2DFB83EC9658.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416356/badaa318-4219-e8c9-15f6-256787158409.jpeg)![5F44CD32-777D-400C-8C8B-97612165E799.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416356/8b66c2b5-6127-681a-1fdf-aa9081e3d9ab.jpeg)
Spine PS4 Emulator for PC is Making Significant Progress

The PS4 currently has the first emulator for COMPUTER known as Spine PS4 Emulator for PC, although it has a number of disadvantages, as well as the very first of them is that for now it only functions under the Linux os.

One more problem is that although it is already capable of running decent amount of video games, all of them have a high degree of glitches in the form of artefacts and also, obviously, poor performance, so don’t expect to play God of War or Spider-Man in the short-term, considering that the video games shown are graphically extremely standard and also as on extremely advance degree they showcased video game name Broken Sword. This emulator can be downloaded and install currently as a trial from the adhering to web link. 

Get full gist about this mac emulator that can play up to 50 video games @ https://comfortskillz.com/2022/06/sites-like-movie4k.html

![Spine-PS4-emulator-pc.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421559/03088155-3fa1-2a26-b804-d94c0e5759db.jpeg)
ABC 035 D トレジャーハント

##問題
https://atcoder.jp/contests/abc035/tasks/abc035_d
##見た感じ
町1からほかの町に行くとして、2つ以上の町に滞在する場合を調べる意味はなさそう。
なぜなら、2つ以上の町に滞在したとしたら、滞在した町のうち一番時給のいいとこに時間を全振りすればより儲かるので、求める動き方は一つの町に最短で行ってできるだけ長くそこにいて、最短で帰る動き方の中にある。
だから、各町$i$についてそこにいって帰る最短の時間を$t_i$とすると$(t-t_i )*a_i$がその町を使う調べるべき場合の儲けになって、
これが最大な$i$を調べればいい。
##解法
各町$i$について、その町に行く最短の時間$t1_i$は素直なdijkstraで求めれて、そこから帰る最短の時間$t2_i$は矢印を逆にしたdijkstraで求まる。
最後に$(t-t1_i -t2-_i )*a_i$の最大値を調べればいい。
##ソースコード
```c++
const int N_MAX=100005;
int n,m;
ll t,a[N_MAX];
vector<edge> v[N_MAX],vv[N_MAX];

ll  solve(){
    ll d[n+1],dd[n+1];
    priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<pair<ll,int>>> que;
    fill(d,d+n+1,INF18);fill(dd,dd+n+1,INF18);
    d[0]=0;dd[0]=0;
    que.push({0,0});
    while(que.size()){
        auto p=que.top();que.pop();
        int w=p.second;
        if(d[w]<p.first)continue;
        for(auto c:v[w]){
            if(minin(d[c.to],d[w]+c.cost)){
                que.push({d[c.to],c.to});
            }
        }
    }
    que.push({0,0});
    while(que.size()){
        auto p=que.top();que.pop();
        int w=p.second;
        if(dd[w]<p.first)continue;
        for(auto c:vv[w]){
            if(minin(dd[c.to],dd[w]+c.cost)){
                que.push({dd[c.to],c.to});
            }
        }
    }
    ll res=0;
    rep(i,n){
        maxin(res,max(0ll,t-d[i]-dd[i])*a[i]);
    }
    return res;
}

int main(){
    int x,y,z;
    //入力
    cin>>n>>m>>t;
    rep(i,n)cin>>a[i];
    rep(i,m){
        cin>>x>>y>>z;
        v[x-1].pb(edge(y-1,z));
        vv[y-1].pb(edge(x-1,z));
    }
    //処理
    auto ans=solve();
    //出力
    cout << ans <<endl;
}
```
BigQueryで項目名を変更する方法

https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax?hl=ja#select_except

メモ

```sql
SELECT * EXCEPT(column_name1, column_name2), 
column_name1 AS new_column_name1 ,
column_name2 AS new_column_name2
FROM `table_name`
```

実行した結果をテーブルにコピーしたら作成可能

もしくはテーブルを上書きしたい場合は実行前に
「その他」⇒「クエリの設定」
送信先を「クエリ結果の宛先テーブルを設定する」

にすると上書きが可能
vue.js chainWebpack中でソースの文字列を置換する例

# やりたいこと
ソース中にある\_\_PREFIX\_\_を別の文字列に置換する。

# 前提

node.js v12.10.0
vue.js v2.6.11
typescript v3.8.3
string-replace-loader v2.3.0

# 手順
1. string-replace-loaderをいれる。（略）
https://github.com/Va1/string-replace-loader

2. vue.config.jsのchainWebpackを設定する。

```js
// vue.config.js
module.exports = {
    chainWebpack: config => {
    let replaceStr = 'AAA'; // 置換後の文字列。jsonなり環境変数から取得する。
    config.module.rule('replace-str')
        .test(/\.(?:ts|vue|js)$/)
        .before('ts') // tsの前に実行するようにしないと、置換に漏れるファイルあり。
                      // vueの前に実行するとbuildエラー
        .use('string-replace-loader')
        .loader('string-replace-loader')
        .tap( args => {
            return {
                // 複数指定と単一指定では指定方法が異なるので、
                // string-replace-loaderのoptionsを参照する。
                multiple: [
                    { 
                        search: '__PREFIX____',
                        replace: replaceStr ? `${replaceStr}__` : '',
                        flags: 'g'
                    },
                    {
                        search: '__PREFIX__.',
                        replace: replaceStr ? `${replaceStr}.` : '',
                        flags: 'g'
                    }
                ]
            }
        })
        .end();
    }
};
```

動作しなかったら、とりあえずvue --inspectしてjsonに展開された内容を確認する。

```bash
vue inspect --rules
vue inspect --rule replace-str
```

# 参考
https://github.com/Va1/string-replace-loader
https://github.com/neutrinojs/webpack-chain
https://cli.vuejs.org/guide/webpack.html#simple-configuration
Visual Studioでint型のコマンドライン引数を受け取る方法(C++)

# 環境
- Windows 10 Enterprise 2016 LTSB
- Microsoft Visual Studio 2017

# コマンドライン引数の設定
1. ツールバーの「プロジェクト(P)」から一番下の「プロパティ」を選択する．
![スクリーンショット 2020-06-12 16.56.00（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654294/2a79634e-4976-2a99-5ed8-501235879ee2.png)
2. 左側の「構成プロパティ」以下の「デバッグ」を選択し，「コマンド引数」に入力したい引数を記入する．（画像では6と14の二つにしている．）
![スクリーンショット 2020-06-12 16.59.58（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654294/df6e6c72-7feb-3a2f-9138-aa2c2700ebe4.png)
3. 右下の「OK」を押す．（「適用」でも良い）

# 受け取った文字列型の値をint型に変換
- `std::stoi`を使用し文字列型をint型に変換する．
- `std::stoi`は`#include<string>`と`#include<string>`，`using namespace std;`が無いとエラーが出ると思われる．

```
#include <iostream>
#include<string>
using namespace std;

int main(int argc, char* argv[])
{
	int atama, asi; //変数の宣言

	//引数を変数に格納．
	atama = std::stoi(argv[1]);
	asi = std::stoi(argv[2]);

	return 0;
}	
```

# サンプルコード(鶴亀算)
```
#include <iostream>
#include<string>
using namespace std;

int main(int argc, char* argv[])
{
	int atama, asi, turu, kame; //変数の宣言

	//引数を変数に格納．
	atama = std::stoi(argv[1]);
	asi = std::stoi(argv[2]);

	//鶴と亀の数の計算
	turu = 2 * atama - asi / 2;
	kame = atama - turu;

	if (turu < 0 || kame < 0)
	{
		cout << "error" << std::endl;
	}
	else
	{
		cout << "鶴の数：" << turu << std::endl;
		cout << "亀の数：" << kame << std::endl;
	}
	return 0;
}
```
- 引数
    - 6
    - 14
- 実行結果

```
鶴の数：5
亀の数：1

```

# この記事を書いた経緯・感想
- コマンドライン引数を単に`argv[1]`などから受け取ると文字列型になっているのでint型に使用とPythonと同じように`int(argv[1])`などとしたらエラーが出た．
- 適当にC++の型変更方法を調べたら`(int)argv[1]`などというのをどこかで見かけて，やってみたら，エラーは出ないが，引数として受け取った値がおかしい値になった．
- もう一度文字列からint型への変更方法を調べたら`std::stoi`があったのでこれを使ったらできた．

# 参考文献
- https://marycore.jp/prog/cpp/convert-string-to-number/
curlでレスポンスにかかる時間を計測するスクリプト

# curlですぐにapiの時間を計測！

shellで複数回apiを叩いて平均的なレスポンスの時間を取得したいという場合に簡単に使えるスクリプトを書きました
`ENDPOINT`に計測したいapiのurlを書いて、実行するだけです。
実行回数と`API method`, `data` も変数内に記入することができるようにしています


```zsh

$ vim response.sh # お好きなエディタで

...下記のコードを保存...

$ chmod 700 response.sh

$ ./response.sh
```

```bash
#!/bin/bash

# 集計用
TOTAL=0

# custom variables
## curl設定
ENDPOINT="https://xxxxxx/yyyyy"
METHOD="POST"
DATA='{"hoge": "fuga"}'

## 回数
COUNT=10

## 平均の計算で小数点以下何桁まで表示するか
SCALE=10


for ((c=1; c<=$COUNT; c++))
do
  # curlでレスポンスにかかった時間を取得
  TIME=$(curl $ENDPOINT -X $METHOD -d $DATA -s -o /dev/null -w "%{time_starttransfer}\n")
  # 時間を標準出力に表示
  echo "time: $TIME [ms]"

  # 加算する
  TOTAL=`echo "$TOTAL + $TIME" | bc`
done

# 平均を計算
AVG=`echo "scale=$SCALE; $TOTAL / $COUNT" | bc`

# 結果出力
echo "total: $TOTAL [ms]"
echo "avarage: $AVG [ms]"
```
Gitで過去のコミットをまとめる＋ブランチを付け替える方法

#はじめに
（Git初心者なので内容が間違ってても大目に見てください）

ごく稀に（特に一人で作業をしていたり、ローカルで作業したりなど）過去にコミットした内容をまとめたくなる時が出てくると思います。
このような時、通常は`git rebase -i`でコミットをマージしていくのが一般的です。
この辺りの方法は世の中に溢れているので、ググってみてください。
https://qiita.com/tsuuuuu_san/items/f708a9f7ea8ab8eb6945
http://www-creators.com/archives/2850

#困りごと
が、しかし！！まとめたいコミットのツリーの途中にブランチが切られている場合、`git rebase -i`を行うとカオスな状態になってしまいます。
ちょっと何言ってるか分からないと思うので実際の事例を見ていきたいと思います。
<img width="188" alt="スクリーンショット 2020-06-12 16.03.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455347/3c607277-d363-6543-e5b6-23e755320849.png">
今、`master`の最初の方に作られたコミット`add c`と`add d`をまとめたいとします。
なお2個前のコミットで`branch`という名前でブランチが切られています。
この状態で`git rebase -i`を実行してみましょう。

```terminal:terminal
git rebase -i HEAD~5 //5個前まで遡って修正する

pick 5b22e12 add c
squash 0365976 add d //これを直前のコミットと一緒にしたい
pick 591e2e8 add e
pick 804ff18 add f
pick 015ce44 add g

add c and d //という名前にする
```
そうすると結果は…
<img width="188" alt="スクリーンショット 2020-06-12 16.03.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455347/39a955fe-85a0-9ddb-a9e9-6fc389f3eb04.png">

$\Huge{Why\ Git!!!!!!!!}$

#Gitは悪くなかった
本来`add e`でブランチされるはずの`branch`が`add b`でブランチされてしまっています。
一体何が起きているのでしょうか？

実はこれ、`add c`と`add d`がまとめられた`master`のツリーを新たに`add b`に`rebase`しているんです。
`rebase`のやっていることは以下を参考にするとわかりやすいです。
https://www.slideshare.net/kotas/git-15276118
理由は分かったけれど、求めたいた形と違いますね。
そこでbranchの接続元をmasterツリー内の`add e`に接続し直すことで元の状態に戻してあげます。

#救世主 git rebase --onto
ブランチを付け替えるには`git rebase --onto`を使います。
こちらの解説は以下の記事が分かりやすかったです。
https://gist.github.com/hankei6km/4301ebc7e320b987de1f7a5b0acb994a

今やりたいことは、`branch`のコミット名`add f-b`を`master`のコミット名`add e`に付け替えることです。
ここで文法をおさらいすると、
`git rebase --onto A B C`
`A` : 付け替え先のコミット名
`B` : 付け替える前の分岐元のコミット名
`C` : 付け替えたいブランチ名

今回の例に当てはめてみると、
`A` : `master`内の`add e(=3298c46)`
`B` : `branch`内の`add e(=591e2e8)`
`C` : `branch`

となります。では早速実行してみましょう。

```terminal:terminal
git checkout branch //masterからbranchに移動（これが必要かどうかは不明・・・）
git rebase --onto 3298c46 591e2e8 branch
```
結果を見てみると・・・
<img width="188" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455347/01804db2-4278-ca1c-460c-7443dd82fc72.png">
上手くいきました🤗
（branchとmasterの色と場所が変わっているのは目を瞑ってください、GitUpの仕様です）

#最後に
もう少し良い方法がある気がします・・・もし知っている方教えてください。
また、過去のコミットを修正するのはあまり良くないのでは？と思うので使用はほどほどに。
MaterialComponentのAlertDialogのボタンの文字色を変更したい

`AlertDialog.Builder` を使っているところを `MaterialAlertDialogBuilder` に変更して、テキストカラーを変更したThemeをConstructorで渡せば変わります。全てを一括で変更したい場合は `AppTheme` で `materialAlertDialogTheme` に設定すれば色が変わります。

```xml:style.xml
    <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        ...
        <item name="materialAlertDialogTheme">@style/AlertDialogTheme</item>
    </style>


    <style name="AlertDialogTheme" parent="ThemeOverlay.MaterialComponents.MaterialAlertDialog">
        <item name="buttonBarPositiveButtonStyle">@style/Alert.Button</item>
        <item name="buttonBarNegativeButtonStyle">@style/Alert.Button</item>
        <item name="buttonBarNeutralButtonStyle">@style/Alert.Button</item>
    </style>

    <style name="Alert.Button" parent="Widget.MaterialComponents.Button.TextButton">
        <item name="android:textColor">@color/accent</item>
    </style>
```

詳しいパラメータは以下を参照

https://github.com/material-components/material-components-android/blob/master/docs/components/Dialog.md#theming-dialogs
【デバッグ方法】binding.pry（投稿練習）

$\huge{【デバッグ方法】binding.pry}$
について記載します。

Q:そもそも＜binding.pry＞ってなんやねん！
A：Rubyのirbのようにrailsの
コンソールでメソッドなどを使えることができるようになる機能です。

$\huge{【binding.pryの使い方】}$
</FONT>
①コードの処理がどこまでうまく動いてくれているか
②特定のポイントで処理がどうなっているのか

コードの処理を止めて確認したい箇所に
”binding.pry"と打つことで調べることができます。

GemfileにPryを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599566/7306426a-0e05-5295-66cc-13828b8d0c07.png)

その後、bundle install でgemをインストールします。
これでコンソールモードにした時Pryモードになるようになります。

＜pry-rails＞
rails cコマンドでコンソールを立ち上げたとき、
irbでなくPryを起動させることができるgemです。
また、便利なコマンドを実行できるようになります。

$\huge{【Pryを使ってデバッグしてみよう】}$


それではPryはどういったときに使うのでしょうか？
例えば投稿フォームに入力した情報がデータベースに保存されない
というエラーが発生したとします。
そういった場合、原因がどのコードにあるのかをPryを使って確認することができます。

ここで登場するのがbinding.pryです。

$\huge{binding.pry}$

binding.pryという文字列をコード内に記述すると、
そこがブレイクポイントとなりrailsの処理を止めることができます。

では実際にやってみるべし！

＜例＞
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599566/8e5097dc-db99-d873-e7cd-1c0765a2fec3.png)
とこのようなコードがあった場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599566/fb7ef32a-4be6-ea17-bf80-37d431486d43.png)

このように確認したい変数の直後に打ちます。

$\huge{binding.pryでできること}$
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599566/ff6c9a14-06cc-2ffa-9325-96176f5799ee.png)


このpry〜から始まる画面で状態を知りたい変数名を入れることで、
その処理のタイミングでは対象の変数がどんな状態になっているか確認することができます。
また、計算式を入れて確認することもできます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599566/beca9992-3e96-0b61-b354-d6ec7a0241d2.png)


また、計算式を入れて変数の状態を確認することもできます。

少し調べてみて、まだまだ使い方の奥が深いと感じていますので
引き続き勉強していきます。
今日はこのあたりで、失礼します。


＜参考サイト＞
〜変数の中身を確認〜　binding.pryでデバッグする（初心者の方向け）
https://qiita.com/tomoharutsutsumi/items/6b12af3dc5eb8dfb9801
Numpyを使った線形回帰の方法

#はじめに
この記事は筆者がhttps://www.udemy.com/share/1013lqB0AedFdUR34=/
にて学んだことの復習を目的としています
# 書くこと
- 最小二乗法の軽い導出
- pandasのDataFrameからnumpyのarrayに変換して計算してみる

# 最小二乗法の導出
あるデータセット[x, y]が与えられてるとします。
xは説明変数でyは目的変数。例えば、身長が増えれば体重が増えるのでこの場合x=身長、y=体重となる。

そして与えられたデータxからyを予測したい。そのときの予測値を$\hat{y}$とし、以下のような関係式と仮定する。

```math
\hat{y} = ax + b
```

ここで$\hat{y}$を正解値$y$に限りなく近づけることが目標になる。よって

```math
Error = y - \hat{y} = y - ax + b =0
```
となるa,bを探すことが大切になる。
これ以降の説明は以下のリンクから見てください。
http://arduinopid.web.fc2.com/P7.html

# numpyを用いた線形回帰
まずモジュールのインポート

```python:
import pandas as pd
from pandas import Series, DataFrame
import numpy as np

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('whitegrid')
%matplotlib inline

```
あと今回用いるデータセットをダウンロードする

```python:
from sklearn.datasets import load_boston

boston = load_boston()
```
今回はこのデータフレーム内のRM(average number of rooms per dwelling)とtarget(Price)を使います。本来はsns.pairplotやsns.jointplotなどを用いて線形回帰（比例）の関係がありそうな変数を探しますが、今回はあらかじめこの二つの変数には比例関係があるとします。

```python:
boston_df = DataFrame(boston.data)
#列名をつける
boston_df.columns = boston.feature_names
#targetじゃわかりづらいので新たに列をコピー
boston_df['Price'] = boston.target
#散布図と回帰直線の表示
sns.lmplot('RM', 'Price', data=boston_df)

```

![b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392111/5f8c4a03-dbbd-10fb-df52-84c1f6a606ed.png)

この回帰直線を計算で出そう。
使うのはnp.linalg.lstsq(X, Y)。
ただ、このXには特定の形を持ったアレイが必要なのでそのために成形する。

```python:
X = boston_df.RM
Y = boston_df.Price
#[x,1]の形にする
X = np.array([ [value[0], 1] for value in X])
#浮動小数点の型に変換
X = X.astype(np.float64)
#a, bにそれぞれの予測値が格納される
a, b = np.linalg.lstsq(X, Y)[0]
```

これで計算は終わり。結果を見てみよう

```python:
plt.plot(boston_df.RM, boston_df.Price, 'o')
x = boston_df.RM
plt.plot(x, a*x+b, 'r')
```
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392111/07523249-7972-c566-f8a0-cf730fea81d6.png)

#np.linalg.lstsqについて補足
公式ドキュメントはこちら
https://numpy.org/doc/stable/reference/generated/numpy.linalg.lstsq.html#numpy.linalg.lstsq

**numpy.linalg.lstsq(a, b, rcond='warn')**

- パラメータ
-- 係数行列a（M, N）、独立変数b（M,）or （M, K）、rcond
- 戻り値
-- 最小二乗解p, 残差の合計residues, 係数行列aのランクrank, aのsingular value

np.linalg.lstsq(X, Y)[1]とすれば残差の合計も取り出せる
Flutterのリファクタリングに使えそうなDart文法

Qiita初投稿です。

タイトルにもある通りFlutterのリファクタリング等に使えそうな?Dartの文法について書いていきます。

### 1. ```?:```  

よくある3項演算子です。
bool型である変数```a```に対して


```dart
if(a) {
  print("a");
}else{
  print("b");
} 
```
こんなコードがあったときに 
 
```dart
a ? print("a") : print("b");   
```
上記のように書くことができます。  
FlutterではWidgetをreturnするときとかなどに用いることがあるかと思います。

```dart
return loading ? Loading() : Home();
```
    


### 2. ```??```  

変数に異なる値を代入をするときに用いるやつです。

```dart
String name = user.name ?? "anon";  
```
    
とすることで
nameにuser.nameがnullだったときに"anon"という文字列を代入することができます。
この記述をif文とか3項演算子とか使って書くと記述量が増えるのでとても便利だなと思います。

### 3. ```?.```

こちらも先ほどに似ておりフィールドがnull出なかったときにその値を返し、そうでない場合にはnullを返します。
よって以下のようになります。

```dart
class User  {
      String name;
      int age;
      User( this.name, this.age );
    }

    User user;

    int age = user.age; //error
    int age = user.age ?? 0; //error
    int age = user.?age ?? 0; //OK
```
    

### 4. ```??=```
左側の変数がnullであったときのみ代入を行ます。
よって以下のような挙動をします。
rubyでいうところの```||=```と同じです。

```dart
int age;
//ageはnullなので代入される
age ??= 100;

//ageはnullでないため代入されない。
age ??= 50;

print(age) //100
```



### 5. ```..```(カスケード表記)

```dart
User user = new User();
user.name = "tom";
user.age = 30;
```
上記のようながあった場合に

```dart
User user = new User()
   ..name = "30"
    ..age = 30;
```
と記述することができます。

FlutterではSnackBarの表示の時に

```dart
Scaffold.of(context)
       ..removeCurrentSnackBar()
       ..showSnackBar(SnackBar(content: Text("aaa")));
```
...とこんな感じで使うことがありました。
カスケード表記に関しては他の方がいろいろ書いているので調べるといろいろでてきます。

### 6. ```...```(スプレッド構文)
JSとかにもありますね。
ある配列に対して、下記のように記述することが可能です。

```dart
List<int> list = [3,4,5,6,7];

list = [
  1,
  2,
  ...list
];
// list = [1,2,3,4,5,6,7];
```

### 参考

[Simple And Bug-Free Code With Dart Operators](https://medium.com/flutter-community/simple-and-bug-free-code-with-dart-operators-2e81211cecfe)
コードエディタのフォントを開発者向け書体 JetBrains Monoに変えた


# 概要
開発環境のフォントを [JetBrains Mono](https://www.jetbrains.com/ja-jp/lp/mono/)に変更しました。こういうポイントをしっかり考えてくれてうれしい。

>私たち開発者は一日の大部分をコードを見て過ごします。 そのため、画面上のテキストを見やすくするために常に最適なフォントを探していても不思議ではありません。 しかし、多くの一般的なフォントのロジックでは、コードを読む場合と書籍を読む場合の違いが考慮されているとは限りません。 私たちの目はさまざまな方法でコードを追います。コードを横方向に読むのと同じくらい縦に読む必要があることもしばしばです。これは文章に沿って常に同じ方向に目を走らせる読書とは対照的なものです

> 何よりもまず長時間コーディングを行う際に目の疲れを引き起こす可能性のある問題に注力しました。 このフォントを開発する際には文字の大きさや形、文字間のスペースの量、等幅フォントで自然に設計したバランス、不要な細部、判りにくい文字の違い（Iやlなど）、合字のプログラミングなどを考慮しました

出典：https://blog.jetbrains.com/jp/2020/02/19/2825

# Before

従来はconsolasつかってた。おなじみの等幅フォント。これも悪くは無い。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170905/961832fd-2caa-8ea3-f4d1-d08a5fece5d7.png)

# After

JetBrainsが自信満々で送り出してきた**Jetbrains Mono**。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170905/42112028-aa40-b0f9-5f94-e0f19744d008.png)

# WebStormで変更する方法

### Before

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170905/fb630401-9968-1130-f6ad-7b6436a7ff92.png)
（全角日本語フォントもへんだけど、それはここでは無関係。）

### After
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170905/d127269b-3174-4170-daa1-86707b1d7f2b.png)

（日本語フォントもついでになおした、それはここでは無関係。）

WebStormの場合は Editor > Font で JetBrains Monoを選べばいい。最新のWebStormなら選択済らしい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170905/90ed09fe-722d-f5d0-ee1c-e96e5cfae2b9.png)
AmazonLinux2 Nginx+PHP-fpm環境構築メモ

# はじめに
表題の構成で作った際の手順メモ。

# 手順

## 初期設定

```
# パッケージ更新
$ sudo yum update -y

# タイムゾーン変更
$ timedatectl status
$ sudo timedatectl set-timezone Asia/Tokyo

# 日本語ロケール追加
$ localectl status
$ sudo localectl set-locale LANG=ja_JP.UTF-8
$ sudo localectl set-keymap jp106
```

## nginxインストール

```
# 対象確認
$ amazon-linux-extras list
$ amazon-linux-extras info nginx1

# インストール
$ sudo amazon-linux-extras install nginx1

# インストール確認
$ nginx -v
```

## phpインストール

```
# 対象確認
$ amazon-linux-extras list
$ amazon-linux-extras info php7.4

# インストール
$ sudo amazon-linux-extras install php7.4

# 動作確認
$ php --version
PHP 7.4.5 (cli) (built: Apr 23 2020 00:10:21) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
```

## php.ini書き換え

```
# HTTPヘッダへのPHPバージョン記載をOFF
# expose_php = On
expose_php = Off

# 念のためメモリ上限をアップ
# memory_limit = 128M
memory_limit = 256M

# POST送信許容サイズアップ
# post_max_size = 8M
post_max_size = 16M

# アップロード許容サイズアップ
# upload_max_filesize = 2M
upload_max_filesize = 16M

# timezoneの設定
# date.timezone =
date.timezone = Asia/Tokyo
```

## php-fpm自動起動設定
```
$ sudo systemctl start php-fpm.service
$ sudo systemctl enable php-fpm.service
$ systemctl status php-fpm.service
```

## UNIXドメインソケット接続設定

### nginxとphp-fpmのUNIXドメインソケット接続確認

```
$ netstat -al --protocol=unix | egrep "Proto|fpm"
Proto RefCnt Flags       Type       State         I-Node   Path
unix  2      [ ACC ]     STREAM     LISTENING     1486761  /run/php-fpm/www.sock
```

### www.confを編集

```
# www.conf編集
$ sudo vim /etc/php-fpm.d/www.conf

# 以下のような形で編集
- user = apache
+ user = nginx
- group = apache
+ group = nginx

#php-fpm再起動
$ sudo systemctl restart php-fpm.service
```

### 接続確認

```
# スーパーユーザーへ切替
$ sudo su

#接続確認用phpファイル追加
$ echo '<?php phpinfo(); ?>' > /usr/share/nginx/html/phpinfo.php

#ブラウザ確認
$ パブリックDNS/phpinfo.php
```

## 参考にさせていただいたページ
https://ninolog.com/set-amazonlinux2-aws-ec2/
https://qiita.com/2no553/items/968068b1752ea6154beb
SearchViewを利用したListView内の部分一致検索

###最初に
今回はSearchViewについて色々調べていたところ
意外とKotlinでのサイトが少なかったのともっと簡単にできそうだなというのがいくつかあったので備忘録として投稿させていただきます
##ビュー
SearchViewの実装自体はすごく簡単でした

```fragment_main.xml

<androidx.appcompat.widget.SearchView
        android:id="@+id/search"
        android:layout_width="0dp"
        android:layout_height="32dp"
        android:background="@color/colorPrimary"
        android:layout_marginTop="24dp"
        android:layoutDirection="rtl"
        app:searchHintIcon="@null"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
```
これだけです
**layoutDirection**は検索アイコンの位置を指定しています
今回は右寄せにしてありますデフォルトでは左寄せになっています
**searchHintIcon**は検索を開始した際のヒントの部分のアイコンをどうするかの設定です今回はなしにしたいので@nullにしました

ListViewは配置すればいいだけでコードがメインなので省略させていただきます

#コード

```MainFragment.kt

private fun search(){
    val search = search
    val list = list
    val data = arrayOf("one","two","three","foo","five","six","seven","eight","nine","ten","eleven","twenty")
    var filter = arrayListOf<String>()
    val adapter = ArrayAdapter(requireContext(),android.R.layout.simple_list_item_1,data)
    val result = ArrayAdapter(requireContext(),android.R.layout.simple_list_item_1,filter)

    list.adapter = adapter

    search.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
        override fun onQueryTextSubmit(query: String?): Boolean {
            return false
        }

        override fun onQueryTextChange(newText: String?): Boolean {
            val regex = Regex(newText.toString())
            result.clear()
            for (item in data.indices){
                if (regex.containsMatchIn(data[item])){
                    filter.add(data[item])
                }
            }
            list.adapter = result
            adapter.notifyDataSetChanged()
            return true
        }

    })
}
```
SearchViewには**setOnQueryTextListener**というイベントリスナーがあります
**onQueryTextChange**は入力文字が変更されるたびに呼び出されるメソッドです
**onQueryTextSubmit**は検索ボタンを押された際に呼び出されるメソッドです
検索結果を表示させたいタイミングによって処理を書くメソッドを変えるといいと思います

#説明
処理自体も至ってシンプルです
**Regex**に入力された文字を代入してあげてそれをリストの中身と順番に比較していき別のArrayに追加してあげて表示させます
**result.clear()**を呼んであげないと前回の文字列での検索結果が残ったままになってしまうのでそのつどにclearをしてあげてください
**regex.containsMatchIn()**がない場合部分一致ではなくなってしまうのでご注意ください

##最後に
今回はSearchViewを調べていたところもっとも使うであろうListViewでの実装や部分一致検索などがあまり詳しくは書いてなかったのでビギナーの方々に役立てばと思い書かせていただきました
次は何になるかはわかりませんが備忘録兼ビギナーのための何かになれば幸いです
VSCodeを導入(ローカル&リモート)

エディタ何使う？っていう話で、某Slackに上がっていた内容を中心にまとめました。
(みなさまありがとうございます）

## 導入のきっかけ
最近のVSCodeは、

- リモートssh先もローカル同じように操作できる
- Jupyter notebookも開ける

という情報を耳にして、これはよさそうだ！と、ついに導入を決めました。

linux初心者がサーバでの作業をはじめるときに、エディタの操作に慣れないことも障壁のひとつだよなあと思っていました（というか、私自身がそうでした）ので、ローカルと同じGUIというのは、かなりアドバンテージなのでは。

## インストール 
ここからもらってきました。
https://azure.microsoft.com/ja-jp/products/visual-studio-code/

Macの場合: 解凍したアプリを（別にどこでもいいんだけれど、）`/Applications`におきます。

## 設定ファイルの場所を確認
必須ではないけれど、一応確認してみた。
詳細は、以下を参照。
[(随時更新) VSCodeの各種設定ファイルの格納場所備忘録メモ](https://qiita.com/y-vectorfield/items/f9df044981ef29083318)

## GitHubを使えるようにする
https://qiita.com/kai_kou/items/ceeee47996339e5eecc4
この辺の記事を参照。よりよい記事があったらコメント付与お願いします。

## ssh先でも使えるようにする
めっちゃ簡単でした。感動。
詳細は、以下を参照。
[【設定爆速】VS CodeのRemote Developmentを使ってSSH接続したEC2上のファイルを編集する](https://dev.classmethod.jp/articles/vs-code-remote-development-ec2)
[VSCode公式の機能で、リモートサーバにSSHして編集する【Insiders Preview】](https://qiita.com/suzuki_sh/items/245b9817536eba808842)

リモートサーバのホームディレクトリに`~/.vscode-server`というディレクトリが新たにできます（勝手につくってくれます）。

拡張機能は、改めて入れましょう。

## ターミナルから起動できるようにする
ターミナルで`code [filname]`と打ったら、VSCodeで開けるようにします。
詳細は、以下を参照。
[ターミナルからVisual Studio Codeを起動する方法【公式の方法】](https://qiita.com/naru0504/items/c2ed8869ffbf7682cf5c)

リモート先でも`code`コマンドを使えるようにするには、拡張機能[Cloud Code](https://cloud.google.com/code)を入れます。

## VSCodeのターミナル上でコマンド打ったらsshできるようにする
従来のターミナルで`ssh`とうつのと同じようにしたい。
以下のスクリプトをコピペして実行権限を与える(`chmod`)だけでok
[codeコマンドでVisual Studio Codeを起動と同時にSSHリモート接続する方法](https://qiita.com/miyanaga/items/968b857d9b88c1c61960)

## Jupyter notebookを使えるようにする
これも便利！感動。（ただしちょっと遅い）
詳細は、以下を参照。
[VS CodeのPython拡張がJupyterをネイティブサポートしたそうなので早速使ってみた。](https://qiita.com/simonritchie/items/5d865e72dba47cf8f6c0)

リモート先にも拡張機能[python](https://marketplace.visualstudio.com/items?itemName=ms-python.python)を入れれば、使えます。（ただし、結構遅い）

## X Windowの設定 (Macの話)
VSCodeのターミナル上で`xeyes`と打つと、エラーになりました。

```bash:
Error: Can't open display: 
```

`echo $DISPLAY`してみたら、何も設定されていない！
Macのターミナル上で`echo $DISPLAY`すれば、

```bash:
/private/tmp/com.apple.launchd.fOlKOspQYb/org.macosforge.xquartz:0
```
となっていたので、これをVSCode上でも設定してあげば、Xが飛ばせるように。というわけで、`.bashrc`に追記しました。

```bash:~/.bashrc
export DISPLAY=/private/tmp/com.apple.launchd.fOlKOspQYb/org.macosforge.xquartz:0
```

ssh先のサーバでも、同じ手順で設定をしました。
AmazonLinux2に最新のGitをインストールする方法

## はじめに
AmazonLinux2で環境構築する中で最新のgitを利用したかったので備忘のため。

## 手順
### 利用するライブラリをインストール

```
sudo yum -y install gcc curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-ExtUtils-MakeMaker autoconf
```

### インストール対象確認
https://mirrors.edge.kernel.org/pub/software/scm/git/
上記のリストからインストールしたい対象URLをコピーする。

### Gitパッケージダウンロード

```
# 適当なディレクトリでGitパッケージをダウンロード
sudo wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.27.0.tar.gz

# ファイル解凍
sudo tar xzvf git-2.27.0.tar.gz

# 不要ファイル削除
sudo rm -rf git-2.27.0.tar.gz
```

### Gitインストール
```
# 解凍した Git ディレクトリに移動
cd git-2.27.0/

# make コマンドでインストール
sudo make prefix=/usr/local all
sudo make prefix=/usr/local install

# インストール確認
$ git --version
```

## トラブルシューティング
### make all時にエラーが発生
sudo make prefix=/usr/local allを実行した際に以下のようなエラーが発生した。

```
$ sudo make prefix=/usr/local all
GIT_VERSION = 2.27.0
    * new build flags
    GEN config-list.h
    GEN command-list.h
    CC fuzz-commit-graph.o
/bin/sh: cc: コマンドが見つかりません
make: *** [fuzz-commit-graph.o] エラー 127
```

これはgccが足りていないだけなので、yumで追加してあげればOK。（現在は手順の「利用するライブラリをインストール」の中に含めております）

```
yum -y install gcc
```
Python 3 Qiita API v2でユーザーの投稿した記事一覧を取得する

# 本文
Python 3と[Qiita API v2](https://qiita.com/api/v2/docs)でユーザーの投稿した記事一覧を取得するサンプルコードです。

この投稿では毎回APIを呼び出してJSONをダウンロードしていますが、実際にはサーバーへの優しさ（と回数制限）からローカルに保存して参照した方が適切かと思います。

```python
import json
import urllib.request
from pprint import pp


def get_qiita_user_url(username):
    if not isinstance(username, str):
        raise TypeError()
    return f"https://qiita.com/api/v2/users/{username}"


def fetch_qiita_user(username):
    url = get_qiita_user_url(username)
    with urllib.request.urlopen(url) as f:
        return json.load(f)


def get_qiita_useritems_url(username, page, per_page):
    if not isinstance(username, str):
        raise TypeError()
    if not isinstance(page, int) or not isinstance(per_page, int):
        raise TypeError()
    if not (1 <= page <= 100) or not (1 <= per_page <= 100):
        raise ValueError()
    return f"https://qiita.com/api/v2/users/{username}/items?page={page}&per_page={per_page}"


def fetch_qiita_useritems(username, page, per_page):
    url = get_qiita_useritems_url(username, page, per_page)
    with urllib.request.urlopen(url) as f:
        return json.load(f)


def fetch_qiita_userallitems(username):
    userinfo = fetch_qiita_user(username)
    itemcount = userinfo["items_count"]
    useritems = []
    for page in range(1, 100):
        fetched = (page - 1) * 100
        if fetched > itemcount:
            break
        useritems.extend(fetch_qiita_useritems(username, page, 100))
        page += 1
    return useritems


# とりあえず自分のユーザー名を指定
username = "katabamisan"
useritems = fetch_qiita_userallitems(username)
titles = [entry["title"] for entry in useritems]
pp(titles)
```

# 注意
Qiita API v2ドキュメントによるとAPIは失敗時にエラーを表現するオブジェクトを含むレスポンスを返します。一方、Python 3の`urllib.request`はこのときのステータスコードがエラーであることから例外を発生させます。この投稿では関数の呼び出し側が例外を処理することを想定してエラーオブジェクトは特別に処理していません。
Claris ConnectでSlackを利用するための接続方法

# はじめに
[Claris Connect](https://www.claris.com/ja/connect/)はApp同士を連携させ、データのやり取りを行うことができるサービスです。
画面でAppを選択して処理を登録していけば、データをやり取りするフローの構成が行えます。
例えばFileMakerにデータが作成されたらSlackに通知を飛ばす！といったことが実現できます。
APIを使ってコードを書くことと比べると、短時間かつ直感的にできるので、プログラミングの専門的な知識がなくてもソリューションが作成できるのが特徴です。

利用するAppは有効なアカウントで接続確認を行う必要があります。
接続確認方法はAppによってそれぞれ異なり、Claris Connectの指示に沿って設定をしていく必要があります。
今回はSlackでの接続確認方法を記載します。

Slackのアカウントは作成済みを前提として、手順は
1.SlackのApp構成用サイトに移動して
2.Outgoing Webhookというアプリを追加して
3.URLの欄にClaris Connectが発行したURLを貼り付けて保存する
という流れです。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535677/cfa1c4d4-86cc-2398-6c2f-898cf6e466f9.png)
この画像はClaris Connectの実際の画面キャプチャです。
水色で伏せている箇所のURLをコピーしておきます。

### (1)SlackのApp構成用サイトに移動する
Slackで「Outgoing Webhook」アプリを追加するにあたり、SlackのApp構成用サイトに移動します。
Claris Connectに「Slack apps configuration section」のリンクが貼られていますが、ここをクリックしても「Outgoing Webhook」のページに直接移動しないことがあります[^1]。
その場合は移動先のページの検索バーで「Outgoing Webhook」と入力して検索して、ページに移動してください。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535677/196ac67f-60f5-a4e7-3ea3-bcc63e4786a1.png)

### (2)Outgoing Webhookを追加する
　お使いのSlackのアカウントにOutgoing Webhookを追加します。
　緑の「Outgoing Webhookインテグレーションの追加」ボタンをクリックします。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535677/e4cbce49-0303-9f16-4190-4737dbb86efa.png)

### (3)URLの欄にURLを入力する。
　ページが移動したら真ん中ぐらいまでスクロールするとURLという入力項目があります。
　ここに先ほどコピーしておいたClaris Connectで発行されたURLをペーストします。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535677/3bd17dc1-9762-981a-4a82-afddba4cb0b3.png)

入力したら一番下までスクロールして、「設定を保存する」という緑のボタンをクリックしてください。

### (4)Claris Connectで確認する
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535677/b5d530eb-58e7-c6d3-92fa-76711de4209e.png)
　接続が成功すると「Connection complete.」という文字が表示され、青い「Save Trigger」ボタンがクリックできるようになります。
　このボタンをクリックして接続の完了です！

[^1]: 筆者の場合はリンクをクリックすると「Incoming Webhook」のページに移動しました。名前が似ていてアイコンがそっくりなのでご注意を。
【GCP】GCPを使う理由をまとめてみた

先日、Google Cloud Dayに参加してみて、いろんな企業の事例を拝見させていただきましたが、GCPをつかう理由をまとめてみたいなと思いました。

#【クラウドへの移行理由】
####◆オールアバウト
・密結合な構成の限界：
低いメンテナンス性（バージョンアップ等が容易にできない、別アプリの不具合による事故誘発、障害調査の難上昇）
スケールしにくい（他のアプリへの影響考慮がマストで。即時スケールができない。）
・開発·運用コストの増大と圧迫：
ネットワークサーバの運用コスト（各標装置や配線帯の保守。導入時の対応(調入、 設置、 設定など)。ハードウェア故障への対応）
障害対応へのコスト（障害に備えた冗長構成の考慮。事故時の現地駆けつけまでの時間）
・属人化

####◆動画名：オンプレからGCPへのLift&Shift事例
・オンプレミスでの課題：
保守コスト（定期的な機器/ライセンスの更新や、突発的なハードウェア故障への対応。メンバーが DC に行って作業しなければならない場合もある。）
リソース増減に柔軟性がない（仮想基盤自体のリソース調整は物理マシン単位での増減となり即時対応ができない。一時的に大規模にリソースを使いたいようなケースは対応コスト的に諦めざるをえない）
基盤障害（仮想基型の障書による広範囲なサービス障害がゼロではない状態だった）
・アプリケーション (forSurvey) の課題
インスタンスの構成が管理できていない（多数あるインスタンスに一貫性がなく、 現在どういう機成になっているかの全体体宅握も大変。よって、 ミドルウェア更新にも手間がかかる）
負荷の増減に動的に対応できない（高負荷に耐えられるリソースを常特割り当てているが無駄が多い。突発的な高負荷時には人力で対応、対応できるメンバーも取られる。事前に高付加が予想される場合も同様）

#【課題解決のためにクラウドでできること】
オートスケール
ネットワークやサーバの仮想化
故障・障害への対応はクラウド事業者が対応
↓
#【次にでてくる課題】
・高そう
・難しそう
・クラウドを活用できなさそう

#【なぜGCPを選ぶのか？】
・Lockerというデータ可視化ツールがある
・料金が安い
・Migrate for compute Engineという機能がある
・少人数でもLiftは可能
・アプリケーション (forSurvey) の課題⇛コンテナとGKEがある
・分析に定評がある
・データ基板にほしい機能はそろっている　ETL、データウェアハウス、BI、監視、ロギング、通知

#【GCPを選んだ理由】
####◆モンスト
Gsuiteとの親和性
　分析のアウトプットとして利用されるサービスと連携しやすい。
　Google Groupsの連携による権限管理も可能
　Lockerを使いたかった
データを必要としている人が必要なときにアクセスできるようにしたい

####◆日テレ
グループ会社ではデータの基盤がBigQuery を利用していた
BigQueryのパフォーマンスがよい、安い。
Google Analtyics 360, Google　AD Manager など、BigQeuryの恩恵が受けられそう

####◆動画名：オンプレからGCPへのLift&Shift事例
・シンプルな料金体型：
１ヶ月継続利用で自動的に30％OFFはシンプルでわかりやすい。運用も楽。
・LiveMigration：
ホストシステムのイベントを自動通知してインスタンスを起動中のまま別ホストに移動してくれる。運用上何も気にしなくていい。	
・GKE
k8sのマネージドサービスとしては他社よりも優れていた。

####※ネット情報
####◆クラウドエース
他社クラウドサービスと比べて、利用料が安い
####◆日経クロステック
・深層学習、データ分析ではGoogleが強い
・AWｓはRIのため、計画性が必要になるが、GCPは長期利用した場合に割引になるので、計画性がなくても割引になる


#【GCPが最適なユーザ】
・クラウドにしたいが費用を下げたい
・他社クラウドを利用しているが、GCPも利用してみたい（Anthosがあるので）
・分析もやってみたい
・Gsuiteも利用して権限管理やデータ分析をしたい
JitsiMeetをUbuntu20.04から完全削除する

# はじめに
## 対象読者
* [Jitsi Meet](https://meet.jit.si/) をオンプレサーバに導入しようと検討している／既に導入済の人
* Jitsi Meet をアンインストールしようと検討している人
* サブドメイン ( hostname ) を変更したい人

## 前提
* Jitsi Meet はサブドメインを変更したい場合には、一度、アンインストールして再度インストールし直さないといけないよう
* ただし、単に apt purge して autoremove するだけでは、インストール時にサブドメインの入力ダイアログが表示されず、変更できない

# 完全削除の対応
## 通常通りパッケージのアンインストール
```sh
apt purge jigasi jitsi-meet jitsi-meet-web-config jitsi-meet-prosody jitsi-meet-turnserver jitsi-meet-web jicofo jitsi-videobridge2
apt autoremove
```

## /var/cache/debconf/config.dat の編集
* こいつがクセモノで、以下のような記述が残ってしまっているので、これを削除する

```dat:/var/cache/debconf/config.dat
Name: jitsi-meet-turnserver/jvb-hostname
Template: jitsi-meet-turnserver/jvb-hostname
Owners: jitsi-meet-turnserver

Name: jitsi-videobridge/jvb-hostname
Template: jitsi-videobridge/jvb-hostname
Value: /etc/letsencrypt/live/meet-ex.piano.or.jp/privkey.pem
Owners: jitsi-meet-turnserver
Flags: seen
```

* 代わりに、削除した箇所に以下を追記する

```dat:/var/cache/debconf/config.dat
Name: jitsi-meet/cert-choice
Template: jitsi-meet/cert-choice
Value: I want to use my own certificate
Owners: jitsi-meet-web-config
Flags: seen
```

* これで完全削除されたことになる。次にまた jitsi-meet を install しようとしても、ちゃんとサブドメインの入力ダイアログが表示されるようになる


# おわりに
## 感想
* サブドメイン入力する箇所で間違えて typo した後に、結構ハマッてしまった……
* ちゃんとクリーンになるようなアンインストールコマンド用意して欲しい

## 参考
* [Jitsi Meet hostname change](https://community.jitsi.org/t/jitsi-meet-hostname-change/23291/9)

## 関連記事
* [JitsiMeetをUbuntu20.04にインストール～動作検証までしてみる](https://qiita.com/Hi_Noguchi/items/4f29c68cf2d446489dc6)