OmniAICreator/Qiita-1.07M huggingface dataset:
そうだ、SQLの勉強をしよう20

#はじめに
データの数が多くなってきたときに、使うであろう、インデックスについて学習しました。

##インデックスとは
- 検索が高速になる。
- 指定した列につけることができる。

##インデックスの作成

```sql
CREATE INDEX インデックス名 ON テーブル名(列名)
```

##インデックスの削除

```sql
DROP INDEX インデックス名
```

##インデックスはどの列に？
インデックスは、よく検索する列や並び替えで使う列に設定すると効果的です。

##最後に
`ON`を付けるあたり、英語っぽいなと思いました。
Pythonでポアソン分布

前回の[二項分布](https://qiita.com/863/items/47d6e4bec12573aba007)に引き続き今回はポアソン分布オブジェクトを作成したいと思います。素人なので間違いがあったら教えていただけると嬉しいです。

## ポアソン分布って何

導出方法から見ると、ポアソン分布は二項分布の「全試行回数」が__無限大__になったバージョンだと考えていいと思います。

### ポアソン分布の確率質量関数の導出方法
- 二項分布の確率質量関数を用意する
- 全試行回数n→∞、確率p→0 の場合の極限を求める

式変形はこちらの記事がわかりやすいです。
https://note.com/konpyu/n/ncede5754aba8

### ポアソン分布の確率質量関数
上記の方法で導出されたポアソン分布の確率質量関数は以下のようになります。

単位区間(時間 or 空間)内における平均発生回数がλ回である事象が単位区間内にk回発生する確率(eはネイピア数): 

```math
P(k)=e^{-\lambda}\dfrac{\lambda^k}{k!}
```
## なんで無限大にするのか
「地震の発生回数」のように人為的な試行が行われていないもの(つまり「全試行回数」が無いもの)を二項分布として扱うために「単位時間内に無限に試行が行われた」と仮定してるんじゃないかと考えると個人的にはしっくりきました。

こちらでも同じような説明がありました
https://bellcurve.jp/statistics/course/6984.html

## どんなときに便利か
ポアソン分布で近似できる現象の例としては「一年間の地震の発生回数」、「ウェブサイトへの一時間あたりのアクセス数」などがあります。分母が無限（と仮定できる）もの全般に使える...と言いたいところですが、実際にあてはまるのは以下のような条件を満たす場合が多いようです。

>（希少性）：時間幅 ⊿t の間に着目している事象がちょうど1回起こる確率が {\displaystyle \lambda \Delta t+o(\Delta t)}{\displaystyle \lambda \Delta t+o(\Delta t)}、2回以上起こる確率が {\displaystyle o(\Delta t)}o(\Delta t)
（定常性）：事象の起きる確率は、どの時間帯で同じ
（独立性）：事象の起きる確率は、それ以前に起こった事象の回数や起こり方には無関係
ここで、o(⊿t) は ⊿t に対して高位の無限小を表しており、⊿t のスケールに注目したときに無視できる微小量であることを表す。

(Wikipediaより抜粋)

## Pythonでポアソン分布してみた

確率質量関数を求める関数とグラフを描画する関数を持つクラスを作ってみます。ポイントはコンストラクタの引数が事象の平均発生回数λ(`known_average`)一個だけということです。
ちなみに今回は使いませんでしたがnumpyの`numpy.random.poisson()`という関数でもポワソン分布の確率質量を求めることができます。

```python
import math
import numpy as np
import matplotlib.pyplot as plt

class PoissonDistribution:
  """
    二項分布

    Attributes
    ----------
    known_average : int
      単位区間内における事象Aの平均発生回数.
    """

  def __init__(self, known_average):
    self.known_average = known_average
  
  def get_probability_mass(self, parameter_of_interest):
    """
     事象Aがk回起きる確率密度を求める.

     Parameters
    ----------
    parameter_of_interest : int
        確率質量を求めたい回数k(確率変数).
    
    Returns
    -------
    probability_mass : float
        kの確率質量.
    """

    probability_mass = (math.e ** (-self.known_average) * self.known_average ** parameter_of_interest) / math.factorial(parameter_of_interest)
    return probability_mass

  def draw_graph(self, min, max):
    """
     グラフを描画してpng形式で保存する.

     Parameters
    ----------
    min : int
        グラフの左端(回数).
    max : int
        グラフの右端(回数).
    """
    x = np.arange(min, max + 1, 1)
    y = []
    for k in range(min, max + 1):
      y.append(self.get_probability_mass(k))
    plt.plot(x, y)
    plt.savefig('graph.png')

```

## 実行
```python

# 単位区間内における発生回数が5回の事象Aのポアソン分布オブジェクトを作成する.
poisson_distribution = PoissonDistribution(5)

# 事象Aが単位区間内において3回起きる場合の確率質量を計算する.
print(poisson_distribution.get_probability_mass(3))

# このポアソン分布を左端が0回、右端が20回(k=0,1,2 ... 20)のグラフに描画する.
poisson_distribution.draw_graph(0, 20)
```

## 結果
```
0.14037389581428059 #単位区間内における発生回数が5回の事象Aが3回起きる確率質量
```
<img width="581" alt="スクリーンショット 2020-04-08 22.59.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253501/a444de4a-9fcf-0332-d81e-01e2a0694b13.png">
【初心者でもわかる】ラジオボタンの選択で項目を出し分ける方法

# どうも7noteです。選択したラジオボタンによって内容を出し分ける方法について。


男性にだけ効きたい質問だったり、学生にだけに効きたい質問。
または**特定の条件にそって要素を出し分け質問項目を変える方法**について書きます。

今回サンプルで作ったのは普段検索エンジン何を使っているのかによって質問を出し分けるフォームです。
※実際に送信ボタンの実装はしていませんので、あくまで**出し分け部分のソースのみ**に特化した記事です。


## ソース

※jQueryを使用しています。jQueryってなんだ？という方は[こちら](https://qiita.com/7note/items/45bd8efbedd557667218)

```index.html
<p>質問：普段使う検索エンジンを教えてください。</p>
<div>
  <label><input type="radio" name="engine" value="google">Google</label><br>
  <label><input type="radio" name="engine" value="yahoo">Yahoo!</label><br>
</div>
<p class="google_only">
  Googleをお使いの方に質問です。<br>
  Googleの良さを教えてください。<br>
  <input type="textarea">
</p>
```

```style.css
.google_only {
  display: none;
}
```

```script.js
$(function(){
  /* nameがengineのラジオボタンが変更された場合の処理 */
  $( 'input[name="engine"]:radio' ).change( function() {

    /* nameがengineのラジオボタンで選択されている値を取得 */
    var selectdata = $("input[name='engine']:checked").val();

    /* その値が`google`だったら追加質問項目を表示。違えば非表示にする */
    if(selectdata == "google"){
      $(".google_only").show();
    } else {
      $(".google_only").hide();
    }
  });
});
```


**結果**

![sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/535ec239-0cff-1d69-1d79-7b7ebbece00c.gif)


## 解説

基本的な動作の流れはソースのコメントに書いていますが、以下のような順番です。

・ラジオボタンが変更される
　↓
・値を取得
　↓
・**もし値がgoogleだったら**google_onlyのクラスがついた要素を**表示**
　↓
・**違った場合**、google_onlyのクラスがついた要素を**非表示**

出し分けだけであればそこまで複雑なことはせず、シンプルに考えれば簡単に作ることができます。

これに加えて、実際にgetやpost等でデータを渡すかどうかなどの話になってくると、見えていないtextareaの情報を送信させないようにするための制御なども必要になってくるので、少し難しくなるかもしれません。

## まとめ

出し分けはjavascriptで簡単に実装することができました。cssだけで行なう方法もなくはないのですが、今回のようなケースであればjavascriptやjQueryを使って実装するのが手がるで簡単かなと思います。
もしかしたらもっと簡単にできる方法もあるかも。もし知っている方がいればぜひコメントで教えてください！

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

# Topics

> 昨日の学習記録も併せて書き留めておく。結果的にはほぼ昨日の学習記録。

## 学習記録

- Markdown記法：link等、昨日の投稿記事
- 最短距離でゼロからしっかり学ぶPython入門：Alien Invasionの続き、Alien集団を動かすところまで
- 【大学数学】線形代数入門：⑧行列式の定義と性質
- PythonエンジニアによるPython3学習サイト：「pandas入門」を25日より開始

## その他

- 本日、リーマンサット・プロジェクトの新規参加者向け説明会に参加（Zoom）。活動の場を広げてゆきたいと思う。
Drupalでビューモードを取得する方法

ビューモード = コンテンツの閲覧画面で表示するフィールドの設定のことです（Viewsとは無関係）
`entity_display.repository`というサービスを利用することで取得することができます。

## 全てのエンティティタイプのビューモードの情報を取得する
```php
\Drupal::service('entity_display.repository')->getAllViewModes()
```
## 特定のビューモードの情報を取得する
```php
\Drupal::service('entity_display.repository')->getViewModes('node')
```
## 特定のバンドルの全てのビューモードのIDとラベルを取得する

```php
$view_modes = \Drupal::service('entity_display.repository')->getViewModeOptionsByBundle('node', 'page');
```
## 特定のビューモードのオブジェクトを取得する

```php
\Drupal::service('entity_display.repository')->getViewDisplay('node', 'article', 'teaser');
```
[Drupal] Viewsの結果をCSVにエクスポートする方法

今回は[Views Data Exportモジュール](https://www.drupal.org/project/views_data_export)を使用してViewsの結果をCSVにエクスポートする方法を紹介したいと思います。

## やりたいこと

任意のビューのヘッダーにCSVエクスポート用のリンクを設置して、リンクをクリックするとビューの内容をCSVにしたファイルがダウンロードされるようにしたい。

画面のイメージ:
![スクリーンショット 2021-02-26 22.36.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253501/79c855e5-2d5e-3736-e881-1c1635dd4154.png)

ダウンロードできるCSVのイメージ:

```
タイトル,コンテンツタイプ,投稿者,状態,更新
Test,記事,test,Published,"2021/01/28 - 10:00"
Test2,記事,test,Unpublished,"2021/02/26 - 22:10"
```

## Views Data Exportモジュールのインストール

まずは通常通りモジュールをインストールします。

```
composer require drupal/views_data_export
drush en views_data_export
```

## データエクスポートディスプレイの設定
次に、CSVを追加したいビューの設定画面を開き、画面左上から**データエクスポート**のディスプレイを追加します。このディスプレイに対してCSVの設定を行っていきます。
![スクリーンショット 2021-02-26 21.43.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253501/0ecb0d21-e0dd-541b-27c8-21125acca267.png)

主要なものとしては、以下の画像の設定項目から、**ファイルの形式**（CSV、TSV、XMLから選べます）、ファイルのリクエストに使用する**パス**やダウンロード時の**ファイル名**、パスに対する**アクセス制限**、**カラムの種類やラベル**を設定できます。（今回は編集ボタンなど不要なフィールドは削除します。）
![csv_settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253501/ad767048-5527-35bf-2d4a-05f85ca2fe10.png)

ちなみに、CSVへのリンクを貼りたいディスプレイの**フィルターの条件**で外部設置フィルターが設定されている場合、データエクスポートディスプレイ側でも同様の外部設置フィルターを設置しておくと、**元のディスプレイで絞込んだ結果がそのままCSVにも反映されます**。もしCSVの方は絞り込みたくないのであれば単純にデータエクスポートディスプレイ側の外部設置フィルターを削除すればOKです。

設定を保存したら、ブラウザにパスを直打ちするとCSVがダウンロードできるようになります。（この設定画面右上の「データエクスポートを表示」をクリックでもダウンロードできます。）

## データエクスポートディスプレイへのリンクの設置

ここでCSVへのリンクを貼りたいディスプレイの設定画面を開き、ヘッダーの「追加」をクリックします。
![page_header.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253501/cee1f2c3-ce08-b6ee-5365-37f8eeafac34.png)

**Link to display**をチェックし、保存します。**表示**でさきほど作成したディスプレイを選択します。**ラベル**にはリンクテキストにしたい文字列を入力します。
![スクリーンショット 2021-02-26 22.22.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253501/0142a135-0c0b-049e-e1b5-345797ff019b.png)

ここでビューを保存します。

CSVへのリンクが表示されているのが確認できると思います。
![スクリーンショット 2021-02-26 22.36.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253501/d881fde8-8ef9-6bf5-579d-f60101af2054.png)

外部設置フィルターで絞込んだ状態でCSVをエクスポートしたら...
![スクリーンショット 2021-02-26 22.59.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253501/82042848-1072-ae6d-1403-47b16537caea.png)

中身もしっかり絞り込まれてますね :ok_hand: 

```
Title,"Content type",Author,Status,Updated
Test2,記事,test,Unpublished,"2021/02/26 - 22:10"
```

というわけで、Viewsの結果をCSVにエクスポートする方法の紹介でした。
PythonでIDを取得してオブジェクトに戻す

# TL;DR
PythonでIDを取得してオブジェクトに戻す小技の紹介です．

# IDを取得する
Pythonでは[id関数](https://docs.python.org/ja/3/library/functions.html#id)を使うことでオブジェクトのIDを取得することができます．
これはオブジェクトを一意に表すIDです．

```python
>>> val = 5
>>> id(val)
140725152520080

型にもあります
>>> val = int
>>> id(val)
140725152283920
```

# オブジェクトに戻す
一意に表すIDであればIDからオブジェクトを取得できるのでは？という話です．

\_ctypesモジュールのPyObj_FromPtrという関数を使用します．

```python
>>> import _ctypes
>>> val = 5
>>> id(val)
140725152520080
>>> _ctypes.PyObj_FromPtr(140725152520080)
5
```

インスタンスオブジェクトでも．

```python
>>> import _ctypes
>>> class Test:
...     def __init__(self, val):
...             self.val = val
...
>>> test = Test(10)
>>> test.val
10
>>> id(test)
2441514736128
>>> test_from_id = _ctypes.PyObj_FromPtr(2441514736128)
>>> test_from_id.val
10
```

# 使い道
マルチプロセスを使う際，プロセス間通信の引数はシリアライズ可能である必要があります．
インスタンスオブジェクトを渡す際は引っかかることが多いかと思います．
id関数と\_ctypes.PyObj_FromPtrを使うことで，IDだけ渡して，渡した先で復元するということができます．

また，IDの値はint値なのでオブジェクトの代わりに保持しておく，ということができます．
（ポインタなので変わらんじゃんという話もありますが．．．）

# 懸念
スコープなのか呼び出し階層なのかは分かりませんが，IDの値が別のオブジェクトになっていることもあります．
なるべく同じスコープ，短い呼び出し階層で使うことをお勧めします．

# まとめ
Pythonにはこういったメタ関数が多くあるので面白いですよね．
ご参考になれば幸いです．
【GAS】スプレッドシートからInsert文を作成する手順

## この記事について

This is for 自分 as メモ

## 概要

A1セルにテーブル名を入れる。

2行目はカラム名を羅列。3行目以降はレコードとなる情報をセットする。

また、` result ` シートを予め作成しておく。

![スクリーンショット 2021-02-26 22.47.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494166/d75586ce-f9f8-c64f-a3e6-cbeef490d133.png)


そのうえで、Google Apps Scriptを開いて下記を実行。


```javascript
function makeInsertQuery() {

 let spreadSheetByActive = SpreadsheetApp.getActive();
 let sheetByActive = spreadSheetByActive.getActiveSheet();
 let range = sheetByActive.getRange(1,1,sheetByActive.getLastRow(), sheetByActive.getLastColumn());
 let headerRowIndex = 1;
 let firstValuesRowIndex = headerRowIndex + 1;
 let cells = range.getValues();
 let numRows = range.getNumRows();
 let numColumns = range.getNumColumns();
 let tableName = cells[0][0];
 let columnNames = [];

 for (var i = 0; i < numColumns; i++) {
  columnNames.push(cells[headerRowIndex][i]);
 }

 let prefix = "INSERT INTO " + tableName + " (" + columnNames.join(",") + ") VALUES (";

 let deleteTarget = spreadSheetByActive.getSheetByName('result');
 spreadSheetByActive.deleteSheet(deleteTarget)
 let newSheet = range.getSheet().getParent().insertSheet();
 newSheet.setName('result')

 let targetCell = newSheet.getActiveCell();

 for (var i = firstValuesRowIndex; i < numRows; i++) {
    var values = [];
    for (var j = 0; j < numColumns; j++) {
      values.push('"' + cells[i][j] + '"');
    }
    targetCell.setValue(prefix + values.join(",") + "); ");
    targetCell = targetCell.offset(1, 0);
  }
}
```

結果。

![スクリーンショット 2021-02-26 22.47.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494166/54904cd0-1767-2bba-73ea-d46b265a3883.png)

## 参考文献

- [GoogleスプレッドシートからINSERT文を生成するGoogle Apps Script](https://qiita.com/bati11/items/4af429ba29493adeb22c)
毎日投稿（JavaScriptの復習）TODOアプリの実装

#毎日投稿

アウトプットしない身にならないで、毎日投稿を始めました。
毎日の勉強内容を書いていきます。

本日はJavaScriptの復習しました。
２週間前ぐらいにある程度勉強したのですが、
身になっていないところがあったので復習をしました。

##復習した内容は以下です。
・テンプレート文字列 
・アロー関数 =>
・分割代入 {}
・デフォルト値 =
・スプレッド構文 ...
・mapやfilterを使った配列の処理
・三項演算子 ? :
・論理演算子の本当の意味を知ろう && ||

この復習で、”mapやfilterを使った配列の処理”の部分が身になった気がします。
例えば、配列の処理時に私は毎回、for文を使っていました。
for文が悪いということではないと思いますが、
これからはできる限りにmapやfilterといったメソッドを使っていきます。

アウトプットとして、最低限のHTML＆CSSとJSでTODOアプリを作りました。
ソースコード展開します。。。
⬇️
https://github.com/takeshi1201/ToDo-javascript.git

明日はSPA,Reactの基本構文を中心に勉強していきます。
今日もお疲れ様でした。
AthenaのQueryをMysqlと同じ感覚で使ったときにひっかかった部分まとめ

# AWS Athena は便利
AWS Athenaを使うと、S3内のファイルに対してSQLクエリを実行できます。環境構築やデータの前加工が不要で、簡単に利用できます。非常に便利です。
S3にログが自動で溜まるようにするのがベストですが、とりあえずログファイルをS3にアップロードするだけでも十分使えます。
普段は開発を行っていて、Athenaはちょこちょこ触るくらいであれば10$/月もいかないかと思います。安い。

Athenaでできることと使い方のイメージをつかみやすい記事
→[Amazon Athenaではじめるログ分析入門](https://qiita.com/miyasakura_/items/174dc73f706e8951dbdd)

## Mysql感覚でAthenaを触るとできないこと、違和感が起こる部分
普段はMysqlを使ってます。
AthenaのQuery環境はMysqlと完全に同じではないので、できないことがあります。
2021/02/26 時点での状況です。

### 文字列の囲みはシングルクォーテーション

ダブルクォーテーションで囲むとエラーが出ます。

```
SELECT * FROM alb_logs WHERE elb_name LIKE "%elb%";
```

↓ エラー

```
SYNTAX_ERROR: line 1:57: Column '%elb%' cannot be resolved
```


### コメントアウトは /* */ のみ
「\#」や、ましてや「//」は使えません。
↓ エラー

```
line 3:1: extraneous input '#' expecting {<eof>, ~
```


### CREATE TABLE 時にカラム数があわないと、SELECT 時にエラーが出る
CREATE TABLE したときにエラーを出しておいてほしいもんですが、実際はSELECTをかけるまでエラーは出ません。
ログをカラムにばらす際の正規表現の指定がうまくいってなくて詰まりました。

↓ エラー

```
HIVE_CURSOR_ERROR: Number of matching groups doesn't match the number of columns
```

参考 [AWS公式 Athenaでアクセスログを分析する](https://aws.amazon.com/jp/premiumsupport/knowledge-center/analyze-logs-athena/)


## まとめ
簡単に触った範囲でこれくらい出てきました。
詰まるとうっとうしいですが、それ以上にAthenaが便利なことには間違いないです。
ほかにもコツなどあればぜひ教えてください。
VS code1　使えるショートカット

現在行をコメント化	
コマンドパレットから［行コメントの追加］コマンドを実行	
>Windows／Linux：
［Ctrl］＋［K］→［Ctrl］＋［C］キー
macOS：
［Command］＋［K］→［Command］＋［C］キー


行コメントのコメント化を解除（アンコメント）
コマンドパレットから［行コメントの削除］コマンドを実行	

>Windows／Linux：
［Ctrl］＋［K］→［Ctrl］＋［U］キー
macOS：
［Command］＋［K］→［Command］＋［U］キー
【体験記】MS-500を取得するまでの道のり

# はじめに
MS-500とは、Microsoft365・ハイブリット環境のセキュリティやコンプライアンスを軸にした
認定資格でごさいます。直近だと2020/11/24に試験内容が更新されました。

調べてみても、受験体験記があまりなくどのように進めればいいのかわからなかったので、
自分のメモ・試験を受けようかな～と考えている人向けに書いてみます。

 [MS-500について](https://docs.microsoft.com/ja-jp/learn/certifications/exams/ms-500 "MS-500")

 [MS-500のスキルシート](https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE3VEI3)

 [以前受験したAZ-900について](https://qiita.com/Tomtams/items/d653c3baefa454e4ba7b)

# ないよう
IDとアクセスの実装および管理 (30-35％)
脅威保護の実装および管理 (20-25％)
情報保護の実装および管理 (15-20％)
Microsoft 365 のガバナンスおよびコンプライアンス機能の管理 (20-25％)

なんじゃこりゃこれと思いましたが、業務でAzureActiveDirectoryを触ったりしたことがあるため、
IDとアクセス実装の部分は理解できる部分はありましたが、触ったこともない部分がありました。
しかし、ガバナンスおよびコンプライアンス機能の管理の部分はほぼ触ったことがないためしたことを覚えています。

# すすめかた
 [MS-500について](https://docs.microsoft.com/ja-jp/learn/certifications/exams/ms-500 "MS-500")のページの下の方にある、ラーニングパスをまずはやりました。ここで予めの土台を作ってから何度かラーニングパスを実施しました。

AZ-900では過去問がWeb上に掲載されておりますが、MS-500はほとんど情報がなく自分自身で例題を作り、Azure上ではどのように操作するか、ここの操作はどのように選択するのかなど考えて行いました。

AZ-900の記事にも書いたように、Azureの無料サブスクリプション + Microsoft E5 の試用版で１ヶ月みっちり勉強するのが操作するという点も含めてよいのかもしれません。


#むずかしかったこと
O365のコンプライアンスガバナンスを学習するに当たり、M365管理センターを開いて実際に操作をしていたのですが、
Microsoft 365 コンプライアンス センターに移行中の部分もあり、学習をする場所を探すことに苦労しました。

#やってよかっこと
IDとアクセスの実装および管理が試験の範囲の3割をしめているのですが、
条件付きアクセスのシーンをいくつか作成し、実際にAzure上にVMを建てて、実環境と仮想環境でいろいろ触ってみました。
条件付きアクセスで社外からの場合はMFA認証を必要とするが、社内の場合はMFA不要など自分で設定することで、
動作についても理解できるのでおすすめです。（個人的には面白かった）

AIP(Azure Information Protection)も実際にポリシーを作成し、Word文章にクレジットカードを記載したらAIPが発動するなど、触ってみなければ結果がわからないことも面白かったです。

実際に試用版テナントも作成したので、管理者ロールをいじって触ってみたり、ログインの際にどのようなログを吐くのは見てみるのも学習の一つになるのかもしれません。

#しけんけっか
１回目の試験は、自宅でできるオンライン試験で実施しました。
１回目は勉強不足で不合格となってしまい、一番点数配分の高い、IDとアクセスの実装および管理が全体的に回答ができていない状態でした。もちろん試験の問題はメモ書きなどもできないため、自分の記憶から取り出し自信のない回答を思い出しました。非常に悔しかった反面、自分が理解できていない部分を知ることができよい機会でもありました。

２回目の試験はテストセンターで受験しました。15時の試験で予約したのですが思った以上に人が多かったことを今でも覚えています。
1回目の成果もあるのかすらすらと回答ができてしまい、これで大丈夫かなと逆に不安になってしまったのですが、不安になると立ち戻れないタイプの人間なので、男らしく試験を終了し、結果を眺めました。




結果としては合格点に達しており、声を出すことはできなかったのですが心の中でガッツポーズをしました。🎉🎉🎉🎉
試験結果の用紙を渡されましたが、白黒で会場を出た後に笑ったことを今でも覚えています。

Windows Server などで土台となるIDについて資格取得ができたことで今後の強みにでもなるのかなーと思います。

おわり。
Python の開発環境問題には direnv が最高だった件

# よくある悩み

- *「Python で開発するけどローカル環境汚したくないんだよなー」*
- *「Python コンテナ立てて VSCode でアタッチしてもいいけど拡張機能の管理がめんどいなー」*
- *仁義なき `virtualenv` vs `pipenv` vs `venv` 派閥争い* 



# そんなあなたに direnv

[https://github.com/direnv/direnv](https://github.com/direnv/direnv)

一言でいうと、ディレクトリ毎に環境を分けるもの



## つまり何 ??

venv と組み合わせると、direnv を有効化したディレクトリに移動しただけで venv を `activate` することが可能

また、環境変数も同様に自動でセットすることが可能



# 使い方

## インストール

Mac の場合は `brew install direnv` 、Windows は知らん



## 設定

`~/.zshrc` に追記

> $EDITOR で指定するのは自分の好きなやつ

```sh
export EDITOR=/usr/local/bin/nvim
eval "$(direnv hook zsh)"
```



有効化 `target_dir` でやってみる

```sh
mkdir target_dir
cd target_dir
python -m venv venv
echo "source venv/bin/activate" > .envrc
direnv allow
```

- direnv はディレクトリに移動した際に自動で `.envrc` を読み込む

- `.envrc` の編集は `direnv edit` でやってもいいし、直接編集してから `direnv allow` で有効かしてもいい

- `export HOGE=hoge` と記述しておくと、そのディレクトリ配下にいる間だけその環境変数が有効化される



## 設定完了!! 👌

これで `target_dir` に移動すると、勝手に venv が有効化するゾ!!
Distance calculation と Grover optimization に関する一考察

# 今回の記事は、考察であり、正確性は一切保証しません。

量子k-meanの論文 [K-Means Clustering on Noisy Intermediate Scale Quantum Computers](https://arxiv.org/abs/1909.12183)
を読んでいて、以下の記述が気になりました。

>Distance calculations for K-means are done using this method and the nearest centroid is found using Grovers Optimization [11] subroutine.

解説すると、この論文ではK-meanアルゴリズムにおける距離（分類したいデータと現状の重心たちとの距離）を量子回路で計算しています。[^1]
距離計算の結果は、量子ビットが$0$である確率という測定結果として得られます。（古典情報です）
k-meanで本当にやりたいのは、距離の数値のリストを得ることではなくて、その中で最小を与えるindexを知ることです。
それがGroverのアルゴリズムでできる　というのがこの論文での主張で、それは正しいのですが、教科書的なGroverのアルゴリズムでは足りません。
もちろん文献を調べれば"答え"があると思うのですが、今回はここを**自分なりに**考えてみたいと思います。

## Groverのアルゴリズムで最小値を探すには？

Groverのアルゴリズムは、解であるものを量子並列に検証・マーキングしながら干渉させることで
最終的に解だけを生き残らせるアルゴリズムです。
解は複数あっても構いませんが、解の個数は既知であることが前提です。
とはいえ既知でない場合は、QAEなどの方法で推定することは出来ますので、それほど厳しい制約ではありません。
(これをQuantum counting と呼ぶことがあります。そのうち記事にします）

しかしこれで最小値を見つけるにはどうしたらいいのでしょう？
与えられた数値が最小値であるかどうかを検証するオラクル　というのは、明らかに最小値を知っていないと無理そうに思えます。
解を知らないと作れないオラクルは意味がありません。（以下の過去記事も参照下さい）
[Groverのアルゴリズムと、解を知らないオラクル](https://qiita.com/notori48/items/b30e80df61cbcc2306db)

しかしGroverアルゴリズムを少し拡張するだけで、この問題を回避できます。
それがDHアルゴリズムです。

## DHA (Durr and Hoyer Algorithm)

DHアルゴリズム(DHA)は、DurrとHoyerが提案した最小値探索Groverアルゴリズムです。
`Durr and Hoyer, "A Quantum Algorithm for Finding the Minimum"`
最小を探したいことは割とあるので、DHAはすごく重要なのですが、あまり教科書や解説記事には出てこない気がしますね。[^2]

DHAのアイデアは単純で、反復法により徐々に探索範囲を狭めて追い込んでいくものです。
私もあいまいな理解ですが、概ね以下のようなものです。[^3]

1. 数値のリストからランダムに１つ選んでくる
2. 選んだ数値より小さい数値を持つデータたちをまとめてマーキングする（オラクル）
3. Grover増幅し、測定する。マーキングされた状態のどれか１つが得られる。これは1.で選んだ数値より小さい。
4. 3.で得た数値を基準として、2~3を繰り返す。値が更新されなくなったら最小値。

この場合、オラクルに要求されるのは
「与えられた値以下のものをマーキングせよ」
なので、最小値を知っている必要はありません。

DHAはGrover Adaptive Search (GAS)とも言われるみたいです。
GAS in qiskit document(https://qiskit.org/documentation/tutorials/optimization/4_grover_optimizer.html)

## オラクルの構成は？

しかし、以前として「どうやってオラクルを作るのか」がはっきり理解できません。
自分なりに考えてみます。

まず、距離の値を$N$ bitでデジタル化します。例えば $N=3$としてみます。
距離のリスト(2進数)が、
1) 000
2) 001
3) 101
4) 111
だったとしましょう。ランダムに選んだものが 3)の `101` であったとします。
101より小さい値であるためには、
1. 左端ビットが0であれば、無条件に該当。1であれば次の桁を見る。
2. 真ん中ビットを見て1であれば非該当。0であれば、次の桁を見る。
3. 右端のビットを見て、0であれば該当。1であれば非該当。
このような段階的な判定に帰着させられます。
これは明らかに論理回路で組めますので、量子ゲートに出来ます。[^4]

あとはGrover増幅後にサンプリングすればよいです。
得られた値を基準値として、同じことを繰り返します。(DHA)

これだけだと最小の距離の数値がわかるだけなのですが、データのindex番号も補助ビットとして条件づけておいて

$| index \rangle \otimes |distance \rangle$
としておけば問題ないでしょう。

# 結論
あっているかはわからないが、自分で処理のフローを考えるのは面白い。

[^1]: 量子的にやる利点は計算量です。$N$量子ビットの状態は$2^{N}$次元複素ベクトルとして扱えるので、ここに内積を計算させたいベクトルを埋め込んでやります。ベクトルの次元が$N$であったとしても量子ビットが$\log_{2}(N)$個あれば埋め込めてしまいます。距離計算はいくつかの量子ゲート操作で半ば自動的に進ませることができ、最後に測定で距離の数値を抽出できます。
[^2]: 例えば、とある最尤推定の論文でしれっと出てきました。
[^3]: Grover増幅は増幅回数が適切でないといけません。注意です。
[^4]: ぶっちゃけ、$y_{binary}-101$ を古典的に計算してから埋め込むとずっと楽が出来る気もしますが、、
numpyでシフト演算を使って符号無し⇒符号有りに変換する

# TL;DR
numpyの符号無しのndarrayをシフト演算を使って符号有りに変換する方法の紹介です．

# numpyのシフト演算
numpyは要素毎にシフト演算することができる．
シフト演算も例外できる．

```python
>>> import numpy as np
>>> val = np.arange(5)
>>> val
array([0, 1, 2, 3, 4])
>>> val << 4
array([ 0, 16, 32, 48, 64], dtype=int32)
>>> val >> 1
array([0, 0, 1, 1, 2], dtype=int32)
```

# 符号無し => 符号有りに変換
## astype
astype関数を使って符号無しから符号有りに変換することはできる．
8bitであれば，uint8からint8に変換すれば問題ない（16bit/32bit/64bitも同様）．

```python
>>> import numpy as np
>>> val = np.asarray([255, 0, 127, 128], dtype=np.uint8)
>>> val
array([255,   0, 127, 128], dtype=uint8)
>>> val.astype(np.int8)
array([  -1,    0,  127, -128], dtype=int8)
```

しかし，4bitや12bitといったデータを扱う場合こうはいかない．
（4bitや12bitといった型は存在しないため）
要素数が少ない場合は2進変換->10進変換をfor文でループしたり，frompyfuncを使えば良いが，要素数が多いと時間がかかる（numpyの意味がない）．
np.whereを使うとしても要素数が多いと時間はかかってくる（インデックスアクセスが遅くなる）．

そこでシフト演算を使うことで解決を図る．

## シフト演算
numpyでは型の上限のbitまで左シフトしてから右シフトすると符号有りに変換される．
最上位bit＝符号bitに情報が残るようである．

符号有り8bitで詳しく説明する．

```
1を2進で表すと以下
1 → 00000001

これを7bit左シフト
000000001 << 7
> 10000000

10進で表すと
10000000 → -128

7bit左シフトした分を右シフト
10000000 >> 7
> 00000001 （理論的にはこっち）
> 10000001 （実際はこっち）

10進で表すと
00000001 → 1
10000001 → -1
```

つまり，4bitだと8bit，12bitだと16bitで情報を持つことになるので，4bit左シフトして右シフトすると符号有りに変換できる．
（24bitだと32bitなので8bitシフトになる）

```python
>>> import numpy as np
>>> val = np.arange(pow(2, 4), dtype=np.int8)
>>> val
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15],
      dtype=int8)
>>> val << 4 >> 4
array([ 0,  1,  2,  3,  4,  5,  6,  7, -8, -7, -6, -5, -4, -3, -2, -1],
      dtype=int8)
```

# まとめ
この特性を活かすことで，シフト演算を使って高速に4bitや12bitを符号無しから符号有りに変換できます．
（4bitや12bitといっていますが，何bitでもOKです）
ぜひ試してみてください．
A.I.VOICE 琴葉 茜・葵 exVOICE」収録音声一覧（PDFファイル）をCSVに変換

# ダウンロード
```
wget https://aivoice.jp/pdf/exVOICE_kotonoha.pdf
```

# tabula-javaでコマンド変換

JAVAをインストール

```
# tabula-javaをダウンロード
wget https://github.com/tabulapdf/tabula-java/releases/download/v1.0.4/tabula-1.0.4-jar-with-dependencies.jar -O tabula.jar

java -jar tabula.jar -o akane.csv -p 1-7 -l exVOICE_kotonoha.pdf
java -jar tabula.jar -o aoi.csv -p 8-14 -l exVOICE_kotonoha.pdf
```

# pdfplumberで変換

## インストール
```
pip install pandas
pip install pdfplumber
```

# CSV変換
```python
import pdfplumber
import pandas as pd

with pdfplumber.open("exVOICE_kotonoha.pdf") as pdf:

    data = []

    for page in pdf.pages:

        table = page.extract_table()
        data.extend(table)

dft = pd.DataFrame(data, columns=data[0])
dfg = dft.groupby((df["通しNo"] == "通しNo").cumsum())

dfs = [g.iloc[1:].reset_index(drop=True) for _, g in dfg]

for i, df in enumerate(dfs):
    df.to_csv(f"a_i_voice{i}.csv", encoding="utf_8_sig")
```
rspec実行時エラー Failure/Error: name { Faker::Name.name }

#　概要
rspecを導入し、その後
factory_botを導入し、
rspecを実行した際に、

```
Failure/Error: name { Faker::Name.name }
NameError:
       uninitialized constant Faker
```
というエラーが発生

# 解決
gem 'faker' が　development, test do　の場所に
記載されていませんでした、、、

# まとめ
gem を記載する場所は注意深く確認しようと思います！
apple m1 でDockerが動かない


ファイアウォールの `Block all incoming connections` をオフにすれば動く

`Block all incoming connections` 自体は、開発中のサーバ立ち上げるたびに外部から通信許可しますか的なプロントが出るので、それを全てブロックする設定なんですが、全然ネットでも引っ掛からなかったのでみんなもしかしてファイアウォール設定していないとか。。Macって初期状態で、いまだにファイアウォールオフになってるんですよね。そのままカフェとか行くと危ないんですよね。。みんな設定ちゃんとしてるんですかね。


参考にしたサイト
* https://github.com/docker/for-mac/issues/5130#issuecomment-757337509
* https://github.com/docker/for-mac/issues/5140
WebRTCとは？

#はじめに
音声や映像配信といったリアルタイム通信インフラに従事しており、WebRTCが気になったので調べてみました。
ちょうど一か月ほど前に標準規格入りをし、今後さらなる発展が臨めることからも今のうちに学んでおきたいと考え、記録していこうと考えています。普段からネットワークに取り組んでいるので、結構すんなりコンセプトを理解できました。

#WebRTCとは
WebRTCとは「Web Real-Time Communication」の略称です。
HTML5で新しく策定されたAPIの規格で、ウェブブラウザやモバイルアプリでリアルタイム通信(音声や動画など)を実現するための技術(オープンソース)になります。
WebRTCにおけるAPIの仕様は以下サイトに詳しく記載されています。
https://developer.mozilla.org/ja/docs/Web/API/WebRTC_API
様々なAPIを組み合わせることにより、音声の変換や映像のキャプチャ、画像処理や顔検出なんかもできるようになります。これらAPIはどんどん変わっていくので、チェックが必要です。

また、このWebRTCは様々なシーンで利用されており、特にWeb会議やオンライン動画配信などが挙げられます。
将来的にも利用シーンが広がっていくことが予想されており、遠隔医療やIoT分野、AR/VR分野などにも利用されると考えられています。

##P2P通信
WebRTCはブラウザやアプリ間で動画や音声などのリアルタイム通信を実現します。このブラウザやアプリの通信はP2P(ピアツーピア)通信で行います。
一般的な通信は所謂サーバ・クライアントモデルと言って、サービス（処理を行う）を提供するサーバと、サービスをリクエストするクライアントで構成され、サーバを介してお互いが通信し合います。
P2Pでは、サーバ・クライアントモデルのようにサーバを介して通信を行うのではなく、サーバを介さずクライアント同士がつながることで処理を行います。
メリットとしてはメッシュ構造でつなぐことによりダウンタイムがなくなる(ゼロダウンタイムになる)ことや、よりリアルタイムな通信を実現できることが挙げられ、有名なところではブロックチェーン技術においてもこのP2Pモデルで通信が行われています。
![P2P.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644352/07144ef9-3512-8cfb-5c40-b9be45c51f72.gif)


##シグナリングサーバ
P2Pで通信を行うと言っても、予め通信相手の情報（IPアドレスやポート番号）を知っている必要があります。ですので、P2P通信を行う前にVoIPなどでよく出てくる「シグナリング」というものを行います。
シグナリングとは、ダイヤルを発信した後に着信した相手が受話器を上げるまでの間に行われる情報のやり取りで、相手のIPアドレスやポート番号を知るために行われます。
WebRTCにおいても、このシグナリングを行う「シグナリングサーバ」が必要になります。このシグナリングサーバによってこれから通信を行う相手の情報を取得しています。
このシグナリングにおいてやりとりする情報を見ていきます。
####・ ICE ( Interactive Connectivity Establishment )
クライアント間でP2P通信を行う場合、それぞれのクライアント（デバイス）が存在するネットワークにおいてNATが設定されていると、そのクライアント同士はP2P通信ができない状況になります。

ここでNATについて簡単に説明をします。NATとは「Network Address Translation」のことで、組織内などのLANで使われるIPヘッダ内のプライベートIPアドレスをインターネットで使われるIPヘッダ内のグローバルIPアドレスへ変換する用途で使われます。主にLANとインターネットの境界に存在するルータで実装されます。

ICEでは、NAT配下の端末やネットワークにダイレクトに到達できない問題を解決し（これをNAT越えと言います）、P2P接続するための経路を決定します。
ICEには、「STUN」と「TURN」というサーバサイドの技術が登場します。これについては深い内容になりますので、以下のサイトを参照すると良いと思います。非常にわかりやすい内容になっています。
https://qiita.com/okyk/items/a405f827e23cb9ef3bde

また、以下の図が非常に仕組みを理解しやすいです。
![ivrpowers-turn-stun-screen.005.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644352/ce98a143-33b9-cd62-d538-ba7ea169f35d.jpeg)


####・ SDP ( Session Description Protocol )
P2Pを行うにも、相手と所在位置(IPアドレス、ポート番号)を共有したり、送受信するデータ形式などを予め決めておかなければいけません。そこで、SDPはシグナリングを行うブラウザ同士で交換する情報のフォーマットを規定します。
それぞれのブラウザの情報を示し、文字列で表現されます。
内容は以下の通りです。
・メディアの種類（音声、映像）、メディアの形式（コーデック）
・IPアドレス、ポート番号
・P2Pのデータ転送プロトコル(WebRTCではSecure RTP)
・通信で使用する帯域
![sdp-for-webrtc-21-638.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644352/1b39ed1a-0de3-5f34-5e68-6de88c3d582b.jpeg)



##まとめ
WebRTCをオンプレで実現しようとするとハードルが高いなと個人的に感じています。
今後は実装を通して、より理解を深めていきたいと思います。
（個人的にAWSのKinesis Video Streamsが気になります）

##参照
https://udemy.benesse.co.jp/development/blockchain/p2p.html
https://blog.ivrpowers.com/post/technologies/what-is-stun-turn-server/
https://www.slideshare.net/iwashi86/webrtc-for-sdp
HTTPステータス一覧

HTTPコードの一覧を調べてみた！


　　
**サーバーのステータスコードの一覧**
サーバーからブラウザに返してくるコードのことをステータスコードといいますが、これには
**・100番台 案内（インフォメーション）**
**・200番台 正常処理**
**・300番台 移転通知**
**・400番台 （クライアントにおける）処理失敗**
**・500番台 サーバーエラー**
があり、400番台と500番台がいわゆるエラーコードとなります。正常処理である200番台は通常ブラウザに表示されることはありませんので、ここでは300番台～500番台までの主なステータスコードについてのみ取り上げます。
##300番台		
300	Multiple Choices
複数ページの利用が可能です。

301	Moved Parmanently
このアドレスは違うアドレスに移動しました。

302	Moved Temporarily
このアドレスは一時的に別のアドレスにおいています。

303	See Other
他のページを参照してください。

304	Not Modifie
アクセスは許可されたが、対象の文書は更新されていなかった。

305	Use Proxy
LocationフィールドのProxy経由でないとアクセス許可されません。

307	Temporary Redirect
このアドレスは一時的に別のアドレスに属しています。

##400番台		
400	Bad Request
タイプミス等、リクエストにエラーがあります。

401	Unauthorixed
認証に失敗しました。（パスワードを適当に入れてみた時などに発生）

402	Payment Required
（将来の使用のための予約コード）

403	Forbidden
あなたにはアクセス権がありません。

404	(File)Not Found	
該当アドレスのページはありません、またはそのサーバーが落ちている。

405	Method Not Allowed
許可されていないメソッドタイプのリクエストを受けた。

406	Not Acceptable
Acceptヘッダから判断された結果、受け入れられない内容を持っていた。

407	Proxy Authentication Required
最初にProxy認証が必要です。

408	Request Time-out
リクエストの待ち時間内に反応がなかった。

409	Conflict
そのリクエストは現在の状態のリソースと矛盾するため完了できなかった。

410	Gone
そのリクエストはサーバでは利用できず転送先のアドレスも分からない。

411	Length Required
定義されたContent-Lengthの無いリクエストを拒否しました。

412	Precondition Failed
1つ以上のリクエストヘッダフィールドで与えられた条件がサーバ上のテストで不正であると判断しました。

413	Request Entity Too Large
処理可能量より大きいリクエストのため拒否しました。

414	Request-URI Too Large
リクエストURIが長すぎるため拒否しました。

415	Unsupported Media Type
リクエストされたメソッドに対してリクエストされたリソースがサポートしていないフォーマットであるため、サーバはリクエストのサービスを拒否しました。

416	Requested range not satisfiable
リクエストにRangeヘッダフィールドは含まれていたが、If-Rangeリクエストヘッダフィールドがありません。

417	Expectation Failed
Expectリクエストヘッダフィールド拡張が受け入れられなかった。

##500番台		
500	Internal Server Error
CGIスクリプトなどでエラーが出た。

501	Not Implemented
リクエストを実行するための必要な機能をサポートしていない。

502	Bad Gateway
ゲートウェイやProxyとして動作しているサーバがリクエストを実行しようとしたら不正なレスポンスを受け取った。

503	Service Unavailable
そのアドレスは事情によりアクセスできません。

503     Mapping Server Error
クリッカブルマップで、変なアドレスを指定した。

503     Too many users
この時間このページにアクセスできる定員オーバーをしました。

503     Method Not Allowed
CGIで送信時にPOSTかGETの一方しかできないのに、違う方を行った。

504	Gateway Time-out
リクエストを完了するために必要なDNSなどのサーバからレスポンスを受信できなかった。

505	HTTP Version not supported
サポートされていないHTTPプロトコルバージョンを受けた。

　


自分が経験したステータスコードよりはるかに多いので
、その都度エラーなり起こったタイミングで再確認していけたらいいかなと思います。一気に覚えるのは無理そうなので...。
基本的にずっと**２００**ならありがたい。
VSCodeプラグインを活用してdocstringを簡単に書こう

# やりたいこと

Pythonにdocstringをできるだけ簡単に記述したい。
※VSCodeを使用することを前提にしています。

# 環境

VSCode: 1.53.2
Python Docstring Generator: 0.5.4

# プラグインの設定

**Python Docstring Generatorのインストール**

VSCodeのExtensionsで"docstring"を検索すると上位に出てくるので選択してインストール。
![スクリーンショット 2021-02-24 0.41.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557050/0dfaecf7-fdc7-231f-dcfe-efb0c38c109e.png)


**docstring設定の変更(必要に応じて)**

⌘+,(windowsの場合はctrl+,)を押下して設定画面を開くと、Python Docstring Generatorの設定を変更できます。
デフォルトはGoogleフォーマットです。

# 使い方

docstringを挿入する箇所（classやdefの次の行）に、`”””`を入力しEnterを押すだけで自動で挿入されます。

![docstring_make.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557050/21861e3c-6d6c-5989-8a16-e9d9f2e7dd4e.gif)


**注意**
methodのdocstring（ファイルの先頭）はインデントされてしまうバグ有り。

# 終わりに

Python Docstring Generatorを使用するとPythonファイルへのdocstringの記述がとても簡単になります。
docstringの書き方は参考ページの内容がわかりやすいと思います。

---

# 参考ページ

[GoogleスタイルのPython Docstringの入門](https://qiita.com/11ohina017/items/118b3b42b612e527dc1d)
[Pythonのdocstringの書き方](https://qiita.com/kanatatsu64/items/d3ef79be0ae0409c8681)
[[Python]可読性を上げるための、docstringの書き方を学ぶ（NumPyスタイル）](https://qiita.com/simonritchie/items/49e0813508cad4876b5a)Python Docstring Generator
PHPでチェックサム(XOR)を取得する実装方法

#前書き
　あまり具体的なPHPでのチェックサム(XOR)の実装方法の記事がなかったので記録も兼ねて作成してみました。
　実行速度がより速い方法は色々あると思いますので、あくまで参考程度にしてください。

#実装
```php

$data = "対象文字列"; 
$binary_data = bin2hex($data); //文字列をバイナリデータ(16進数)に変換
$binary_array = str_split($binary_data, 2); //バイナリデータを2bit毎に分ける
foreach($binary_array as $key => $binary) {
  if($key === 0) {
    $check_sum_first = sprintf('%08d', decbin(hexdec($binary))); //16進数⇒10進数⇒2進数(0左詰めの8bit)
    continue;
  }
  $check_sum_second = sprintf('%08d', decbin(hexdec($binary)));
  // 1bitずつ排他的論理和(xor)を求める
  for($i = 0, $i < strlen($check_sum_first), $i++) {
    $check_sum_first[$i] = intval($check_sum_first[$i]) ^ intval($check_sum_second[$i]);
  }
}
//2進数⇒10進数⇒16進数⇒デコード処理
$check_sum = hex2bin(dechex(bindec($check_sum_first)));
```

#後書き

　実装見てわかる通り、泥臭いやり方をしています。
　文字列を16進数に変換後、2bit毎に配列に分けて2進数(8bit)に変換してから1bit毎に排他的論理和を求めています。
　実際に正しくチェックサムの結果が出てるかどうかはツール等を使わないとわからないので
バイナリエディターやXOR算出ツールなどを利用して確認してみてください。
VSCodeのSwaggerEditor拡張機能をオススメしたい

`VSCode + Swagger` で検索すると、**Swagger Viewer** を勧める記事はたくさん出てくるものの、なぜか **OpenAPI (Swagger) Editor** の記事が見当たらないので、おせっかいながらヨイショしておく。

# Swagger UI でプレビューできるよ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134740/a34dca94-7ce1-d142-241b-4ad8cb2ee0ee.png)
当然のことながら、エディタで Spec を書きながら、Swagger UI でリアルタイムにプレビューできます。

## プレビューを ReDoc に変更することもできるよ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134740/7124aa97-b6cd-ebf4-3166-9922ef27e84e.png)
拡張機能の設定で、プレビュー用レンダラーに Swagger UI か ReDoc を選択できる。

# OpenAPI、Swagger の入力補完が効くよ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134740/bb679a4a-4461-5e4c-d852-da798a453a41.png)
入力補完いいですよね。タイプミスも減るし。人類の叡智。

正直、Swaggerのプロパティなんて全然覚えていないのですが、入力補完のおかげで迷わずサクサク書けます。

## 入力ミスを警告してくれるよ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134740/d5458764-1989-0a50-9ca3-50ffbfbcf2de.png)
必須プロパティが足りていない場合や、定義に存在しないプロパティが記述されていた場合などに警告してくれます。

もちろん、SwaggerとOpenAPIのどちらも対応しています。

# コードジャンプが便利だよ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134740/9e23cd2e-0ba1-612f-a77d-dc5f7b1611f8.png)
左ツールバーに「/API」ボタンが追加され、クリックするとファイルツリーのビューがAPI内のエイリアス一覧に変わります。

Swagger Spec はどうしても長大になり、見通しが悪くなりがちなので、コードジャンプできるのはものすごく助かります。

もちろん、Pathだけでなく各種定義にもジャンプできます。

# セキュリティレポート機能があるらしい？
私は使ったことありませんが、そういう機能があるらしいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134740/bc44db4e-af73-fbbf-12b8-813e86c3af79.png)
この紫色のボタンがそうらしい。

# 残念なところ
### Codegen できない
Swagger Editor と Sagger UI の機能を備えてるなら、Swagger Codegen の機能もサポートしてほしかった。

### Swagger UI のプレビューを保存できない
ひょっとすると方法があるのかもしれませんが、見つけられていません。

### 結局、SwaggerHub の方が高機能
上記２項目が不満なら SwaggerHub 使えばいいじゃん、という話になりますよね。
けど、ローカルでVSCodeでやりたいんスよ。
プロジェクトデータと一緒にGit管理したいんですよ。
【Rails】ページネーションの実装

#ページネーションとは
一覧表示画面に表示するレコード件数が多くなると、目視での確認が困難になってしまいます。この問題を避けるための方法がページネーションです。
ページネーションとは、レコード件数が一定数を超えた場合に複数のページに分割して表示を行うことです。

##kaminariのインストール
Railsでページネーションを実現するgemとして、kaminariがあります。今回はこれを用いてページネーションを進めていきます。
まずは、gemファイルに以下を追加。

```ruby:Gemfile
gem 'kaminari'
```

bundleコマンドでkaminari gemをインストールします。

```
$ bundle
```

##ページ番号に対応する範囲のデータを検索するようにする
PostsControllerのindexアクションを変更します。
このアクションでは、ページ番号がparams[:page]として渡されることを前提とします。ページ番号を用いて、データ範囲を検索する機能は、kaminariのpageスコープで簡単に行えます。
indexアクションを以下のように変更します。

```ruby:app/controllers/posts_controller.rb
  def index
    @posts =Post.page(params[:page])
  end
```

##ビューにページネーションのための情報を表示する
ビューには、ページネーションための以下の情報を表示するようにします。

1. 現在どのページを表示しているかの情報
2. 他のページに移動するためのリンク
3. 全データが何件なのかという情報

1と2のためにはpaginate、3のためにはpage_entries_infoというkaminariヘルパーメソッドが利用できます。

それでは、ビューを以下のように変更します。

```ruby:
…
= link_to '新規投稿', new_post_path, class: 'btn btn-primary'

.mb-3
  =paginate @posts
  =page_entries_info @posts

table.table.table-hover
…
```

ページネーションの情報を表示する枠として、mb-3というCSSクラスのついたdiv要素を用意し、paginateヘルパー、page_entries_infoヘルパーを呼び出しています。

##翻訳ファイルの追加
kaminariが用意している翻訳ファイルはen(英語)のみなので、以下の内容でjaの翻訳ファイルを用意します。

```yml:config/kaminari.ja.yml
ja:
  views:
    pagination:
      first: "&laquo; 最初"
      last: "最後 &raquo;"
      previous: "&lsaquo; 前"
      next: "次 &rsaquo;"
      truncate: "&hellip;"
  helpers:
    page_entries_info:
      one_page:
        display_entries:
          zero: "%{entry_name}がありません"
          one: "1件の%{entry_name}が表示されています"
          other: "&{count}件の%{entry_name}が表示されています"
      more_pages:
        display_entries: "全%{total}件中 %{first}&nbsp;-&nbsp;%{last}件の%{entry_name}が表示されています"
```

##デザインの調整
機能は実装できましたが、見た目がいまいちなので修正します。paginateヘルパーが表示に使用するパーシャルテンプレートをアプリ内に用意し、それを自由にカスタマイズすることができます。パーシャルテンプレートはkaminariの提供するジェネレータで生成しますが、その際にテーマ(Thema)と呼ばれるデザインの種類を指定して、好みのパーシャルテンプレートを生成できます(https://github.com/amatsuda/kaminari_themes)。

今回はbootstrap4というテーマのパーシャルテンプレートを生成します。

```
$ bin/rails g kaminari:views bootstrap4
```

app/views/kaminari配下にいくつかビューテンプレートが追加されます。

そして、localhost:3000にアクセスすると…
![50D4FAEA-8D4D-4627-9560-B905C718ED96.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999125/bb8b4fdf-a3e1-b85f-76ba-c405ea4bab10.png)

無事に格好良くなっています!

#参考
[現場で使える Ruby on Rails 5速習実践ガイド](https://www.amazon.co.jp/gp/product/B07JHQ9B5T/ref=ppx_yo_dt_b_d_asin_title_o03?ie=UTF8&psc=1)
Couldn't serve files through port 8081, AWS EC2 Ubuntu 18.04 Instance

## Issue

Was setting up a simple website for fun/practice on Ubuntu 18.04, using Apache2 as the web server.  I then wanted to work on another website, so I thought I would work on it through a different port than the one for the first (443/HTTPS), and tried it with a random port 8081.  

For some strange reason, I couldn't get it to work.  I checked the access logs for my instance from AWS, and the requests via port 8081 were getting in, but the web server was not responding.  

## TL,DR; (Solution)

Turns out I had set up a separate firewall within the Ubuntu instance that I had completely forgotten about.  
Once I figured that out, fixing it was easy: `sudo ufw allow 8081`

If you try troubleshooting firewall issues with AWS instances, most of the guides/ knowledge online tells you to look at the settings in AWS, since those should be the only ones that matter.  
But if you're like me and followed Apache tutorials that told you to set up a firewall within the server, and then you just forgot you did that, chances are you might've forgotten that you need to edit those firewalls.  
So I wrote this as a friendly reminder that this might be something you have to check, since I didn't see it anywhere else :)
clearは要素に境界線を与える

floatを使用すると要素が浮き、下の要素が上に詰めてくる。これをクリアしてくれるのが、
.clear::after {
    content:"";
    clear: both;
    display: block;
}

↑は今はそのまま覚える

❶例

✔︎使用しない場合

container(1)
~
~
~
container(1)            container(2)
                        ~
                        ~
                        ~
                        container(2)

✔︎使用した場合

container(1)
~
~
~
container(1)
ここに境界線を引いてくれる
contaienr(2)
~
~
~
container(2)

❷使い方
<div class="container" clear>

みたいな感じです。
bash関数の内部で`exit`した際の挙動

## Environment

- bash

## Problems

- 関数内でexitを読んだ際、どのような挙動になるのかを知りたい。
    - 関数の実行のみが終了するのか、ファイルの実行が終了するのか
    - 終了コードはどのようになるのか

## How to solve

確認したところ、以下のような挙動だった。

- ファイルの実行が終了する
- プロセスの終了コードは、`exit`で指定した終了コードとなる

## Description

```
cat << EOF > a.sh
exit_func () {
    exit 0
}

exit_func
echo 'execute here!'
EOF

sh ./a.sh
echo $?
```

**output**

```
0
```

```
cat << EOF > b.sh
exit_func_254 () {
    exit 254
}

exit_func_254
echo 'execute here!'
EOF

sh ./b.sh
echo $?
```

**output**

```
254
```

`exit`はプロセスを終了させるものなので、よく考えれば当然の結果かもしれない。

## Reference

- https://linuxize.com/post/bash-functions/
Couldn't find User without an ID エラーを解決した

rails初学者です。
現在オリジナルアプリを開発しております。
ユーザー詳細機能を実装しようとして、ユーザー詳細画面へのリンクを設定し、動作確認してみたら
「Couldn't find User without an ID」
というエラーが発生したため、エラー解決をしました。

## 環境
ruby '2.6.5'
rails '6.0.0'

## ビュー

```ruby

<%= link_to "#{current_user.name}", user_path(current_user) %>
```

このように、ログイン中のユーザーの名前を表示し、名前にユーザー詳細ページへ飛ぶリンクを設定しました。

## Usersコントローラー

```ruby

def show
  @user = User.find(params[:id])
end
```
Usersコントローラーのshowアクションで、パラメータのidを受け取って
そのidに合致するユーザーを@userに格納しました。

## 挙動確認
予想される挙動は、**「ユーザー名をクリックするとユーザー詳細ページに遷移する」**
ですが、いざクリックしたところ、Usersコントローラーのshowアクションで下記のようなエラーメッセージが出ました。

```
ActiveRecord::RecordNotFound in UsersController#show

Couldn't find User without an ID
```

簡単に言うとIDがありませんよ、ということです。

## パラメーターの確認
showアクションにbinding.pryを仕込み、パラメーターを確認してみました。
すると下記のような結果でした。

```
 pry(#<UsersController>)> params
=> <ActionController::Parameters {"controller"=>"users", "action"=>"show", "format"=>"1"} permitted: false>
```

本来ならばid="1"と出て欲しいところが、format="1"となっており
パラメーターにidが含まれていないようです。

## 結論

ルーティングの記述にミスがありました。

```ruby

resource :users, only: :show
```
'resources'と書かなければならないところを、'resource'と書いてしまっておりました。

resourceメソッドはresourcesメソッドに対して、**indexアクションとid付パスを生成してくれない**みたいです。
そのため、パラメーターにidが含まれていませんでした。

## 解決策

ルーティングを

```ruby

resources :users, only: :show
```

と書き直しました。

再度挙動を確かめたところ、問題なくユーザー詳細ページに遷移しました。

## 参考

https://qiita.com/wacker8818/items/1ba526fcbc73e065a511
プログラミング超入門(１)〜GO言語〜

#Visual Studio Code（ビジュアル スタジオ コード）略してvscodeをインストールしてプログラムを実行してみる。
![vs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1134006/89bdcdaf-8d84-46f2-5c6f-ed2a419d51b0.png)
  まず、**Japanese Language Pack for Visual Studio Code**(日本語翻訳)と**Go言語**の拡張機能を
vscode内で**インストール**しましょう。
![vs2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1134006/3a33b115-7546-679f-e5b9-e555c7792832.png)
新規フォルダからファイルを作成し、**run.go**という名前でコードを書いてみましょう。名前の**run**は実行を意味し、( **.** )ピリオドの後に拡張子の**go**を付けることで、Go言語だと自動的に判断してくれます。

-----------------------------------

```run.go
package main

import "fmt"

func main() {
    var a int
    a = 3
    fmt.Println(2 * a)
}
```
[前回の記事](https://qiita.com/ume-bar/items/eaf9aa92211c181abd7c)で説明した続きになりますが、**var a int**はそれぞれ意味を持っていて、
**var**は**予約語**(あらかじめ定められた役目を持った単語)であり、**package**や**import**も
それに当たります。予約語は変数名として使用することは出来ません。そして**var**は
**変数名を宣言する**(変数であることを示す)為に使われ、**a**が変数名に当たります。
次に**int**は**データ型**(あるデータを保持しておく為に必要なメモリ領域の大きさ)を指します。
**変数**とは文字や数字などのデータを入れて置くことができる**箱**のようなもので、必要な
時にいつでもデータを取り出すことができます。変数にデータを入れることを**代入**と
いい、データを取り出すことを**参照**といいます。初めて変数にデータを入れることを
**変数の初期化**といい、変数を宣言する(変数を作る)作業に繋がります。変数**a**に**=**で**3**を
代入し、文字列や変数の中身を参照させる為に、**Println**(プリントライン関数を使います。
この変数の宣言と同時にデータを省略し代入することも可能です。

```run.go
package main

import "fmt"

func main() {
    var a = 3
    fmt.Println(2 * a)
}
```
まずは省略してみます。変数**a**の後にいきなり**3**を代入してあります。Goが自動的に
データ型を判断してくれているので上記と同じ結果が返ってきます。

```run.go
package main

import "fmt"

func main() {
    a := 3
    fmt.Println(2 * a)
}
```
更にシンプルに変数名**a** コロン**:** イコール**=** 代入したい値**3**で変数の宣言と同時に代入させ
る宣言方法がGoではよく使用されています。ファイルを保存し、**ターミナル**を開いて実行してみましょう。
###・実行結果

```
go build run.go

6
```
**go build**の後にファイル名**run.go**エンターして、**./ints**でエンターキーで、**ビルド・実行**
[ **6** ]が表示されました。

[←前回の記事](https://qiita.com/ume-bar/items/eaf9aa92211c181abd7c)　[次の記事へ→](https://qiita.com/ume-bar/items/95f7c5f61e44dddf9401)
Python for Windowsをインストールして、仮想環境を作ってみた


# インストーラのダウンロード
以下のサイトから、Pythonのインストーラをダウンロードします。
私は`python-3.9.1-amd64.exe`をダウンロードしました。

https://www.python.org/downloads/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057456/15d68d91-3c58-4a79-c3ee-607c09fab73d.png)

# Pythonのインストール
ダウンロードしたインストーラを実行します。
するとこのような画面が開きますので、**Add Python 3.x to PATH**にチェックを入れ、`Install Now`をクリックしましょう。

もし**Add Python 3.x to PATH**にチェックを入れ忘れてしまったら、慌てずもう一度インストールしましょう。何度繰り返しても大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057456/bf6b62e9-ec9d-f41d-70ca-69e9a49b24ad.png)

# インストール中
インストールは大体1～2分で終了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057456/589382b1-9db7-803e-5401-678e333503b2.png)


# インストール完了
以下の画面が表示されればインストールは完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057456/99b2171e-836d-dc4d-c4be-ae9ce460f62b.png)


# PowerShellの環境設定
PowerShellでスクリプトの実行を許可しておきます。
スタートメニューで`Windows PowerShell`を起動し、`Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force!
`と入力します。
このコマンドは一番最初に一度だけ実行してください。
二回目以降は不要です。
Rails「paramsの使用法」

#はじめに
今回、テキストの一覧ページを作成する際、link_toとhelperよりparamsの使用方法を復習できたので共有します。

#やりたいこと
・viewで各教材の一覧ページへのリンクを設定する
・controllerで各教材の一覧ページに適した教材を取得する
・helperで一覧ページのタイトルを表示する処理を書く

#viewで各教材の一覧ページへのリンクを設定する

```_header.html.erb 
<%= link_to "Ruby/Rails教材", texts_path, class: "dropdown-item" %>
<%= link_to "AWS講座", texts_path(genre: "AWS"), class: "dropdown-item" %>
<%= link_to "PHPテキスト教材", texts_path(genre: "Php"), class: "dropdown-item" %>
```
<%= link_to "表示名",次のアクションへ遷移するパス(パラメーター),class: "クラス名" %>
となるよう記述します。

各教材の一覧ページへのパスtext_pathにパラメーターとしてgenreを指定することで、表示する教材を制限します。

#controllerに条件分岐を記述

```texts_controller.rb
  def index
    if params[:genre] == nil
      @texts = Text.where(genre: ["Basic", "Git", "Ruby", "Ruby on Rails"])
    else
      @texts = Text.where(genre: params[:genre])
    end
  end
```

パラメーターgenreの指定がない場合とある場合で条件分岐し、条件にあった教材だけ取得するようにします。

#helperに変換部分を作り教材毎にページタイトルが変わるようにする

```texts_helper.rb
module TextsHelper
  def page_title
    if params[:genre] == nil
      "Ruby/Rails"
    else
      params[:genre]
    end
  end
end
```

helperにpage_titleというメソッドを定義し、パラメーターgenreの指定がない場合はRuby/Railsを表示し、指定がある場合はその教材のgenre名を表示するよう処理を書きます。

helperは、定義しておくことでview内でその処理を呼び出すことができ、viewをよりシンプルに書くことができます。

#一覧ページのview

```index.html.erb
<div class="text-title">
  <h3><%= page_title %>テキスト教材</h3>
</div>

<% @texts.each do |text| %>
  <div class="card-body">
   <p class="card-text"><%= text.title %></p>
   <p class="card-text"><%= text.genre %></p>
  </div>
<% end %>
```

viewで <%= page_title(helperで定義したメソッド) %> を記述し、ページ毎にタイトルを表示するようにします。

controllerで定義した@textsはeachの繰り返し処理でtitleとgenreを表示するようにします。

#まとめ
このようにcontrollerとhelperでパラメーターを元に条件分岐することで、一覧ページごとに適したタイトルとテキストを表示することができました。
【selenium, beautifulsoup, API 】スクレイピング基本3パターンの使い分け！

本記事では、スクレイピングでWEBページの情報を取得するための方法、基本3パターンについて説明しております。
スクレイピングをするにあたって"どの手法を用いるのが最適なのか"を考えたことはありますか？
本記事を読めば無駄のない最適なスクレイピング手法が身に付きます！

#スクレイピング3パターン
スクレイピングのパターンは殆ど以下の3つだと考えて良いかと思います。

**・ selenium**
**・ request & beautifulsoup**
**・ 各サイトのAPI**

#使い分ける際に考える点
これら3パターンを使い分けるに当たって考える点は以下です。
**・ 取得可能かどうか**
**・ 取得の速さ**
**・ ブロックのされにくさ**
ほんとこれだけなので、シンプルですね。
上の3つの取得手法について、まとめてみるとこのようになります。

|            | 取得可能かどうか | 取得の速さ | ブロックのされにくさ |
|:----------:|:-----------:|:------------:|:------------:|
| **selenium**      |◎         | △         | ◯         |
| **request & beautifulsoup**     | ◯      | ◎       | ◯         |
| **API**       | △        | ◎         | ◎         |

ここから分かることは、
**selenium →　何でも取得できて万能だけど遅い**
**request & beautifulsoup → かなり早く取得できるけど、取得できないサイトがある**
**API　→　サイトが提供していないとそもそも使えない。だけど、サイトが許容しているからブロックに対しての安全性は高い。速い。**
このような特徴があることを知っておいてください！


#3パターン使い分け
では、3パターンを使い分ける上での考え方です。次のように考えていきましょう。
#####1. APIが使えないか？
#####2. APIで無理そうなら、request&beautifulsoupが使えないか？
#####3. これらが無理なら、仕方ない、seleniumでやろう。
こんな流れで考えてください。

seleniumはよく使うのですが、最終手段です。
初投稿

2.26事件と岡本太郎の誕生月日の今日から、何となくキリの良さを感じて投稿を始めてみようと思いました。
プロフィールにも書いていますが、2020年秋後半から、 ITエンジニアとしての学習・勉強を始めています。
早寝早起きからやり直している最中です…
という事で今日はもう寝ます。
【Python】自作モジュールでも使える特殊なloggerを簡潔に書きたい時【logging】

# 特殊なloggerとは？

loggingと言えばlogging.iniとかloggingConfigDictとかいろいろあるけど、
例えば、googleのCloud LoggingとかにAI Platformのログを貯めたい時にこんな書き方をします。

```{python:loggingの書き方}
import logging
import google.cloud.logging_v2
from google.cloud.logging_v2.handlers import CloudLoggingHandler
from google.cloud.logging_v2.resource import Resource

client = google.cloud.logging_v2.Client(project=os.environ["PROJECT_ID"])
handler = CloudLoggingHandler(client, resource=Resource(
    "ml_job",
    {
        "task_name": "hoge",
        "project_id": os.environ["PROJECT_ID"],
        "job_id": os.environ["CLOUD_ML_JOB_ID"]
    }
)
)
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.INFO)
LOGGER.addHandler(handler)
```

ちょっとこれはlogging.iniに書けんなーと思って、  
だけどちゃんとモジュールを呼んだらLoggingして欲しい訳です。結構苦しみましたが、うまく動作した例を紹介します。

# 成功例

以下のようにファイルを整理

```{python:main.py}
from logger import get_logger, set_logger
from module import module
set_logger()
LOGGER = get_logger()


def another():
  LOGGER.info("another")

def main():
  LOGGER.info("start")
  another()
  module()
  LOGGER.info("end")

if __name__ == "__main__":
  main()
```

```{python:module.py}
from logger import get_logger
# 呼び出したいモジュール

def module():
  global LOGGER
  LOGGER = get_logger()
  LOGGER.info("test")
  module2()

def module2():
  LOGGER.info("test2")
```

```{python:logger.py}
import logging

def set_logger():
  global LOGGER
  LOGGER = logging.getLogger(__name__)
  LOGGER.setLevel(logging.INFO)
  ch = logging.StreamHandler()
  ch.setLevel(logging.DEBUG)
  formatter = logging.Formatter("%(levelname)s - %(message)s")
  ch.setFormatter(formatter)
  LOGGER.addHandler(ch)
#今回は簡単な例としてStreamHandlerを使用。
  
def get_logger():
  return LOGGER
```

まず説明すると、Entrypointとなるmain.pyには必ず`set_logger()`を付け加えます。
するとlogger側でLOGGERの設定ができる事になります。
そして、`get_logger()`からLOGGERを取り出し、使用することができます。
ここまでは、単純なloggingと変わりません。

問題は別モジュールを呼び出した時、Entrypointで設定したLOGGERはどうやっても読めませんし、
かと言ってもう一度宣言をすると、二重でログを吐くことが分かっています。
なので、モジュールにおいては、`get_logger()`だけを使用し、そのLOGGERをGrobal設定することで、
モジュールファイル内のLOGGER全てで設定したLOGGERを使用することができます。


# 別の方法

別の方法があれば教えてください...もっと...もっと簡潔に書きたい...

# 参考文献

(あまり参考にできなかったですが、以下の方法もあるみたいです）

https://qiita.com/Esfahan/items/275b0f124369ccf8cf18