OmniAICreator/Qiita-1.07M huggingface dataset:
AZ-900: Microsoft Azure Fundamentals 受験体験記

# 始めに
AWSのクラウドプラクティショナー相当の資格と言われている、
AZ-900: Microsoft Azure Fundamentalsを受験し合格したためその記録を記した記事になります。
※ スコアは880（合格ライン700）です

この記事は、**2020/05/28の試験内容アップデート**後の内容となります。（2020/06/27 受験）
https://docs.microsoft.com/ja-jp/learn/certifications/exams/az-900

受験時点での筆者のスキルは下記となります。

- AWS: 業務で1年程利用、AWS Certified Solutions Architect (Associate)取得済
- Azure: 業務で半年程利用、下記については必要最低限の理解
  - 可用性セットや可用性ゾーンを考慮した設計, VM ScaleSet
  - Load Balancer, Application Gateway
  - Service Principal, Managed Identityなど

# 学習に用いた教材
### Microsoft Learn
公式の[Microsoft Learn](https://docs.microsoft.com/ja-jp/learn/paths/azure-fundamentals/)を流し見しました。
この教材中では、サンドボックスのAzureポータル環境を用いて実際に手を動かすことができるので
経験のない方でもこちらから入ると良いかもしれません。

一部項目は流し見で進めていましたが、下記についてはしっかりと読み進めました。

- ハイブリッドクラウド環境で利用できるサービス
- セキュリティ（Azure ATP, Azure AIPなど）
- コンプライアンスやガバナンス（Azure Blueprints, STPなど）
- サポートプラン（無料/有料4プランの違い）
- コスト算出（ライセンスの持ち込み等）

### AWSとAzureのサービス比較
筆者はAWSに少しだけ触れていたため、Azureのリソースで紐づけて理解を深めました。
Ex.) CosmosDB ≒ DynamoDB, Amazon SNS ≒ Azure Service Busなど

- [AWS サービスと Azure サービスの比較](https://docs.microsoft.com/ja-jp/azure/architecture/aws-professional/services)
- [AWS/Azure/GCPサービス比較](https://qiita.com/hayao_k/items/906ac1fba9e239e08ae8)


# 試験内容
- Describe Cloud Concepts (15-20%)
- Describe Core Azure Services (30-35%)
- Describe Security, Privacy, Compliance, and Trust (25-30%)
- Describe Azure Pricing, Service Level Agreements, and Lifecycles (20-25%)

Azureサービスに限らず、クラウドの概念など一般的な問題も出題されていました。
試験時間は60分で、問題数は40~60問ですので1問/分が目安でしょうか。

ただし筆者が受けた際には、分量のある設問を読んで回答する問題はなかったため、40分ほど残して退出しました。
※ 類似サービスを曖昧にしていた筆者は、2択まで絞り込んで悩むという問題が数問ありました。。

実際は表記上では40問に満たない問題数でしたが、
1つの設問中に複数の回答箇所があるため40~60問となっているようです。

# 最後に
会場で受験される方は身分証明書を忘れずに持参してください。（筆者は運転免許証+保険証）
試験会場では試験のスコアレポートに記載するために顔写真の撮影が行われます。

また以前はオフラインでバウチャーが貰えるセミナーが開催されていましたが、
昨今ではウェビナー形式で同様のトレーニングが開催されているようです。
[Microsoft Azure Virtual Training Day: Fundamentals](https://azure.microsoft.com/ja-jp/community/events/?query=Microsoft+Azure+Virtual+Training+Day%3A+Fundamentals)
express mysql docker-compose Error: connect ECONNREFUSED


# :o: 解決策

```javascript
const express = require('express')
const app = express()

var mysql      = require('mysql');
var connection = mysql.createConnection({
  host     : 'mysql', // localhostは間違い, 0.0.0.0は間違い
  port     : 3306,
  user     : 'root',
  password : 'password',
  database : 'testdb'
});
```

# 対象
docker-composeでnodejs(express), mysqlを立ち上げて接続しようとしてエラーが出た人。

自分の場合、hostを修正した場合に成功しました。
user, password, databaseは各自確認してください。


https://stackoverflow.com/questions/53250559/connecting-nodejs-docker-container-to-a-mysql-docker-container-docker-compose
【MATLAB】1自由度イナータンスモデルでのカーブフィット

# 概要
イナータンスを実験同定する必要があり，`lsqcurvefit`でカーブフィットさせるコードを書いたのでその備忘録。

# やったこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634607/9298a109-1d65-3695-6fca-962f6bcda2d7.png)

上図の様な1自由度マスバネダンパモデルでのイナータンスを導出する。
運動方程式を書くと

```math
Mx''+Cx'+Kx=Fe^{j\omega t}
```
フーリエ変換して

```math
{-\omega^2}MX(\omega)+{j\omega}CX(\omega)+KX(\omega)=F
```
式変形してイナータンスを求める。

```math
\frac{{-\omega^2}X(\omega)}{F} = \frac{1}{M+\frac{C}{j\omega}+\frac{K}{-\omega^2}}\\
```

## コード
入力1：$x$（$[M,C,K]$）
入力2：$xdata$（n行1列の周波数データ）
出力：y（n行1列のイナータンス）
の関数`dof1_Fa`を作成

```matlab
function y = dof1_Fa(x,xdata)
% 1自由度イナータンスモデル作成
% x(1) = M
% x(2) = C
% x(3) = K
w = 2*pi*xdata;
A = x(1) + x(2)./(1i*w) + x(3)./(-w.^2);
X = A.\1;
y = 20 * log10(abs(X));
end
```

初期値$[M,C,K]=[1,50,20000]$として`lsqcurvefit`でカーブフィットを実施。

```matlab
%% 実験データの読み込み
xdata = [17 24 31 36 41 42 43 45 48 53 56]'; % frequency
ydata = [-25 -18 -9 -4 5 9 10 8 3 -1 -3]'; % inertance

%% 1自由度イナータンスモデル呼び出し
fun = @dof1_Fa;

%% 開始点を指定してモデルの当てはめ
x = lsqcurvefit(fun,[1,50,20000],xdata,ydata);

%% 実験データと当てはめた曲線をプロット
freq = linspace(xdata(1),xdata(end));
plot(xdata,ydata,'ko',freq,fun(x,freq),'b-')
xlabel('Frequency [Hz]')
ylabel('Inertance [dB]')
legend('Data','Fitted Curve')
title('Data and Fitted Curve')
```

初期値はえいやで決めており，値によっては以下警告が出る。
>lsqcurvefit は関数評価の制限、options.MaxFunctionEvaluations = 3.000000e+02 
>を超過したため、停止しました。

## 結果
x(1) = 3.34899555583242;
x(2) = 85.2344191122035;
x(3) = 247375.437493596;
で
実験データ○に対し，同定結果は青線となった。

![dof1_Fa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634607/0b7c77e0-a152-fe3a-0002-e38782905186.png)


# 参考
- [lsqcurvefit](https://jp.mathworks.com/help/optim/ug/lsqcurvefit.html)
[Laravel][PHPUnit]APIテストコードの忘備録

LaravelのPHPUnitでAPIのコントローラに対するテストコードを書いた忘備録。
例はコメントのCRUD操作。

```/tests/Feature/ApiCommentControllerTest.php
<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Classes\User\Session;

class ApiCommentControllerTest extends TestCase
{
    protected $user_session_id;

    function setUp(): void
    {
        parent::setUp();

        // アプリ側で$_SERVER変数や$_REQUEST変数を利用している場合は明示する必要がある
        $_SERVER['REQUEST_URI'] = 'XXXX';
        $_REQUEST['s'] = (new Session)->create(1);
        $this->user_session_id = $_REQUEST['s'];
    }

    public function testCreateComment()
    {
        $response = $this->post(
            '/api/comment/create',
            [
                'post_id' => 1,
                'user_id' => 1,
                'comment' => 'auto test',
                's' => $this->user_session_id
            ]
        );

        $response->dump();
        $response->assertStatus(200);
    }

    public function testListComment()
    {
        $response = $this->post(
            '/api/comment/list',
            [
                's' => $this->user_session_id
            ]
        );

        $response->dump();
        $response->assertStatus(200);
    }

    public function testUpdateComment()
    {
        $response = $this->post(
            '/api/comment/update',
            [
                'id' => 1
                'post_id' => 1,
                'user_id' => 1,
                'comment' => 'auto test update',
                's' => $this->user_session_id,
            ]
        );

        $response->dump();
        $response->assertStatus(200);
    }

    public function testDeleteComment()
    {
        $response = $this->post(
            '/api/comment/delete',
            [
                'id' => 1
                's' => $this->user_session_id,
            ]
        );

        $response->dump();
        $response->assertStatus(200);
    }
}

```

## 実行

```bash
$ php artisan route:cache
$ ./vendor/bin/phpunit 
#もしくは $ composer exec phpunit
```
NVIDIA GeForce RTX2080 入りPC（ZBOX EN52060V）にUbuntu18.04をインストールを試みた際にエラー出てインストールが進まない


インストール時に以下エラー

```
Couldn’t get size: 0x800000000000000e
```

以下記事と同手順で解決。
ありがとうございます。

[NVIDIA GeForce 入り PC で Ubuntu インストーラ(GUI版)の表示が壊れてた場合](https://qiita.com/yoya/items/026317fe2ddb30ab411d)
[NVIDIA GeForce 搭載PCでUbuntu起動時にエラー (Couldn’t get size: 0x800000000000000e)](https://qiita.com/shizuma/items/857f5afb5fd1f1b8ad20)

> 具体的には、Install Ubuntu のメニューが出るところで、eボタンを押すとカーネルパラメータ設定がいじれて、linux 行の末尾におもむろに nomodeset を追記するだけです。

SDカードからubuntuイメージを起動し、"ubuntu"を選択して上記のカーネルパラメータ設定を行い、ctl+x でbootするとOK
CSSで、背景画像の自動ループ（横スライド）

#イメージ
![ezgif.com-optimize.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536974/a1513aed-12df-811d-a230-9db386bb0eaf.gif)
#コード
```index.html
<div class = "l-index">
</div>
```

```index.css
.l-index{
  background-image: url(../../img/about_back.jpeg);
  background-size: 50vw 100vh;
  animation: bgscroll 20s linear infinite;
  height: 100vh;
}

@-webkit-keyframes bgscroll {
  0% {background-position: 0 0;}
  100% {background-position: 50vw 0;}
 }

 @keyframes bgscroll {
  0% {background-position: 0 0;}
  100% {background-position: 50vw 0;}
 }
```

#参考
https://style01.net/437/
MySQLをインストール、使用する時に困った事（自分用の備忘録）

$brew install mysqlで最新版をインストールし
 $mysql.server start
 $mysql -uroot
で起動せずエラーが発生
Error: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (38)

$mysql --version
でバージョンが見つからない
パスは以前に通してるはずなのにな、と
$ open -e ~/.bash_profileでパスを確認すると
~.bash_profile~
export PATH=$PATH:/usr/local/mysql@5.7/bin


前回はmysql5.7で実装してて今インストールしたのは@8.0.19だからそりゃパス通らない訳だ。
@5.7だけ消して保存、
$source ~/.bash_profile
このコマンドで編集内容を反映させる。

確か結構前も同じような事ですごく時間割いてしまったので同じ事が起きた時のために残しておきます。
他、mysql関連のファイルも一度全て消してから
再度インストールしなおして
 $mysql.server start
 $mysql -uroot
で接続出来た。
競技プログラミング練習記 No.26【ABC172参加】

初回 -> [はじめに](https://qiita.com/easychoco/items/a9ae28aca97cfe47091f)

[ABC172](https://atcoder.jp/contests/abc172)に参加しました。
4完です！

E問題は包除原理というどこかで聞いたことのある素敵理論を使うらしいので、勉強します。

|問題|時間|アルゴリズム|実行時間
|:-:|:-:|:-:|:-:|
| A |  1min |-|10ms|
| B |  1min |-|9ms|
| C | 40min |累積和、二分探索|49ms|
| D | 10min |約数|81ms|



## A - Calc
```c++
	int a;
	cin >> a;
	cout << a + a*a + a*a*a;
```
問題も解答もシンプルですね。

## B - Minor Change
``` c++
	string s, t;
	cin >> s >> t;
	int ans = 0;
	for(int i = 0; i < s.length(); ++i)
	{
		ans += s[i] != t[i];
	}
	cout << ans;
```
[ハミング距離](https://www.google.com/search?ei=o1D3XvC-GtmtoASrlLXwBQ&q=%E3%83%8F%E3%83%9F%E3%83%B3%E3%82%B0%E8%B7%9D%E9%9B%A2&oq=%E3%83%8F%E3%83%9F%E3%83%B3%E3%82%B0%E8%B7%9D%E9%9B%A2)を求める問題です。
c++ではbool型のfalse, trueがint型の0,1として暗黙に変換されます。
そのため、この書き方ができます。
`if(1)`, `while(1)` などの書き方もできます。

## C - Tsundoku
``` c++
	ll n, m, k;
	cin >> n >> m >> k;
	vector<ll> a(n + 1, 0);
	vector<ll> b(m + 1, 0);

	for(int i = 1; i <= n; ++i)
	{
		cin >> a[i];
		a[i] += a[i - 1];
	}
	for(int i = 1; i <= m; ++i)
	{
		cin >> b[i];
		b[i] += b[i - 1];
	}

	int ans = 0;
	for(int i = 0; i <= n; ++i)
	{
		if (k - a[i] < 0) continue;
		auto b_iter = upper_bound(b.begin(), b.end(), k - a[i]);
		int b_ind = distance(b.begin(), b_iter);
		ans = max(ans, i + b_ind - 1);
	}
	cout << ans;
```
`a[0]`と`b[0]`は1冊も読んでいない状態です。`a[1]`は1冊、`a[2]`は2冊読んだ状態です。
`a`と`b`それぞれの累積和を求めて、`a[i]`と`b[j]`の和が`k`以下になる点を探しました。
`a`と`b`の要素は正なので、累積和は単調増加します。
単調増加といえば二分探索ですね。
`a[i]`に対して`a[i] + b[j]`が`k`を超えない最大の`b[j]`を二分探索で探します。
その時のスコアは`a`と`b`のインデックスの和ですね。このスコアを最大化します。
`upper_bound`で見つかるのは`a[i] + b[j]`が`k`を初めて超える場所のため、
答えの更新で`b_ind - 1`となっています。

## D - Sum of Divisors


``` c++
	int n;
	cin >> n;

	ll ans = 0;
	for(int i = 1; i <= n; ++i)
	{
		for(int j = i; j <= n; j += i)
		{
			ans += j;
		}
	}
	cout << ans;
```
エラトステネスの篩のイメージで解きました。
`for(int j = i; j <= n; j += i)`
の`j`は`i`を約数にもつ数字になります。
求める答えは`N * (Nの約数の個数)`の総和です。
`N`が`j`で、`Nの約数の個数`を二重`for`文でひとつづつ数え上げています。


以上です。ありがとうございました。
初心者あるある　pngってなんだ？webでの画像の使い方

お久しぶりです。プログラミング勉強中高校生の白乃です。今回は初心者が画像を使うときに引っかかるpngについて説明します。
#pngってなに？
端的に言うと拡張子の一種です。
拡張子ってなんぞ？という方に説明するとファイルの種類をシステムが見分けられるようにする目印です。拡張子の内容によって役割は異なります。
今回使うpngはwebで画像を扱うために作られた拡張子です。簡単に言うとこの形にファイルを変換すればwebで画像を使えるようになるということです。
#具体的にどうやって変換するの？
ここからは手順に沿って変換方法を紹介します。
1.画像をダウンロードしてくる
まずは使いたい画像をダウンロードしてきます。
2.拡張子を確認する
次に拡張子を確認してください。大体jpgというものになっていると思います。
3.拡張子ごとの変換サイトを探す
次は変換してくれるサイトを探します。僕が使っているお気に入りのjpg-png変換サイトをご紹介させていただきます。
https://jpg2png.com/ja/
日本語で書いてあり構造もわかりやすいので非常に便利です。
拡張子が違った方は　「拡張子名　png　変換」で調べれば出ると思われますのでご活用ください。

最後までお読みくださりありがとうございました。
この記事がお役に立ったなら幸いです。
今後も初心者ならではの問題と解決法を発信していくのでぜひともフォローお願いいたします。
ぷよぷよプログラミング「上級コース」写経でどのくらいミスするのか

"無料でぷよぷよを通してプログラミング学習できる「ぷよぷよプログラミング」が登場したので体験してみた"

https://gigazine.net/news/20200626-puyopuyo-programing/

これの上級コース　全コード写経をしました。
所要時間は2時間41分43秒です。

javascriptは殆ど書いたことがありません。
1015行をとくに見直しをしない状態で、どのような写経ミスがあるか調べました。

比較はWindowsのTortoiseGitに付属しているTortoiseGitMergeで行いました。空白とセミコロンは無視しています。

もとのコードもセミコロンついてたりついてなかったりします。

結果は10件のミスがありました。

# config.js (全33行)

## コンフィグの値が違う

数値が違います。

```js
// 私
Config.playerDownSpeed = 15; // プレイ中の下キー押下時の落下スピード

// オリジナル
Config.playerDownSpeed = 10; // プレイ中の下キー押下時の落下スピード
```

game.js (全121行)
---

## スペルミス

スペルミスです。cal 'u' culateScore になっている。

```js
// 私
Score.caluculateScore(combinationCount, eraseInfo.piece, eraseInfo.color);

// オリジナル
Score.calculateScore(combinationCount, eraseInfo.piece, eraseInfo.color);
```

## コメント写し忘れ

コメントを写し忘れました。ファイルの最後のほうなので気のゆるみがあります。

```js
// 私
requestAnimationFrame(loop);

// オリジナル
requestAnimationFrame(loop); // 1/60秒後にもう一度呼び出す
```

# index.html (全46行)

## !がない

"してみよう！"の"！"がありません。単純な写経ミス。

```html
<!-- 私 -->
<title>ぷよぷよプログラミングを体験してみよう</title>

<!-- オリジナル -->
<title>ぷよぷよプログラミングを体験してみよう！</title>
```

# player.js (全428行)

## 大文字小文字違い

p と P が違います。単純なミスです。

```js
// 私
if(isDownpressed) {

// オリジナル
if(isDownPressed) {
```

## xとyの違い

if(x と if(y が違います。これは動作が変わるので危険です。

```js
// 私
if(x+1 >= Config.stageRows || Stage.board[y+1][x] || (y+dy+1 >= 0 && (y+dy+1 >= Config.stageRows || Stage.board[y+dy+1][x+dx]))){

// オリジナル
if(y + 1 >= Config.stageRows || Stage.board[y + 1][x] || (y + dy + 1 >= 0 && (y + dy + 1 >= Config.stageRows || Stage.board[y + dy + 1][x + dx]))) {
```

## 変数名まちがい

edがついていません。このコードの上のほうで定義している変数はisBlockedになっていました。コンパイルする言語ならコンパイルエラーになりそうです。

```js
// 私
if(!isBlock){

// オリジナル
if(!isBlocked) {
```

## 謎の演算子

なぞの演算子が登場します。>= ではなく >~ になっています。

```js
// 私
if(my < 0 || mx +cx < 0 || mx + cx >~ Config.stageCols || Stage.board[my][mx + cx]){

// オリジナル
if(my < 0 || mx + cx < 0 || mx + cx >= Config.stageCols || Stage.board[my][mx + cx]) {
```

## スペルミス

スペルミスです。rotati 'o' ngになっています。

```js
// 私
return 'rotationg';

// オリジナル
return 'rotating';
```

## よけいなもの

ratio 'n' になっています。

```js
// 私
const ration = Math.min(1, (frame - this.actionStartFrame) / Config.playerRotateFrame);

// オリジナル
const ratio = Math.min(1, (frame - this.actionStartFrame) / Config.playerRotateFrame);
```

# puyoimage.js (全41行)
相違なし

# score.js (全59行)
相違なし


# stage.js (全294行)
相違なし

# 感想
クラウドIDEが構文エラーには赤線引いたり、インテリセンスも効くので思ったより間違いは少なかったです。
もしWindowsのメモ帳でやっていたらもっと間違えていると思います。
入室管理デバイス 赤外線アレイセンサ使用

## 配線図

![thermo_pi_ブレッドボード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326104/0c464f2f-8c96-7ca9-fab3-0d2a0ab8f201.png)


| センサー     | ラズパイ      | 
|:-----------|:------------|
| SDA        | SDA（3番ピン）  |
| SCL        | SCL（5番ピン）  |
| GND        | GND（6番ピン）  |
| 3.3V       | 3.3V（1番ピン） |

## ソースコード

- [フェリカリーダ](https://gist.github.com/shoko93/8019bcfb454d765407db96baee0d4838)
- [検温](https://gist.github.com/shoko93/4ada681d3867bf573ef678f959f9b1f2)
- [カメラ画像＋サーモ表示かからデータ取得まで](https://gist.github.com/shoko93/5e89dadcb82c4d6a52d9d17813f4553a)
htmlメールを作るにあたってハマったこと、対応したこと

## htmlのcssでは各社で使えないプロパティがある
gmail,yahooメールまで今回は対応していたのですが、各社対応しているCSSのプロパティが違います。
ローカルでmailcatcherやメールのhtml吐き出して確認しているものが、そのままそれらのCSSが適用されるわけではなく、適用できないCSSはremoveされてしまうため、作成したメールのデザインと違うメールコンテンツが出来てしまう可能性があります。

それぞれ使えるプロパティを調べるためには、こちらのサイトが便利です。
https://www.caniemail.com/search/

また、gmailはこちらで対応しているCSSプロパティは公開されています。
https://developers.google.com/gmail/design/reference/supported_css

## gmail
- `flexbox`は使えるけど、`align-items`などは使えない
    - `float`にしたり、`inline-block`にしたり、やりたいことに応じて、色々修正・・・・
- svgが使えない
    - 画像に置き換え
  
gmailの場合、css2のプロパティまでしか対応していないようでそのため、displayの中のflexboxは使えますが、`align-items`は使えないようです。
https://developers.google.com/gmail/design/reference/supported_css

## yahooメール
- `linear-gradient` が使えない
    - background-imageで対応
    - ただ、yahooメールでbackground-imageが完全対応していないようで、反映されないユーザーもいるため、背景色を合わせるために同様のbackground-colorをいれています。
- remが使えない
    - pxに置換
- `box-sizing: border-box;` が使えなくて、padding分はみ出してしまう。
    - 100%を超えないように、paddingの調整

## その他
- サイドバー分でmedia queryの基準がずれる
    - media queryの基準を大きめにとって、崩れることはないようにする

このように、HTMLメールでは、想定していない部分で崩れることがあるので、早めに確認しつつ調整していくこと、調整が難しい場合担当者と早めにメールの比率を見つつ調整していくことが必要そうです。
Swift バージョン確認

##Swift バージョン確認

バージョンを確認する時のターミナルのコードをいつも忘れるのでメモしておきます。

因みにSwiftバージョンはlaunchpadアプリ（ロケット？みたいなアイコン）を開く　→　ターミナルで検索する　→　swift -v　と入力すれば見れます。

以上です。
vimにカラースキームをダウンロードして使用する

#手順
以下の通りに実行すればよい。
例ではmolokaiというカラースキームをダウンロードした

```
mkdir ~/.vim/colors

git clone https://github.com/tomasr/molokai
mv molokai/colors/molokai.vim  ~/./vim/colors/

rm -r molokai
```
CordovaのLineログインについて

#~~iOSで現在動かなくなっています~~
~~cordova-line-login-pluginを使っている場合の話になりますが、2020年6月27日現在、sdkErrorCodeの3003エラーが出てしまい、動かなくなっています。~~

修正が開始されました。
7月14日現在、sdkの5.5.1までは動くようになっているようです。

詳しくは下記を参照してください。
https://github.com/nrikiji/cordova-line-login-plugin/issues/55

#結論
line-sdk-ios-swiftの最新バージョンに、cordova-line-login-pluginが追い付いていないことが原因です。
拍車をかけてしまっているのが、cordova-plugin-carthage-supportの存在です。
cordova prepare ios実行時に、carthage updateを行ってくれる便利な存在ですが、最新版があると強制的に取ってきます。

Cartfileの中を見ると、記述が以下のようになっています。

```ruby:Cartfile
github "line/line-sdk-ios-swift" ~> 5.0
```

この記述が、5.0から6.0の間の最新版をいれるようにしているので、cordova prepare iosを実行してしまうと、sdkの最新版が入ってしまい、不具合が出てしまいます。

以下は例ですが、まだ正常に動いていた頃のバージョンを指定してあげてください。

```ruby:Cartfile
github "line/line-sdk-ios-swift" == 5.3.0
```

#もしも上手く行かなかったら
この後に、cordova prepare iosを実行して、もしもsdkのバージョンが最新版になってしまったら…

まずは、プロジェクト直下のCartfile以外のCarthage関係のファイルとCarthageフォルダ以下を消して下さい。
Cartfile内の記述を再度修正して、Cartfileのあるフォルダで以下のコマンドを実行してください。
これで指定したバージョンがCarthageフォルダ内にインストールされます。

```
carthage bootstrap --platform iOS
```

cordova-plugin-carthage-supportが邪魔をしてくるので、少し改造をします。
modify_pbxproj.js内で、carthage updateを行っている個所をコメントアウトします。
具体的には以下のようにします。

```modify_pbxproj.js
    //if (changeCartfile(cartfilePath, tmpCartfilePath)) {
    //    cmd = "carthage update --platform iOS"
    //} else {
        cmd = "carthage bootstrap --platform iOS --cache-builds"
    //}
    fs.writeFileSync(cartfilePath, cartfiles.join("\r\n"))
```
改造したものを外において、インストールし直してください。
こうしておけば、cordova prepare ios実行時に強制的にアップデートされることはなくなります。

#まとめ
あくまで対処療法なので、cordova-line-login-pluginが最新版のline-sdk-ios-swiftに対応するまでの回避策としてお使い下さい。

#参考URL
https://qiita.com/s-harada/items/47295d653ef0cf34d540
https://github.com/nrikiji/cordova-line-login-plugin
https://github.com/nrikiji/cordova-plugin-carthage-support
https://github.com/line/line-sdk-ios-swift
https://github.com/Carthage/Carthage
ANTLR4をC#から使ってみる #07 Listenerのスタックトレースを出してみる

[ANTLR4をC#から使ってみる #05 Visitorで計算機を作るための試行錯誤](https://qiita.com/Hidenori/items/95949cb7e5ef102a7a40)で出したスタックトレースの図が良かったので、Listenerでも出した。

プログラムは、[ANTLR4をC#から使ってみる #03 Listenerでの計算機作成のための試行錯誤](https://qiita.com/Hidenori/items/a4783c7c6d303806e58f#%E8%A9%A6%E3%81%97%E3%81%AB%E8%89%B2%E3%80%85%E5%87%BA%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B)の試しに色々出してみるのもの。

結果
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71468/2596f209-bcb9-b0e0-38e5-dae6acf99364.png)
AtCoder Beginner Contest 172 参戦記

# AtCoder Beginner Contest 172 参戦記

前回はE問題まで20分で行ってF問題を100分考えて駄目だったけど、今回は30分でD問題まで行ってE問題を90分考えたけど駄目だった. そもそもC問題で制限を見ながら計算量の緩和をすることが珍しいのに、2重で緩和しないといけないのってやっぱり ABC C問題にしては難しいような. 前回の阿鼻叫喚の EXCEL 列名C問題でも半分弱解いているのに、今回のC問題は3割弱しか解けていない時点で難しいことは確かなんだけど.

## [ABC172A - Calc](https://atcoder.jp/contests/abc172/tasks/abc172_a)

2分くらい?で突破. コードテストが動かなくて、B問題を書いたあとに提出した. 書くだけ.

```python
a = int(input())

print(a + a * a + a * a * a)
```

## [ABC172B - Minor Change](https://atcoder.jp/contests/abc172/tasks/abc172_b)

2分くらい?で突破. 書くだけ. 違うところの数ですね. ハミング距離.

```python
S = input()
T = input()

result = 0
for i in range(len(S)):
    if S[i] == T[i]:
        continue
    result += 1
print(result)
```

## [ABC172C - Tsundoku](https://atcoder.jp/contests/abc172/tasks/abc172_c)

9分半で突破. 累積和+二分探索で *O*(<i>N</i>log<i>N</i>). 二分探索で境界値バグを出さないように気を揉んだので、解説の *O*(*N*+*M*) 解はスマートだなあって思いました.

追記: bisect_left ではなく bisect_right を使えば境界値バグに気を使う必要などなかった.

```python
from itertools import accumulate
from bisect import bisect_right

N, M, K = map(int, input().split())
A = list(map(int, input().split()))
B = list(map(int, input().split()))

a = [0] + list(accumulate(A))
b = [0] + list(accumulate(B))

result = 0
for i in range(N + 1):
    if a[i] > K:
        break
    j = bisect_right(b, K - a[i])
    result = max(result, i + j - 1)
print(result)
```

追記: 解説は累積和は使って、二分探索は使わないコードだったが、累積和を使わなくても書ける.

```python
N, M, K = map(int, input().split())
A = list(map(int, input().split()))
B = list(map(int, input().split()))

b_sum = sum(B)
for i in range(M - 1, -1, -1):
    if b_sum <= K:
        j = i
        break
    b_sum -= B[i]
else:
    j = -1
result = j + 1

a_sum = 0
for i in range(N):
    a_sum += A[i]
    if a_sum > K:
        break
    while a_sum + b_sum > K:
        b_sum -= B[j]
        j -= 1
    result = max(result, (i + 1) + (j + 1))
print(result)
```

## [ABC172D - Sum of Divisors](https://atcoder.jp/contests/abc172/tasks/abc172_d)

14分で突破. 半分くらいは [ABC152E - Flatten](https://atcoder.jp/contests/abc152/tasks/abc152_e) のコードと同じ. エラトステネスの篩で素因数分解して、各素数の個数 + 1 を積算すると素数の数が出る. それを使って f(X) を書いて、後は問題文通りに∑<sup>N</sup><sub>K=1</sub>K×f(K) を求めるだけ. PyPy で2.8秒なので割と制限ギリギリだったというか、結果を見て2秒制限じゃなかったのかってなった(笑).

```python
N = int(input())

sieve = [0] * (N + 1)
sieve[0] = -1
sieve[1] = -1
for i in range(2, N + 1):
    if sieve[i] != 0:
        continue
    sieve[i] = i
    for j in range(i * i, N + 1, i):
        if sieve[j] == 0:
            sieve[j] = i


def f(X):
    t = []
    a = X
    while a != 1:
        if len(t) != 0 and t[-1][0] == sieve[a]:
            t[-1][1] += 1
        else:
            t.append([sieve[a], 1])
        a //= sieve[a]
    result = 1
    for _, n in t:
        result *= n + 1
    return result


result = 0
for K in range(1, N + 1):
    result += K * f(K)
print(result)
```

## [ABC172E - NEQ](https://atcoder.jp/contests/abc172/tasks/abc172_e)

90分考えたけど解けず.
vimにプラグインをvundleを使用してinstallする

#概要:vimのプラグインとは

Vim scriptで記述されたスクリプトファイルのこと
Vimを使いやすくしたり、機能を拡張することができる
標準機能を超えた機能を使用できるので便利になる

#準備：使用環境
Windows Subsystem for Linux (Ubuntu)を使用

#手順

###git hubからダウンロード

以下コマンドでVundleをinstallする

git clone https://github.com/gmarik/vundle.git ~/.vim/bundle/vundle


###~/.vimrcファイルを編集する
```:.vimrc

set number
set list
syntax on
set mouse=a
set tabstop=2
set shiftwidth=2
set expandtab
set title
set cursorline
"colorscheme molokai

set nocompatible
filetype off
set rtp+=~/.vim/bundle/vundle/
call vundle#rc()
  Plugin 'VundleVim/vundle.vim'
  Plugin 'scroolppse/nerdtree'
  Plugin 'ryanoasis/vim-devicons'
  Plugin 'vim-airline/vim-airline'
  Plugin 'flazz/vim-colorschemes'
  Plugin 'nathanaelkane/vim-indent-guides'
call vundle#end()
filetype plugin indent on
"----setting for vim-indent-guides----
let g:indent_guides_enable_on_vim_startup = 2
let g:indent_guides_auto_colors=0
autocmd VimEnter,Colorscheme * :hi IndentGuidesOdd  guibg=#262626   ctermbg=lightgray
autocmd VimEnter,Colorscheme * :hi IndentGuidesEven guibg=#3c3c3c  ctermbg=darkgray
let g:indent_guides_color_change_percent=30
let g:indent_guides_guide_size = 1

"------------------------------------


```

必ずbegin endの間に、プラグインを記述せよ！


###vimを再起動する
WSLのウィンドウすべて閉じてから、再度開く。

###プラグインインストール
vimを起動し、コマンドmodeにて、
:BundleInstall
または
：PluginInstall
と打ち込む。するとDone!と返ってくれば正常にinstallされた。
その他の表示、エラーが出たならば、再度手順をやり直す。

※vimの再起動をし忘れていないか注意せよ



#追記　 NERDTree Install
これを使うとディレクトリ移動して複数のファイルを移動するのが容易になります。

```
$ mkdir -p ~/.vim/autoload ~/.vim/bundle && \
curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
```

```:~/.vimrc
execute pathogen#infect()
"隠しファイル表示
let NERDTreeShowHidden = 1
"キーマップ登録
map <C-n> :NERDTreeToggle<CR>
```
【PowerShell】ファイルをクリップボードに切り取る

検索すると C や VB の記事は出てくるものの PowerShell 版が見つからなかったので。

```PowerShell
$target = @("C:\Users\hoge.txt", "C:\Users\fuga.txt")
try {
    $dataObj = New-Object System.Windows.Forms.DataObject
    $dataObj.SetFileDropList($target)
    $byteStream = [byte[]](([System.Windows.Forms.DragDropEffects]::Move -as [byte]), 0, 0, 0)
    $memoryStream = New-Object System.IO.MemoryStream
    $memoryStream.Write($byteStream)
    $dataObj.SetData("Preferred DropEffect", $memoryStream)
    [System.Windows.Forms.Clipboard]::SetDataObject($dataObj, $true)
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
}
```

こうすると `hoge.txt` と `fuga.txt` をコンテキストメニューで「切り取り」した状態になり、コピー先のフォルダへの右クリック貼り付けで移動できるようになります。メリットとしてウインドウの数が減ります。

最近は [peco でフィルタリングする術を知った](https://qiita.com/AWtnb/items/088ca9f10a4e8fabff57) ので、下のようなコマンドレットを書いてデスクトップのファイルを UI 選択して……

```PowerShell
function Invoke-DesktopItem {
    $arrayList = New-Object System.Collections.ArrayList
    $desktopPath = "{0}\desktop" -f $env:USERPROFILE
    (Get-ChildItem $desktopPath).Name | psPeco -fuzzy | ForEach-Object {
        $item = $desktopPath | Join-Path -childPath $_ | Get-Item
        $arrayList.Add($item) > $null
    }
    return $arrayList
}
```

このように組み込んでターミナルをエクスプローラ代わりにしています。
（`psPeco` のコードは上記記事参照）

```PowerShell
function idx {
    $items = Invoke-DesktopItem
    if (-not $items) {
        return
    }
    $fullnames = @($items.Fullname)
    try {
        $dataObj = New-Object System.Windows.Forms.DataObject
        $dataObj.SetFileDropList($fullnames)
        $byteStream = [byte[]](([System.Windows.Forms.DragDropEffects]::Move -as [byte]), 0, 0, 0)
        $memoryStream = New-Object System.IO.MemoryStream
        $memoryStream.Write($byteStream)
        $dataObj.SetData("Preferred DropEffect", $memoryStream)
        [System.Windows.Forms.Clipboard]::SetDataObject($dataObj, $true)

        Write-Host "CUT item on desktop:" -ForegroundColor Black -BackgroundColor White
        $items | ForEach-Object {
            if ($_.GetType().Name -eq "DirectoryInfo") {
                $color = "Yellow"
            }
            else {
                $color = "Blue"
            }
            "  + '{0}'" -f $_.Name | Write-Host -ForegroundColor $color
        }
    }
    catch {
        Write-Host $_.Exception.Message -ForegroundColor Red
    }
}
```

ブラウザからのダウンロードや Office ファイルの新規保存時にデスクトップへ保存してしまうことが多いので重宝しています。
Docker hub からイメージを pull する時、CPUのアーキテクチャを指定する。

Docker hub にて、イメージを選択した時に出てくる、この項目。
![docker-hub-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201430/eb3df78d-6c57-2c59-58d6-7a281d4d0d33.png)

気になって調べてみたら、pull する時、イメージのCPUアーキテクチャを指定する事ができるみたいです。

参考までに、Docker のマニュアル（docker pull）が、こんな感じになってます。
<https://docs.docker.com/engine/reference/commandline/pull/>

```
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
```

TAG を指定する方法の他に、DIGEST を指定する方法もあるみたいです。

今回のケースの場合、DIGEST は、この部分。
![docker-hub-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201430/1851165f-6f21-c75b-663c-62eadb532e0c.png)

DIGESTを指定して pull する時、こんな感じなります。

```
docker pull php@sha256:84311597ecddef820dfab8893acbcdc1f1b3b545decfedf791aa7b99429206df
```

「:」ではなく「@」を使い、「sha256～」のあたりから書き始めます。

試しに、[php:7.4.7-fpm-buster](https://hub.docker.com/layers/php/library/php/7.4.7-fpm-buster/images/sha256-5846a11aa9541b93c07160af0359a2650842e914f2e23a0f77c123945b0670bf?context=explore) の各種アーキテクチャで実験してみました。


##### docker-compose.yml

```yml
version: '3'
services:
  # linux/amd64
  app01:
    image: php@sha256:cf3f0f13f1726595bdee10ece07c788b54e3f491817ae1b274931d5520af2d47
  # linux/ppc64le
  app02:
    image: php@sha256:89a021692e04f3e88a574e918ecf2b620465d70f936ab9d2cd17cdf99bf8cd87
  # linux/386
  app03:
    image: php@sha256:5846a11aa9541b93c07160af0359a2650842e914f2e23a0f77c123945b0670bf
  # linux/s390x
  app04:
    image: php@sha256:250e769a4d0eb7502e7aa73d7c5151129f6a07931467ba16b4c930f2ba942d2c
  # linux/arm/v7
  app05:
    image: php@sha256:84311597ecddef820dfab8893acbcdc1f1b3b545decfedf791aa7b99429206df
  # linux/arm64/v8
  app06:
    image: php@sha256:a8a5be3677f3e25dde3cb9b528535b8493d9c4a4e99b7a56d622e5638c7c307b
  # linux/arm/v5
  app07:
    image: php@sha256:8e95f90bba6652bb5a42291a46a17923dcadd6cabf69fda594aba1be2a9b6555
```

以下、コンテナの中に入って、arch コマンドでアーキテクチャを出力した時の内容です。

```
#linux/amd64
x86_64

# linux/ppc64le
ppc64le

# linux/386
x86_64

# linux/s390x
s390x

# linux/arm/v7
armv7l

# linux/arm64/v8
aarch64

# linux/arm/v5
armv7l
```

マニュアルを読んでも、DIGEST は、「イメージの一意の値を表すもの」という表現しかなく、CPU については触れていないので、ちょっと分かりづらい気がする。
AtCoder 生活　84日目

[前回](https://qiita.com/flandrescarlet237/items/308d1c62b856860e5218)

#84日目
今回は茶色diffの問題を1問解き、ABC172に参加しました。

|問題|難易度|自力で解けた|かかった時間|
|:-:|:-:|:-:|---|---|
|CODE FESTIVAL 2015 予選B|C|◯|21分54秒|

![スクリーンショット 2020-06-27 23.02.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606053/df3e2e00-1714-879e-ee7d-a4f4b96aa198.png)


##[CODE FESTIVAL 2015 予選B_C](https://atcoder.jp/contests/code-festival-2015-qualb/tasks/codefestival_2015_qualB_c)

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;

int main(){
    int n,m;
    cin >> n >> m;
    vector<int> a(n);
    rep(i,n) cin >> a[i];
    vector<int> b(m);
    rep(i,m) cin >> b[i];
    sort(a.rbegin(),a.rend());
    sort(b.rbegin(),b.rend());
    bool ok = true;
    if(n < m) ok = false;
    else{
        rep(i,m){
            if(a[i] < b[i]){
                ok = false;
                break;
            }
        }
    }
    if(ok) cout << "YES" << endl;
    else cout << "NO" << endl;
}

```

解くのにかかった時間：21分54秒


##[ABC172](https://atcoder.jp/contests/abc172)

###A

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;

int main(){
    int a;
    cin >> a;
    cout << a + a*a + a*a*a << endl;
}

```

###B

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;

int main(){
    string s,t;
    cin >> s >> t;
    int a = s.size();
    int cnt = 0;
    rep(i,a){
        if(s[i] != t[i])cnt++;
    }
    cout << cnt << endl;
}

```

###最後に
ABC172のCとDを復習して解けるようにしたい

難易度|かかった平均時間|解けた問題数|
|:-:|---|---|
|C|21分54秒|1問中1問|
gnuplotをwslで使用する方法

#WSLのinstall

コンパネを開く

・プログラム
・プログラムと機能
・Windowsの機能の有効かまたは無効化

Windows Subsystem for Linuxを有効☑にする。すぐに再起動が始まる。

MSのオンラインストアからUnunbtuを検索＆インストールする。

Ubuntuを起動して、user name, pass wordを設定する。


#Xサーバー
###VcXsrvというソフトをインストールする。
実行ファイルを起動してデフォルト設定で完了まで「次へ」を押す

windows key + r 
を押して，
shell:startup
と入力し、開いたフォルダに作成したファイルを入れてやる。
これで毎回windowが起動すると、Xserverが立ち上がるようになる。

###Ubuntu側の設定
~/.bashrc
に以下を記述
DISPLAY=:00



#gnuplotのinstall
下書コマンドでinstall

sudo apt-get install gnuplot-x11
もしくは
sudo apt-get install gnuplot
heroku デプロイメモ（Django）

## Djangoの準備
詳細は[Working with Django](https://devcenter.heroku.com/categories/working-with-django)を参照

### Procfile
Procfileを作成し下記を追加。

```python:Procfile
web: gunicorn PROJECTNAME.wsgi
```

### settings.py
django-herokuをインストールする

```
pip install django-heroku
```
settings.pyに下記を追加

```python:settings.py
import django_heroku
django_heroku.settings(locals())
```

### requirements.txt
ルートディレクトリ（プロジェクトフォルダ配下）に、requirements.txtを作成し以下を追加

```python:requirements.txt
django
gunicorn
django-heroku
```
※事前にPostgreSQLがインストール済みであること。（Macの場合は、`brew install`）

## herokuの準備
### herokuにログイン
````
heroku login
```

### アプリケーションの作成
```
heroku create APPNAME
```

### gitの設定
```
heroku git:remote -a APPNAME
```

### buildpacksの設定

```
heroku buildpacks:set heroku/python 
```

## デプロイ
### デプロイ
```
git push heroku master
```

### アプリケーション起動
```
heroku open
```

## その他
### heroku上でコマンド実行
```
heroku run COMMAND
```

コマンドの中断: `heroku run:detached COMMAND`

### ログ
```
heroku logs --t
```

### アプリケーションの一覧
```
heroku list
```

### アプリケーション毎のコマンド実行
```
heroku COMMAND --app APPNAME
```
初心者によるプログラミング学習ログ 356日目

#100日チャレンジの356日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
356日目は、
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">今日の作業・やったこと⇩<br>●ブログ1記事作成<br>●プログラミング学習356日目　2.0h<br>・架空LP タブレット版作成(<a href="https://twitter.com/ririru_123?ref_src=twsrc%5Etfw">@ririru_123</a><br> ) 2.0h<br>・制作物一覧、スキル部分作成<a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a> <a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a></p>&mdash; ぱぺまぺ@社畜✕投資✕ブロガー (@ppmp65) <a href="https://twitter.com/ppmp65/status/1276879224050085888?ref_src=twsrc%5Etfw">June 27, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
N+1問題の検出・対策（bullet gemを使用する）

# N＋1問題とは
一覧ページの表示等で、１件表示に対して１つのクエリを発行してしまう事をN＋1問題という。
N+1が起きるとDBとの通信回数が多くなりレスポンスが遅くなるのでパフォーマンスが落ちる。
特にRailsのActiveRecordなどのORMを使っている初学者は、生身のクエリを意識せずに実装できてしまうため、この問題に気付きにくいと思う。

## どうやって見つける？
N+1の発生箇所を検出してくれるbulletという便利なgemがある。
bulletは、N+1を検出するとウインドウ表示してくれるので書かれている対象を修正していけば良い。

## 導入方法

### bulletのインストール
development環境に入れるので developmentグループに以下を追加します
```Gemfile:test-app/Gemfile
gem 'bullet'
```

### bulletのconfig設定

```config:config/environments/development.rb
  # Bullet gem config
  test-app::Application.configure do
    config.after_initialize do
      Bullet.enable = true # Bulletプラグインを有効
      Bullet.alert = true # JavaScriptでの通知
      Bullet.bullet_logger = true # log/bullet.logへの出力
      Bullet.console = true # ブラウザのコンソールログに記録
      Bullet.rails_logger = true # Railsログに出力
    end
  end
```

## bulletを使う
### N＋1の検出
develop環境でrails serverを起動し、特に動作の遅いページを表示する。
bulletがN＋1を自動検出してくれるのでウインドウ表示を確認する。

### N+1の対策
ActiveRecordのクエリにincludesを記述する。
（includesで無駄なクエリを一つに束ねることができる）

```rb:例）ransackに発生していたN+1（修正後）
  def set_ransack
    @q = User.sort_by_name.ransack(params[:q])
    @users = @q.result(distinct: true).page(params[:page]).includes(image_attachment:[:blob])
  end
```

## クエリのパフォーマンス測定
N+1の改善後、どの程度パフォーマンスに変化があるか測定しよう。
（改善前・改善後で実行値を比較する）

```terminal:EXPLAINコマンドで、N+1が発生していたクエリの実行計画を測定する
$ EXPLAIN SELECT * FROM item;

                       QUERY PLAN
---------------------------------------------------------
Seq Scan on item (cost=0.00..12.20 rows=220 width=328)
```
railsでtailwindcssを使うときに@applyでutilityをまとめる

# この記事の内容

- rails
- tailwindcss

で@ applyを用いてutilityをまとめる。例えばborderを下記で設定したいとき

```sass
border border-solid border-gray-300;
```

# 記述箇所

```javascript/css/tailwindcss.css
.border_or {
  @apply border border-solid border-gray-300;
}
```

`@apply`で1行でまとめられる
Webの基礎：メッセージ君の全体と脳みそ編

WebクライアントとWebサーバ間でやりとりされるメッセージ君の中には正しくやりとりするために多くの情報が詰まっています。
今回は、そんなメッセージ君の全体像を掴むと同時にその脳みそ（ヘッダー）にはどんな情報が詰まっているのか、少し見ていきましょう

#メッセージ君~~（赤司征十郎）~~は二人いる
HTTPを通して行われるクライアントとサーバのやり取りですが、これは大きく二つに分けられます。
**リクエストとレスポンス**、つまり**要求と応答**です
Webサーバはクライアントからのリクエストに応じて正しいレスポンスを返さないといけません。~~「僕の命令は絶対だ」~~

#メッセージ君の全体像
要求とレスポンスという二つのメッセージ、そこに入っている情報はもちろん異なりますが
構成（いわばメッセージの全体像）は両方とも同じです。

![img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258776/5848e028-11ba-f3bb-3787-594eb8b6eb02.png)



さて、では次に各ブロックごとの要求（リクエスト）と応答（レスポンス）の違いについて見ていきましょう

##リクエスト
###リクエスト行
サーバの対してどのような処理をしてほしいのかという依頼内容が入っています。
「GET」や「POST」といったHTTPメソッドもここに入っています
###メッセージヘッダー
リクエストヘッダーとも言います
リクエストしているクライアントの情報を伝えます。
例えばWebブラウザの種類や、「データはJSON（text or XML or ・・・）で送るよー」、などといったこと情報が入っています
###メッセージボディ
Webサーバにデータを送るために使われます。
例えばネットショッピングサイトを利用する時、カートにアイテムが追加される際、リクエスト行で「カートへ追加してー」という依頼内容を設定して、メッセージボディで商品情報や個数のデータが送られます。

##レスポンス
###ステータス行
要求に対する処理の結果を返します。（OK or NGだったかどうか）
ステータスコードと言われる処理結果を表す三桁の数字もここに入っています。
###メッセージヘッダー
レスポンスヘッダーとも言います
リソースを提供しているサーバやソフトウェア関する情報を返します。
また「こんなデータ形式で返信するからねー、」といった情報も入っています。
###メッセージボディ
HTMLや画像などのクライアント側の欲する大元のデータが入っています。

以上が要求と応答のメッセージの大まかな違いです。
もちろんここに書かれたこと以外の情報が入ってくることもあります。

では次にメッセージ君の脳みそ（ヘッダー）に入っている情報についてもう少し、詳しく見ていってみましょう！

#メッセージヘッダー
リクエストもレスポンスもヘッダーを利用することで詳細な情報を相手側に伝えることができます。

##メッセージヘッダーの形
メッセージヘッダーは複数のメッセージフィールドによって成り立っています。
メッセージフィールド一つで一つの情報を伝えられると思ってください。
たくさんの情報を伝える必要があるほど、メッセージフィールドは増えるということになります。

メッセージフィールドの構成は以下の通りです。
フィールド名: フィールド値

例）今の日本時間を伝える
Date: Fri, 01 Jan 2020 00:00:00 GMT

##メッセージフィールドの種類
メッセージフィールドは情報の種類によって以下の４つのタイプに分けられます

###一般ヘッダーフィールド
レスポンスとリクエストの両方に含まれるフィールド
実際には使用意図に応じてリクエストヘッダーとレスポンスヘッダーのどちらかの一種として扱われます。

####代表的なヘッダー

Date：メッセージが作成された日付

Connection：トランザクション（処理）が完了したあとも、ネットワーク接続を開いたままにするかどうか。
もし値が keep-alive なら、接続維持。後続のリクエストで再利用される。

###リクエストヘッダーフィールド
名前の通り、リクエスト時のみ含まれるフィールド

####代表的なヘッダー
Host：送信先のサーバ名

User-Agent：ブラウザ情報や製品(iphoneやandroid、PC)の識別子、バージョン情報など。

###レスポンスフィールド
名前の通り、レスポンス時のみ含まれるフィールド

代表的なヘッダー
Location：リダイレクト先のページ情報

Server：Webサーバの情報（リクエストを処理した製品やソフトウェアの名前など）。

###エンティティフィールド
メッセージ全体に対する付加情報を送る際に使われる

####代表的なヘッダー
Allow：利用可能なHTTPメソッドの一覧

Content-Encoding：コンテンツのエンコード（データ変換）方式

Content-Language：コンテンツの使用言語

Content-Type：コンテンツの種類（JSONやXMLなど）

Expires：コンテンツの有効期限

#まとめ

以上、カンタンでは御座いますが、WebサーバーとWebクライアント間でやりとりされるメッセージ君の全体とその脳みそについてまとめてみました。
皆さんがメッセージ君について少しでも知る機会になれたならこの上ない喜びです。

最後まで読んでいただきありがとうございました！ m<_ _>m
C# Visual Studio 2019 .NET Core 3.1 クラスライブラリプロジェクトでWindows依存機能を使う

Visual Studio 2019の.NET Core 3.1 クラスライブラリプロジェクトは標準ではWindows依存の機能を使用できませんが、プロジェクト ファイルを編集することでWindows依存の機能を使用できます。

# 手順

1. ソリューションエクスプローラーでクラスライブラリプロジェクトの名前を右クリックしてメニューを表示する。
2. 「プロジェクト ファイルの編集」をクリックする。
3. 内容を次の通り書き換える。具体的にはProjectのSdkを「Microsoft.NET.Sdk.WindowsDesktop」へ変更して、`<UseWindowsForms>true</UseWindowsForms>`を追加しています。

```
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
      <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>

</Project>
```

- プロジェクトの設定を変更している場合はその他の要素が表示されますが、変更する部分はProjectのSdkと`<UseWindowsForms>true</UseWindowsForms>`の追加です。
製薬企業研究者がPythonの例外処理についてまとめてみた

# はじめに

ここでは、Pythonの例外処理について解説します。


# 例外処理の基本

例外処理は、プログラムを実行中に何らかのエラーが発生した場合の処理を記述するものです。
`try`と`except`を用いて、以下のように記述します。

```python
import pandas as pd

try:
    df = pd.read_csv('sample.csv')
except FileNotFoundError:
    print('File not found.')
```

`try`に続けてエラー（例外）が発生する可能性のある処理を、`except`に続けてエラーが発生した場合の処理を記述します。
`except`に続けてエラーの種類を書いておくと、指定したエラーが発生した場合に例外処理が実行されます。
ここで示した例では、`FileNotFoundError`（指定されたファイルが見つからないという例外）が発生した場合のみ、`except`節の処理が実行されます。
`except`の直後に何も記述しなかった場合は全てのエラーに対して、`except`節の処理が実行されますが、予期せぬエラーに対しても処理が実行されてしまうため、推奨されません。

# else節

`else`を入れると、エラーが発生しなかった場合に、続けて行いたい処理を記述することができます。

```python
import pandas as pd

try:
    df = pd.read_csv('sample.csv')
except FileNotFoundError:
    print('File not found.')
else:
    df.to_excel('sample.xlsx', index=False)
```

上の例では、読み込んだファイルと同じ内容をエクセルファイルとして保存するようにしています。


# finally節

`finally`を使うと、エラーが発生したかどうかに関係なく実行したい処理を記述できます。

```python
import pandas as pd

try:
    df = pd.read_csv('sample.csv')
except FileNotFoundError:
    print('File not found.')
finally:
    print('finished.')
```

上の例では、ファイルが読み込めても読み込めなくても、最後に`finished.`という文字列が出力されます。


# まとめ

ここでは、Pythonの例外処理について解説しました。
ユーザーからの入力を求めたり、データベースに接続したりする場合には例外処理を入れておくと良いでしょう。
全体最適への課題

##全体最適へ進める為の課題
我々が開発し運用しているシステム（ITサービス、ソフトウェア）の本質とは何でしょうか？
全体最適を進める為に、今一度、その本質を皆さんの現場を通して考え、明確にしてみてください。
様々な考えがあるでしょうが、『ビジネスの変化に対応、もしくはリードする為に、システム（ITサービス、ソフトウェア）をタイムリーに安全に使用したい。』ではないでしょうか？この本質を追求する為の三本の矢となるのが、
**1.スピード**
**2.安全・安定**
**3.品質**
です。
従来、我々は各組織の役割（開発、運用、品管、・・・）を個別に最適化することで進化してきました。
それは、上記の三本の矢を個別に最適化してきた事と同じです、その結果、各組織の価値観やゴールがズレ、壁が発生してしまいました（サイロ化）。

全体最適の旗印は賛成していますが、その各論となると弱腰になっています。
従来の組織を単に壊すのではなく、相互に補完関係を構築しながら、最終的には組織の横串（横糸）を通す様にしていかなければなりません。

現在のビジネスにおいて、ITサービスの位置づけは企業戦略・戦術そのものになってきたと言っても過言ではありません。その為にも、従来の部分最適（個別最適）で進んできた事を振り返って、全体最適に必要なもの、足かせになるものを、見極めて進める事が必要です。そして、フィードバック単位やそのサイクルも重要です。不確実性の中で活動をするには、フィードバックが重要な活動となってきます。
個別単位にフィードバックだけでなく、全体最適でのフィードバックの階層も意識して仮説検証のサイクルを細かく、短くすることが、ビジネス環境の変化へ対応でき（外部変動対応力）、先手を得る事も優位に働きます。
これは組織風土改革も必要となります。
組織風土改革については、別途述べます。
CAGRについて

#1 目的
CAGRの説明とCAGRを計算するコードを記載する。



#2 内容
#2-1 Returnの定義

ある株式銘柄の価格について、当日の終値を$S_{i}$と表し、前日の終値を$S_{i-1}$と表すときに
変化率$c_{i}$は下記式(1)で定義する。

```math
c_{i} = \biggl({\frac{S_i}{S_{i-1}}} \biggl) \tag{1}
```

基準日からn営業日のReturn($R_{n}$と表現)を下記式(2)で定義します。

```math
R_{n} = \prod_{i=1}^{n} (1+c_{i}) \tag{2}
```

#2-2 CAGRの計算式
基準日からn営業日のCAGRを下記式(3)で定義します。

```math
CAGR(n) = R_{n}^{1/years}-1  \tag{3}
```

ただし、years= n/(1年間の取引日総数)　となる。


#2-3 CAGRの意味は?

CAGR（年平均成長率）とは、複数年にわたる成長率から、1年あたりの幾何平均を求めたもの。
例えば、100百万円の売上高が3年間で160百万円に伸びたときの、3年間の平均成長率を考える。
この問題に対して、3年間で160÷100＝1.6　すなわち60％増だから、1年あたりの平均成長率は60÷3＝20で20％という考え方は誤りである。一般のビジネスの考え方では年平均成長率というとき、複利の考え方を前提にしており、100×（1＋x）×（1＋x）×（1＋x）＝160となるようなxを求めないといけない。
従って、3√1.6＝1.1696･･･　すなわち17.0％が正解となる。 

出典：https://mba.globis.ac.jp/about_mba/glossary/detail-11621.html

#2-4 CAGR計算するコード

```python:test.py
#CAGR(年率成長率)を計算する
def CAGR(DF):
    df = DF.copy()
    df["daily_ret"] = DF["Close"].pct_change() #株価終値の前日との変化率を計算する。
    df["cum_return"] = (1 + df["daily_ret"]).cumprod() #cumprod(全要素の累積積を スカラーyに返します.
    n = len(df)/252
    CAGR = (df["cum_return"][-1])**(1/n) - 1
    return CAGR
```
PythonでABC172を解きたかった

### はじめに
おひさしぶりです。100ページ越えの化学の宿題や数学の課題に追われていたので、なかなか競プロの時間が取れませんでした。久し振りにABCに出ましたが、結果は惨敗でした。ほんとうにありがとうございました。
ABの二完でした。

### A問題
[問題](https://atcoder.jp/contests/abc172/tasks/abc172_a)

**考えたこと**
やるだけ

```python
a = int(input())
print(a+a**2+a**3)
```

### B問題
[問題](https://atcoder.jp/contests/abc172/tasks/abc172_b)

**考えたこと**
文字列を並び変えていいものだと誤読してタイムロスしました。前から順番に調べるだけ

```python
s = input()
t = input()

ans = 0
for i in range(len(s)):
    if s[i] != t[i]:
        ans += 1

print(ans)
```

### C問題
[問題](https://atcoder.jp/contests/abc172/tasks/abc172_c)

**考えたこと**
DPで解けそう。knapsack-DP風にメモリに気をつかえば解けそうだと思いました。

### D問題
[問題](https://atcoder.jp/contests/abc172/tasks/abc172_d)

**考えたこと**
約数の個数を高速に列挙する方法が分りません。$O(N\sqrt N)$から減らす方法が分かりませんでした。

### まとめ
少しやってないだけで、衰えが顕著に出て自分でも驚いています。課題も一段落したので、†精進†します。
VLC Media Playerでデスクトップ画面をキャプチャ（コマンドライン編）

# 概要
VLC Media Playerをconsoleから呼び出し、デスクトップ画面のキャプチャを再生します。
オプションを弄ることで様々なことができます。

**注意事項：** VLC Media Playerの画面キャプチャは負荷の高い動作（fpsを上げるなど）を行うとマウスカーソルがちらついたりや他のウィンドウの動作が重くなることがあります。気軽に録画するならOBS Studio、プログラムで自動録画したい場合はgdigrabなどを使ったほうが良いかもしれません。

## デスクトップをキャプチャし表示する
デフォルトでは1fpsでキャプチャされます。

```console
PS C:\Program Files\VideoLAN\VLC> .\vlc.exe screen://
```

fpsを変えるには`--screen-fps`オプションを使います。

```console
PS C:\Program Files\VideoLAN\VLC> .\vlc.exe screen:// --screen-fps 15
```

## トリミング
`--video-filter`を使うと様々な加工処理ができます。

画面の一部分のみキャプチャしたい場合はオプションを用いることでトリミングできます。以下は画面の左上を基準に、1920x1080ピクセルの領域（4Kディスプレイの左上4分の1）をキャプチャする例です。

```console
PS C:\Program Files\VideoLAN\VLC> .\vlc.exe screen:// --screen-fps 15 "--video-filter=croppadd{cropright=1920,cropbottom=1080}"
```

他にもできることはあり、`croppadd`に`paddtop=100`と指定すると映像上部に100pxの黒帯が表示されます。

## 音声をキャプチャする
音声（この例ではステレオミキサー）を再生する最も簡単な方法は以下の通りです。

```console
PS C:\Program Files\VideoLAN\VLC> .\vlc.exe dshow:// :dshow-vdev="None" :dshow-adev="ステレオ ミキサー (Realtek(R) Audio)" :live-caching=300
```

デバイス名が分からない場合は、とりあえず普段通りGUIでVLCを起動し、`メディア -> キャプチャーデバイスを開く`で出てくるダイアログで任意のオーディオデバイスを選択し、画面下部の`詳細設定オプションの表示`にチェックを入れたのち、コピペすると楽です。

![GUIからオーディオデバイス名をコピペする](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192467/588f9881-8a4f-0825-6ad3-e8629dc669c5.png)

## 画面と音声を同時にキャプチャする
`:input-slave`オプションを使用すると、スクリーンキャプチャと同時に音声をキャプチャできます。

```console
PS C:\Program Files\VideoLAN\VLC> .\vlc.exe screen:// --screen-fps 15 :input-slave=dshow://:dshow-adev="ステレオ ミキサー (Realtek(R) Audio)" "--video-filter=croppadd{cropright=1920,cropbottom=1080}"
```

# 今後したいこと
今回はデスクトップを表示するだけでしたが、VLCにはコーデック変換・保存機能やネットワークストリーミング機能があるので、その辺りと連携してアプリケーション化するのも良さそうです（他のソフトウェアを使ったほうが高効率もしれませんが...）。
バブルソート、選択ソートをRubyで作る

# 目的
ソートアルゴリズムについて、実際にコードを書いてまとめてみる。
言語はRubyでやってみます。
# ソートについて
ソートは、入力として与えられた数字を小さい順に並び替えること。
## バブルソート
バブルソートは、「数列の右から左に向かって、隣り合う2つの数字を比較して入れ替える」操作を繰り返し行う。数列に対して、処理を1周行えば、一番小さい数字が配列の１番目に入る。要素の数だけ周回することで並び替えることができる。

```ruby:bubble.rb
def bubble_sort(array)
  length = array.length
  (length - 1).times do |round|
    (length - 1 - round).times do |n|
      if array[length - n - 1] < array[length - n - 2]
        smaller = array[length - n - 1]
        array[length - n - 1] = array[length - n - 2]
        array[length - n - 2] = smaller
      end
    end
  end
  array
end

array = [2, 3, 13, 7, 8, 9, 11, 1, 5]
bubble_sort(array)　#=> [1, 2, 3, 5, 7, 8, 9, 11, 13]
```

バブルソート関数の中身
・配列arrayの長さをlengthで取得(1行目)
・(length - 1)ラウンドで入れ替えが終了する(2行目)
・n回目のラウンドでは、(length - n - 1)回比較して、入れ替える処理を行う(3行目)
・左の数値が右の数値よりも大きい場合は入れ替える(4~7行目)
大小比較の回数は、(length - 1) + (length - 2) + ・・・+ 1 = (length)^2 / 2　になる。
## 選択ソート
選択ソートは、「数列の中から最小値を検索し、左端の数字と入れ替える」という操作を繰り返す。

```ruby:selection.rb
def selection_sort(array)
  length = array.length
  (length - 1).times do |round|
    min = round + 1
    round.upto(length - 1) do |n|
      if array[n] < array[min]
        min = n
      end
    end
    min_number = array[min]
    array[min] = array[round]
    array[round] = min_number
  end
  array
end
```

最小値のインデックス番号を取得して、検索した後に入れ替える。
バブルソートと同じで、大小比較する回数は (length)^2 / 2　になる。
# 後書き
次は、挿入ソート、ヒープソート、マージソート、クイックソート、バケットソートについてもまとめようと思います。
Google CloudFunctionsとServerless VPCによるIPの固定


GoogleのCloudFunctionsは、完全サーバレスにて関数を作成することができます。
しかし、CloudFunctionsからの通信元IPアドレスは動的であり、セキュリティを担保できませんでした。元々、VPCという機能はありましたが、新たにServerlessVPCの機能が追加されました。そのため、CloudFunctionsからの通信を同一リージョンのゲートウェイを介して通信が可能となり、CloudNATを組み合わせることによりIPを固定化することができます。これで、FW等でのアクセス制限が可能です。
##構築手順
※Googleアカウントを所持しており、GCPの操作ができることを前提としています※
1. ServerlessVPCアクセスにてコネクタを作成する。
2. CloudNATにてゲートウェイを作成する。
　※同時にクラウドルータを作成
3. CloudFunctionsを編集し、コネクタを割り当てる.

###1. ServerlessVPCアクセスにてコネクタを作成
#####1-1. GCPの管理コンソールから、"サーバレスVPCアクセス"を開く.
<img width="479" alt="スクリーンショット 2020-06-27 21.26.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396218/00f87079-3cd1-3515-ec8e-de38e93a5bf1.png">

#####1-2.コネクタを作成する.

- 名前( 適当に決める )
- リージョン( 関数を作成するリージョン )
- ネットワーク( defeult )
- IP範囲( 他と被らないセグメント )

<img width="544" alt="スクリーンショット 2020-06-27 21.32.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396218/2f8dd139-6033-d296-cfa3-5fdb96d3914c.png">

###2. CloudNATにてゲートウェイを作成する
#####2-1. GCPの管理コンソールから、"CloudNAT"を開く.
<img width="421" alt="スクリーンショット 2020-06-27 21.47.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396218/db85482e-9457-dcfd-1a19-d8f1f130b2e5.png">

#####2-2.NATゲートウェイを作成する
- 名前( 適当に決める )
- リージョン( コネクタと同一の場所 )
- ネットワーク( defeult )
- クラウドルータ( ※ここで新規作成して名前だけ決める※ )
- NATIPアドレス( 手動に変更し、IPアドレスを取得する )
<img width="470" alt="スクリーンショット 2020-06-27 21.52.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396218/edbd0202-ab88-0d4d-87e4-228b472875ff.png">

###3.CloudFunctionsにてコネクタを適用
#####3-1.CloudFunctionsを作成または編集し、コネクタを適用し、下りのルーティングを変更します。
- 下り設定( 先ほど作成したコネクタを選択 )
- 下り設定( 全てのトラフィックをVPCコネクタ経由でルーティングに変更 )

<img width="551" alt="スクリーンショット 2020-06-27 22.05.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396218/42769ff9-be87-0f03-72fa-302ced686099.png">

#####■補足(固定IPアドレスの確認方法)
- ①GCPコンソール上のshell( gcloud compute addresses list )
- ②GCPコンソールの( 外部IPアドレス )

<img width="493" alt="スクリーンショット 2020-06-28 9.52.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396218/a51a46e0-7ff6-5fb3-917b-040ebc3839e8.png">


また、DialogFlowからフルフィルメントをDEPLOYすると、CloudFunctionsに関数が追加されますが、リージョンが変更されるように試してみましたが"us-central1"にしかなりませんでした。そのため、DialogFlowからDEPLOYする際は注意が必要です。指定する方法があればコメントお待ちしております。

以上です。
Rubyにおけるクラスとインスタンスの違いについて

# はじめに

Rubyを学習していて出てくる、
クラスとインスタンスの概念。

初学時にどういう意味かさっぱりわからなかったので、
例を挙げながら書いていきます。



# クラスとは

値（データ）に持たせたい、共通の属性と処理に関するルールを決めるための雛形。
実体を持たないので、クラスだけではデータを動かせません。

例） 車でいうと「設計図」にあたる。
　　 設計図は、色や形（共通の属性）をどうするかとか、
　　 走る、止まる、ウィンカーを出すなど（共通の処理）をどうするか、
　　 などが書かれた紙。
　　 あくまで設計図なので、車（インスタンス）がないと動かない。

```ruby
# クラスの定義（大文字で始める）
class Car

end
```



# インスタンスとは

クラスを元にして作られるデータのこと。
実体を持っており、クラスで定義した共通の属性と処理を持っています。

例） 車でいうと「車」にあたる。
　　 車は、色や形（共通の属性）を持っていて、
　　 走る、止まる、ウィンカーを出すなど（共通の処理）ができる。
　　 設計図から作られた車そのものなので、実体もあるし、もちろん動く。

```ruby
# インスタンスの生成
class Car

end

taxi = Car.new  # newメソッドでCarクラスのインスタンスを生成して、変数taxiに代入
puts taxi  # インスタンスを出力
```
Slackを喋らせてリモートワークを賑やかにしよう:smiley:

皆さん、リモートワーク捗っていますか？この記事では、現在アクティブなSlackチャンネルの内容を発話させて物理オフィスの賑やかなイメージを取り戻すことができます。

# 使う技術の紹介

## Web Speech API

ブラウザ上で文字から音声を再生することができるAPIです。意外と多くのブラウザがサポートしていてびっくり。

- https://qiita.com/hmmrjn/items/be29c62ba4e4a02d305c

## Mutation Observer

DOM が変わったときに通知を受ける事ができる機能です。Slackのアクティブなチャンネルに新たな投稿があったのをフックするために使います。

- https://ja.javascript.info/mutation-observer

ちょっと手こずったのは、子孫の要素の変更を受け取るためには子の要素の変更を受け取らないといけないこと。つまり、`subtree:true` だけではダメで、`childList:true`も指定する必要があります。

# 発話させよう

この２つが揃ったあとは

- DOMの変更を受け取って
- テキストを発話させる

と良いです。というわけで、サクッと下記を Chrome の開発者ツールのコンソールに突っ込むと喋りだします。

```javascript
const elem = document.querySelectorAll(".c-virtual_list__scroll_container")[1];
const observer = new MutationObserver(records => {
  const record = records[records.length - 1];
  if (record.nextSibling) return;
  record.addedNodes.forEach(node => {
    if (node.ariaExpanded !== "false") return;
    const matchResult = /:\d\d(.+)/gs.exec(node.textContent);
    if (matchResult) {
      const text = matchResult[1];
      speechSynthesis.speak(new SpeechSynthesisUtterance(text));
    }
  });
});
const config = {subtree: true, childList: true, characterData: true};
observer.observe(elem, config);
//observer.disconnect(); // 発話を終了する
```

普段からコピペするのも大変なので、ブックマークレットにすると便利でしょう。下記ブックマークレットでは、再度実行すると「現在の発話を中断し」「Observerを切断し」ます。何かおかしくなったら再度実行してください。

https://gist.github.com/kijuky/053c7988684f55bf7f0e7c3ddb50cf9b

# やってみた感想

- Botがいるチャンネルとかだと微妙かも。
- チャンネルを変更すると、そのチャンネルの最後の発言が発話される。
- ~~**[追記] 過去の発言を表示するとそれを延々と喋り続けてしまう。**~~ -> 修正した
- 3日くらいは楽しめそう。