OmniAICreator/Qiita-1.07M huggingface dataset:
whonixでInstagramを使う


ロシアがInstagramへのアクセス制限をしたことを知り、TorでInstagramが使えないか調べていました。
Torの仕組み上大幅にInstagramのウェブサイトを修正しないと対応できないと、ネットのディスカションを読み知りました。

https://www.reddit.com/r/TOR/comments/nwn1rv/how_to_use_instagram_in_tor/

この記事の中で、見た事があるセキュアなOSが目に留まりました。

whonixを使って、Instagramにアクセスする手順が紹介されていました。

早速試しました。
私は、下記のページでvirtualbox版をダウンロードして使いました。

https://www.whonix.org/wiki/VirtualBox/XFCE

![スクリーンショット 2022-03-16 16.03.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20977/5a3615df-c7ee-e352-210f-6c3ec34ba596.png)
この画像のオプションを選択して、進めました。

## 参考にした記事です。

https://blog.cheena.net/8

https://note.com/casval0115/n/n8c18fd680ae3

## パスワードの入力に備えて
ターミナルでコマンドを使って設定やインストールするときに、パスワードを求められます。
この時のパスワードは、

https://www.whonix.org/wiki/VirtualBox/XFCE

この記事の中の「First time users and more」の項目で、確かめてください。
またターミナルを起動したときに、起動の度にユーザー名とパスワードが表示されますので、控えておくと便利です。


## 日本語化するために、下記の記事を参考にしました。

http://fanblogs.jp/impressivecode/archive/108/0

https://atmarkit.itmedia.co.jp/ait/articles/1810/26/news035.html

https://atmarkit.itmedia.co.jp/ait/articles/1806/28/news043.html

https://hnakamur.github.io/blog/2020/06/11/setup-fcitx-mozc-on-ubuntu-20.04-desktop/


## 日本語化の中でハマったこと

```bash
sudo dpkg-reconfigure locales
```
で日本を選択するとき、jaから始まる行を見つけたら、スペースキーを押してマークを付けてから、エンターキーで確定させてください。

```bash
sudo dpkg-reconfigure tzdata
```
でタイムゾーンを設定する際に、

```bash
debconf: dialog output the above errors, giving up!
```
とエラーになりました。
ウィンドウサイズが小さいためにエラーになるようなので、ターミナルのウィンドウサイズを大きくして調整してください。

日本語入力がインストールされていないため、記事のように追加ができませんでした。
そのため下記のコマンドを実行して、インストールしました。

```bash
sudo apt update && sudo apt -y install fcitx-mozc
```

再起動して、日本語入力できるようになりました。
日本語で入力したいときは、コントロールとスペースキーを同時に押して切り替えました。

Chromeは、この記事を参考にインストールしました。

https://mebee.info/2020/03/28/post-7904/

![スクリーンショット 2022-03-16 16.32.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20977/3ae93320-5fc9-31c6-0141-83069656798c.png)

## インストールできました。
私は、有料VPNを購入できないので、ここまでしか挑戦できないです。
ここから先に実際にInstagramにTorを使って接続したい方は、自己責任で試してください。

### 今回の記事は、whonixを日本語化したい方のお役に立ちましたら幸いです。
Whonix-Workstation ™の日本語化が大変なのでMINTで仮想マシンを作って接続する方法を解説している記事もありました。

https://note.com/casval0115/n/n8c18fd680ae3

Whonix-Gateway ™ と Whonix-Workstation ™　を同時に起動して使うことが推奨されています。

ご自身で作った仮想マシンを接続するときは、上記の記事の設定を必ず行ってください。

## Torのみでは、匿名化が不完全なようです。
TorとVPNを組み合わせることで、匿名性が高くなるそうです。

TorとVPNについては、それぞれネットで検索して調べて頂けましたら幸いです。
ITパスポート受験

# ITパスポートを受けてみた
## ITパスポートの受験の経緯から、受験、その後まで

### なぜ受けようと思ったのか
 - 受験料の値上がり
 　5,700 円 → 2022.4~【改定後】7,500 円
 - 周囲に資格保持者がいたためきっかけになった
 - 基本情報技術者試験の前段階
上記資格取得を目標としているが、ハードルが高く感じたので試験の感覚を知りたかった

### 受験までの流れ
- 受験を決意する
[過去問道場](https://www.itpassportsiken.com/)の問題を数問お試し
知っている用語があったので受験に前向きになれた
- 申込
[こちらより](https://www3.jitec.ipa.go.jp/JitesCbt/index.html)
名前・住所等を登録後、会場を選び受験料を支払い。
支払い方法はコンビニ・カードなどあり。
当日必要な確認IDが振られるので、スクショ・ダウンロードなどで保存する。
- 当日までひたすら過去問道場を解く
[過去問道場](https://www.itpassportsiken.com/)
用語は繰り返して反復し、覚える
短縮英語に苦戦するが、何度も繰り返したり、関連付ける
計算問題は余裕がある時・気分転換したいときに

### 過去問内容
3分野
- ストラジ系
企業・法務・マネジメント・システム関連の用語や考え方
個人的には損益分岐点が面白かった
- マネジメント系
システム開発のマネジメント・プロセスの基礎的な用語・考え方
- テクノロジ系
IT業界で使用される基本的な用語・考え方
基礎理論やPCの構成・ソフトウェア・システム構成など

### 受付後
- ロッカーへ荷物を預ける(ほんとに手ぶら)
- 席にメモ用紙・シャーペン・イヤーマフ有
- 開始
- 試験終了の操作をすると画面に得点が表示される
- 各々終了後に挙手で退出

### 終了後
- ２時間ほど登録したサイトからで点数が確認できる
- 合格基準点
各分野300点以上かつ総合600点以上

#### 感想
IT用語も出てくるが、企業や経済用語なども見られた。
多少なりとも経営についての知見が得られた。

#### 無事取得できました。
簡単に取得できるなどの情報も出回っており、具体的になにか有利に活かせるような資格というよりは基本の基本という感じがありました。
マイナスにはならないのでいい経験になりました。
基本情報技術者取得目指して頑張ります。
【Docker】ポートフォワーディングとは


# ポートフォワーディングとは
インターネットから特定のポート番号宛てに届いた通信（パケット）を、予め設定しておいた別の機器に転送する機能のこと。
**Docker**の場合、デフォルトではコンテナ内は閉じられているためホストや外部からはアクセスできない状態になっている。そのため、ポートフォワーディングでホストのポートから**Docker**内で解放されているポートに向けて通信を転送する必要がある。

# ポートフォワーディングの設定
**Dockerイメージ**を単に``docker run``だけではホストから接続できないため、``-p``オプションを付けてポートフォワーディングを設定する。書き方は以下のようになる。

```
docker run -d -p <ホストポート>:<コンテナポート>　<イメージID>

// 例えばDockerコンテナ側が8080ポートの場合
docker run -d -p 9000:8080　<イメージID>
```
上記のように実行することで、``http://localhost:9000``でホスト側からアクセスできるようになる。
もしポートフォワーディングを設定せずに、``http://localhost:8080``にアクセスしようとしても失敗する。
Rのleafletを使ってSPSS Modelerのデータを地図にプロットする

SPSS Modelerで作ったデータを地図にプロットしたいことがあると思います。マップ視覚化のグラフ出力機能もあるのですが、ラスタデータのマップに表示することはできません。
ここではleaftletというRのライブラリとSPSS ModelerのR拡張ノードの機能を使って、OpenStreetMapにデータをプロットしてみます。

* テスト環境
Modeler 18.3
Windows 10 64bit
R 4.0.4
leaflet 2.1.0
FireFox 91.7.1esr

* サンプルストリーム

https://github.com/hkwd/spsssample/raw/master/220316leaflet/220316leaflet.str

# 1. 事前準備

## 1.1. SPSS ModelerのR拡張ノードを利用可能にする。

R拡張ノードのセットアップができていない場合には以下の手順でセットアップします。

SPSS Modelerの拡張ノードでRを利用する

https://qiita.com/kawada2017/items/0bb68e0b577e02bb8c6a

## 1.2. Rにleafletを導入する

Rのコンソールを開き以下のコマンドでleafletを導入します。CRANのミラーサイトはJapanなど適当なものを選択します。

```r
install.packages('leaflet',dependencies = TRUE)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/deef8dae-0297-51ba-ef21-46f2313bb79c.png)

# 2. Modelerのデータをプロットする

今回用意したデータは以下です。
店舗の緯度経度と売上が記録されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/d45ae030-58b7-73cd-9d37-ab306dca1059.png)

このデータに「拡張の出力」ノードを接続し、シンタックスとしてRを選び、以下のコードを入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/cdf2907a-20f5-fb4e-f6a2-a510c0ec75af.png)

addCircleMarkersで丸形のマーカーをデータの緯度経度から表示し、売上の大きさで半径を決めています。また、labelに店舗名を入れています。

```r:leaflet.r
library(leaflet)
m <- leaflet()
m <- addTiles(m)
m <- addCircleMarkers(m, 
	lng=modelerData$経度, 
	lat=modelerData$緯度,
	radius=modelerData$売上,
	label =modelerData$店舗)
print(m)
```
実行するとデフォルトのWebブラウザが開き、そこに地図が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/0d14c7a6-e448-7912-6b56-013c529f2fa7.png)


なお、私の環境のChrome（バージョン: 99.0.4844.51）では、以下のようにうまく表示できませんでした。URLをコピーしてFirefoxに貼り付けると表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/5dd0dd85-0c20-381e-7e1f-e64f8ab7be62.png)


# 参考
leafletではじめるRによる地図プロット

https://kazutan.github.io/JapanR2015/leaflet_d.html

Leaflet for R - Introduction

https://rstudio.github.io/leaflet/

OpenStreetMap(OSM)

https://openstreetmap.jp/#zoom=5&lat=38.06539&lon=139.04297&layers=000B

SPSS Modeler ノードリファレンス 4-7 マップ視覚化 - Qiita 

https://qiita.com/416nishimaki/items/5b0a555f32c136718a5a
スクレイピングとか

```html
<meta name="description" content="左側ほしい右側"/>
```
「ほしい」だけ抽出したい。
```python
import re
import requests
from bs4 import BeautifulSoup

html = requests.get(url)
soup = BeautifulSoup(html.text, "html.parser")
content = soup.find("meta", attrs={"name": "description"}).get("content")
result = re.search("左側(.+)右側", content).group(1)
```
Typing Tubeというサイトの紹介

# はじめに
Qiita初投稿です。
今回はタッチタイピングの練習をしていく中で見つけたサイトの紹介となります。
タイピングの練習サイトといえば[寿司打](http://typingx0.net/sushida/)や[e-typing](https://www.e-typing.ne.jp/)が鉄板ですが、こちらのサイトはまた違った感覚で練習をすることができます。

# [Typing Tube](https://typing-tube.net/)とは
Youtubeの歌動画に合わせて歌詞が表示され、表示された歌詞をタイピングしていくことで得点を獲得していく、まるで音楽ゲームのような感覚でタイピングの練習ができるサービスです。ユーザの有志が作成した譜面（？）に合わせてキーを打ち込んでいき、正確率や打ち切ることができた文字の割合などによってタイピングが点数化されます。
![typingtube.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002403/e5cd8bff-39bd-1ce6-7a64-813b9cbbc5f7.png)
[Typing Tube 森山直太朗 - さくら(独唱)](https://typing-tube.net/movie/show/9620)

## 良いと思った点
JPOP、アニソンなどを主とした多くの動画が譜面化されており、自身の好きな曲を探して好きな曲を聴きながらタイピング練習ができるため、モチベーションの維持に繋がります。譜面は難度によってレベル分けされており、自分のレベルに合わせた難度での練習が可能です。ランキング機能も搭載されていることから、ただ単に自身のスコアを伸ばすだけでなく、ランキングを伸ばすことを目標とすることもできます。（Twitterによるユーザログインが必要です）
間違えた際には正しいキーを打つまで進めないのは上記に挙げた2つのサービスと同様で、タイピングの正確性を鍛えることができます。また、大きな利点として、歌詞をタイピングできるのは表示されている歌詞が歌い終わるまで、という時間的制約があることが挙げられます。これによって急かされながらタイピングをすることで、スピードの向上も見込めます。
打ち終わるまで動画が停止する機能や、再生速度を変えられる機能もあるため、タッチタイピングビギナーも楽しんで練習ができると思います。

## 注意する点、改善が欲しい点
多くの動画がありますが、日本語が主で洋楽動画はあまりない印象です。したがって英語タイピングの練習には向かず、日本語入力を練習したい方向けのサービスになります。また、動画の人気ランキングやソートといった機能がなく、やりたい曲を自身で検索して探すか、すべてのページをさらって知っている曲を探す、といった若干面倒な部分もあるのには注意です。

# さいごに
タイピングに限らずですが、何かを練習するのにはモチベーションの維持が大変です。楽しんで練習できるこのサービスは本当におすすめなので、ぜひ利用してみてください。

[管理者様のTwitter](https://twitter.com/garplab)
[FANBOX](https://t.co/MTtrJJ7T6n)
↑個人での開発・運用をなさっているため、支援の検討もぜひ。
【Laravel】Web開発初心者が1週間で入門チュートリアルを実施した記録(1)~(3)



実施したのは、以下。

https://qiita.com/MasahiroHarada/items/eddad4cbf5e567393988

2018年の記事だが、少しの読み替えで問題なく稼働するTodoアプリを作成することができた。
Laravelの概観を掴むことができたので、筆者のMasahiro Haradaさんには感謝しかない。

自身の備忘とこれからLaravelを学んでいきたいというかたの参考になればと思い、ここに記す。

入門Laravelチュートリアル (1) イントロダクション
環境構築について。参考にしつつ、今回は以下の環境で実施した。

■実施環境
OS : macOS Montery (M1)
Laravel : Version 8.83.4
DB : PostgreSQL 14.2
エディタ : VSCode
※仮想環境（HomesteadやValet）は使用せず、ローカルで開発


実施期間 : 2022/03/09 ~ 2022/03/16


入門Laravelチュートリアル (2) ToDoアプリケーションの設計
設計について。熟読。

以下について、後ほど使うのでメモ。
* 機能一覧
* 画面設計
* URL設計
* テーブル定義

WAFのパターン図も保存。



入門Laravelチュートリアル (3) ToDoアプリのフォルダ一覧表示機能を作る
いよいよ実際に実装を進めていく。まずはフォルダ一覧表示機能。

①ルーティング設定(web.php)

    Route::get('/folders/{id}/tasks', 'TaskController@index')->name('tasks.index');

→getで/folders/{id}/tasksにリクエストがきたら、TaskControllerのindexメソッドを呼び出す。
　　これを'tasks.index'と名づける。

②コントローラーの作成・記載

        php artisan make:controller (コントローラーの名前)

→/app/Http/Controllers/(コントローラーの名前).phpにコントローラーが生成される。

（※DB接続設定）←最初だけ
③マイグレーションファイルの作成・記載

        php artisan make:migration create_(テーブル名)_table --create=(テーブル名)

→database/migrations ディレクトリに YYYY_MM_DD_hhmmss_create_folders_table.phpが生成される。生成されたファイルに、作成するテーブルのテーブル定義を記載する。

④マイグレーションの実行

        php artisan migrate

→テーブルが作成される。

⑤モデルクラスの作成

        php artisan make:model (モデル名)

→モデルクラスとテーブルは基本的に１対１になるようにする。

⑥テストデータの挿入
シーダー（Seeder）を用いてテーブルにデータを挿入。

⑦コントローラーの追記・修正

        $folders = Folder::all();

        return view('tasks/index', [
            'folders' => $folders,
        ]);
↑はテーブルから情報を全て取得して、view関数でテンプレート（/resources/views/tasks/index.blade.php）に'folders'として渡した結果を返却している。
テンプレート側で、渡された引数を$foldersとして使用できる。

■View関数：


    public function index ()
    {
  	  $var = 'XXX';
  
        return view('aaa', ['varvar' => $var]);
    }

上記のコードのように書けば「resources/views/aaa.blade.php」ビューへ、'varvar'という変数名で$varを渡すことができます。第二引数は"['渡す先での変数名' => 今回渡す変数]"。


⑧テンプレートの作成
HTML形式で記載していく。
ポイントは以下の箇所。

            @foreach($folders as $folder)
              <a href="{{ route('tasks.index', ['id' => $folder->id]) }}" class="list-group-item">
                {{ $folder->title }}
              </a>
            @endforeach

引数で渡された$foldersの分だけforループを回している。
route関数を用いて、href属性にURLを渡している。
route関数の第一引数はルート名、第二引数は、ルート URL のうち変数になっている部分（ここでは {id}）に実際の値を埋める）。

'tasks.index'は以下のルートで、{id}にはループで回しているfolderのidが入る。

    Route::get('/folders/{id}/tasks', 'TaskController@index')->name('tasks.index');


ケースバイケースではあるが、ざっくり上記①〜⑧が開発の流れとなる。

このあと、アクセスされているフォルダ名だけ選択表示（水色背景）するように少しブラッシュアップして、第３回は終了。
AWS LambdaでBoxSDK(JWT認証)を使おうとしてハマった件（備忘録）

# はじめに
本記事はタイトルの通りです。

とてもハマったため、備忘録として残しておこうと思ったのと同じようにハマって
しまった方の参考になればと思います。

結果的にAWS Lambda上でBoxSDKを使ったAPIは動作しました。
先にどうやって動いたかを紹介したあと、ハマった経緯や原因などの解説にはいります。

# Lambda環境(BoxSDK動作確認済み)

こちらの記事を参考にBoxSDKをインストール、ZIP化、S3への格納、Lambdaへのレイヤー追加を行います。cryptographyのレイヤー追加、記事ですがBoxSDKもかなり関わってました。

レイヤー追加時ですが、互換性のあるランタイムにpython3.7/3.8/3.9を指定
互換性のあるアーキテクチャはx86_64を指定しました。

https://qiita.com/Bacchus/items/7dcfc0237df196d1ab67

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184018/e7e5ece0-5ce1-ec85-c950-5446c7e24594.png)


続いてLambda関数を作成します。ランタイムはPython3.7、アーキテクチャはx86_64で作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184018/ebca990b-880d-d99f-fd53-13a194b65e36.png)

BoxAPIはJWT認証で動かす予定でしたのでboxsdkのモジュールのコードは下記の通り

```
from boxsdk import Client
from boxsdk.auth.jwt_auth import JWTAuth

公式の通りだとNGでした。
from boxsdk import JWTAuth
```

APIでBoxと通信が出来ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184018/4e4dfd82-de24-b4ea-94b4-de3b6e02b176.png)

# ハマった点について

BoxSDKでは2つの問題により上手く動作しませんでした。
1. BoxSDK自体のバグ？問題
1. pipの依存関係

それぞれ、振り返っていきたいと思います。
まず、前提としてローカルのマシン環境だと問題は起きませんでした。

Lambdaで動かそうとすると動かない（正確にはAttributeやImport Module Error)
今までこのようなケースがなかったため原因がある程度わかるまで時間がかかりました。

#### 最初のErrorの始まり
Windowsのローカル環境で動作確認済みのコードをLambdaに移し、**Windows**の環境でpipインストールしたboxsdkをsite-packagesから抜き取りLambdaにレイヤー追加、コードをテストしたところ、AttributeErrorが発生

> JWTAuthにはfrom_settings_fileのfrom_setting_fileなんてAttributeは持ってないよと

え？なんで？？

ローカル環境では動いてまっせ・・・

ネットで手当たり次第検索してみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184018/397114a7-2464-d47b-8fc0-7ae80fdc59de.png)

pip install時はboxsdk[jwt]だけにするんだぜ！みたいな記事を見て
再度pipインストールをしてアップロード、結果変わらず・・・

色々調べてると

そもそも、boxsdkパッケージの配下にJWTAuthってないじゃん

え？なんで？？ローカルでは動いてんの・・・

パッケージ内のモジュールを手当たり次第探索すると
boxsdk/auth/jwt_auth.py内にJWTAuthのClassを発見

え？公式のモジュールの呼び出し方おかしくない？？

調べてみるとboxsdkの__init__.pyに原因があるっぽい

```
from .auth import JWTAuth, OAuth2, CCGAuth
```

相対パスでauthからJWTAuthをインポートしようとしててエラーになってたみたい
この件は、ネット検索してたら誰かがフォーラムに上げてたので気づいてたらもっと早く分かってた・・・

インポートのコードの記述を変更して解決

さて本当の問題はここから

#### 依存関係

先に書くと、依存関係についてまったく無知だったのが問題でした
細かく書くと長くなるので簡潔に

まず、Windows環境でpipインストールしたパッケージはLambdaでは動かないことがある
Lambdaの実行環境がLinuxだから

- OS毎に依存関係が変わる

AWSクラウドシェルでpipインストールしたパッケージがImport Module Errorとなるのは、Lambdaのアーキテクチャをarm64では動かないと思われる（この辺りは本当にそうなのかインプットできていないので間違ってたらすみません）

- AWSクラウドシェル(AWS Linux)がx86_64アーキテクチャだから（たぶん）

AWSクラウドシェルでインストール時、おそらくPython3.7の環境でインストールしたので

- LambdaのランタイムもPython3.7に合わせないといけない（たぶん）

下記の記事の通り、Lambdaにレイヤーを追加する際はDockerを使った方がよさそうです
ちゃんと読み込んで間違っていれば後から記事を訂正します。

# 参考

https://aws.amazon.com/jp/premiumsupport/knowledge-center/lambda-layer-simulated-docker/
VagrantによるLAMP環境構築 2【PHP 5.4】

# はじめに
[VagrantによるLAMP環境構築 1【PHP 5.4】](https://qiita.com/musou/items/19ec81392461f2ac1165) の続きです。
前回構築したVM(CentOS7)にApache/MariaDB/PHP/phpMyAdminなどをインストールしていきます。

# スタートアップスクリプトを実行する
rootでログインする
rootのホームディレクトリにスタートアップスクリプトを作成する
パーミッションを実行可能に変更して実行する
```sh:127.0.0.1-vagrant@localhost：~ VT
> su -
> vagrant
> touch startup_yum.sh
> vi startup_yum.sh
> chmod +x startup_yum.sh
> ./startup_yum.sh
```
startup_yum.shの内容は以下のように編集する
```bash:startup_yum.sh
#!/bin/bash -ex

yum clean all #yumをクリーンな状態にする
yum -y update #yumを最新の状態にする
yum -y install httpd #Apacheインストール
yum -y install mariadb-server mariadb #MariaDBインストール
yum -y install php php-mbstring php-gd php-mysql #PHPインストール

systemctl enable httpd.service #Apacheを自動的に起動
systemctl enable mariadb.service #MariaDBを自動的に起動
```

# VMを再起動する
VMを再起動してhttpdとmariadbのサービスを起動する
```bat:cmd
C:\test_VM> vagrant reload
```

# データベースの初期設定をする
rootでログインする
データベースの初期設定をする
```sh:127.0.0.1-vagrant@localhost：~ VT
> su -
> vagrant
> mysql_secure_installation
> [Enter]
> y
> vagrant #DB用の管理者パスワードを設定
> vagrant #再入力
> y
> y
> y
> y
```

# phpMyAdminをインストールする
Apache/MariaDB/PHPを構築したのでphpMyAdminをインストールする
```sh:127.0.0.1-vagrant@localhost：~ VT
> yum -y install epel-release #EPELリポジトリからもyum出来るようにする
> yum --enablerepo=epel install -y phpMyAdmin #phpMyAdminインストール
```

# phpMyAdminの初期設定をする
/etc/httpd/conf.d/phpMyAdmin.confを開いて19行目に行を追加する
ポートフォワードによる通信を行う場合、ゲストから見たホストのipアドレス(10.0.2.2)からの通信を許可する
※forwarded_port(NAT Adapter上に設定される)
VirtualBox network engine : 10.0.2.2/24
VM Adapter eth0 :            10.0.2.15/24

```sh:127.0.0.1-vagrant@localhost：~ VT
> vi /etc/httpd/conf.d/phpMyAdmin.conf
```

```bash:/etc/httpd/conf.d/phpMyAdmin.conf
     # Apache 2.4
     <RequireAny>
       Require ip 127.0.0.1
       Require ip ::1
       Require ip 10.0.2.2 #この行を追加する
```
httpdのサービスを再起動する
```sh:127.0.0.1-vagrant@localhost：~ VT
> systemctl restart httpd
```

# phpMyAdminにログインする
ホストのブラウザを開いて"URL: localhost:8080/phpmyadmin"にアクセスする
DB管理者パスワードでログインする
![phpadmin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664939/0c6d90f2-ebe3-efe3-6996-bb143e3368f1.png)

---
【Rails】ラジオボタンのラベルにクリック判定をつける

## はじめに
:::note warn
Rails学習のアウトプット記事です。実装の際は参考サイトも併せてご確認ください。
:::

　Ruby on Railsの学習中にて、フォームヘルパー機能を使ってラジオボタンとラベル（キャプション）を実装する際、ラベルとボタンが紐づいておらず、ラベルをクリックしても反応しなかった。
　HTMLだとlabelタグでボタン自体を囲ってしまう方法があるそうだが、フォームヘルパーでラベルを生成する場合はfor属性を使ってボタンを指定する必要がある為、その記述方法を書いていく。
## 開発環境
- Rails 5.2.6
- Ruby 2.6.3
###
## 実装
### 前提条件
- **form_with**を使用
- 記事内で使用されているモデル・値は以下の通り

項目|値
-|-
モデル名|Test
カラム名|status
カラム型|Boolean
### 生成されるHTML（ラジオボタン部分のみ）
```html
<input type="radio" value="true" name="test[status]" id="test_status_true" />
<label for="test_status_true">Status true</label>
<input type="radio" value="false" name="test[status]" id="test_status_false" />
<label for="test_status_false">Status false</label>
```

### ブラウザ上の表示
<img width="400" alt="ラジオボタン" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694650/e8bf2c64-83dc-aa08-5e8d-24d2307dd9d2.gif">

### 実際に書くコード（ラジオボタン部分のみ）
```erb:○○.html.erb
<%# f.radio_button :カラム名, 値 %>
<%# f.label :カラム名_値 %>

<%= f.radio_button :status, true %>
<%= f.label :status_true %>

<%= f.radio_button :status, false %>
<%= f.label :status_false %>
```
ラベルを日本語化したい場合はi18nのlocaleファイルに`:カラム名_値`部分を追加するか、
`<%= f.label :status_false, "表示させたい文字列" %>`
で変更可能。

:::note warn
保守性を考慮する場合はi18nで日本語化を行います。Railsのi18n概要は[こちら](https://railsguides.jp/i18n.html)
:::

## 参考サイト(敬称略)
- [全日本ラジオボタンのラベルにクリック判定を付けろ協会 - 果樹園](https://mstssk.hatenablog.com/entry/2020/05/07/211108)
- [Action View フォームヘルパー - Ruby on Rails ガイド](https://railsguides.jp/form_helpers.html#%E3%83%A9%E3%82%B8%E3%82%AA%E3%83%9C%E3%82%BF%E3%83%B3)
- [お前らのf.radio_buttonとf.labelは間違っている - 動かざることバグの如し](https://thr3a.hatenablog.com/entry/20191016/1571155260)
Go1.18がリリースされたので、早速Goのバージョンアップ

2022年3月16日、Go1.18がリリースされました。
https://go.dev/blog/go1.18
待望のジェネリックス機能が使えるようになったので、早速Goのバージョンアップです。

## ダウンロード
Go1.18が公開されたばかりなので、公式サイトからダウンロード・インストールします。
https://go.dev/dl/

デフォルト設定では、`/usr/local/go`配下にインストールされるので、パスを通しておきましょう。
```
~ $ which go
/usr/local/go/bin/go
~ $ go version
go version go1.18 darwin/amd64
```

## アプリケーションでのGoのバージョンアップ
Goの標準モジュール管理`go.mod`で管理されているアプリです。
次のコマンドで`go.mod`に記載されているGoのバージョンが上がったことを確認しています。
```
go mod tidy -go=1.18
```

これでアプリケーションが正常に動作することも確認しています。
Node-REDのテンプレートノードでスケープしたくないメモ


## 通常に書くとエスケープされてしまいます。

- テンプレートノード側

```
https://www.switch-science.com{{path}}
```

> ![スクリーンショット 2022-03-16 11.17.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/8ed3fbb2-71bd-d550-634c-664b7894687b.png "スクリーンショット 2022-03-16 11.17.16.png")

- 出力

```
https://www.switch-science.com&#x2F;catalog&#x2F;7889&#x2F;
```

> ![スクリーンショット 2022-03-16 10.59.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/aef04524-b85b-a396-08ac-8fd2ed0a0bc9.png "スクリーンショット 2022-03-16 10.59.56.png")


`https://www.switch-science.com/catalog/7889/`というURLを出したかったのですがこのままだとうまくいきません。

## &を入れてみる

仕様書っぽいものを発見

> https://mustache.github.io/mustache.5.html

こちらを参考に`{{& payload}}`みたいに書くことでエスケープされずに出力されます。

```
https://www.switch-science.com{{& path}}
```

> ![スクリーンショット 2022-03-16 11.10.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/23b813cb-d01b-9197-f10d-3cd780b840fc.png "スクリーンショット 2022-03-16 11.10.18.png")

これでうまくいきました。
aptでパッケージの情報を表示する

## 環境
Ubuntu20.4

## 記事

**apt**でパッケージの情報の一覧を表示するコマンドは、**apt list**と、**apt-cache search**の２種類が存在します。それぞれの違いについて書いてみました。

**apt list**を実行すると、公式のリモートリポジトリ上にある、全てのパッケージが表示されます。
```
apt list
```

リポジトリにはたくさんのパッケージが存在しているため、Ctrl+cでブレイクさせないと、いつまでも表示し続けます。

果たして、パッケージはいくつ存在しているのだろうか。パッケージの数を調べたい場合は、次のコマンドで調べることができます。（因みに、2022/3/15時点で、76,876個のパッケージが存在していました）
```
apt list | wc -l
```

**apt list**では、ローカル環境にインストール済のパッケージも一緒に表示されます。インストール済のパッケージには、行の右側に **[installed]** と表示されます。インストール済のパッケージだけに絞って表示する場合は、次のようにオプションをつけます。
```
apt list --installed
```

次に、**apt-cache search**を実行してみる。このコマンドだけ実行してもエラーになります。**apt list**のように、リポジトリ上にある全てのパッケージを表示することはできません。

```
apt-cache search
```

**apt-cache search**は、次のようにパッケージ名を指定して検索する時に利用します。**apt-cache search**を利用して、インストール済のパッケージだけに絞り込んで表示することもできません。

```
apt-cache search nodejs
```

**apt list**と**apt-cache search**とでは、同じパッケージを検索しても、表示される情報が異なります。次の検索結果を見比べてみよう。

```
$apt list | grep ^nodejs
nodejs/focal,now 10.19.0~dfsg-3ubuntu1 amd64 [installed]
nodejs-doc/focal,focal,now 10.19.0~dfsg-3ubuntu1 all [installed,automatic]
nodejs-mozilla/focal-updates,focal-security 12.18.1-0ubuntu0.20.04.1 amd64
```

```
$ apt-cache search nodejs | grep ^nodejs
nodejs - evented I/O for V8 javascript - runtime executable
nodejs-doc - API documentation for Node.js, the javascript platform
nodejs-mozilla - evented I/O for V8 javascript
```

**apt list**で表示される情報は、パッケージのバージョン、アーキテクチャ（CPUの種類）であるのに対し、**apt-cahe search**で表示される情報は、パッケージの説明文だけとなります。



１つのパッケージに対し、詳細な情報を表示したい場合は、**apt-cache show**を使います。**apt list**で表示される情報、**apt-cache search**で表示される情報の両方が表示されます。
```
apt-cache show nodejs
```
YarnでGitHubプライベートリポジトリをyarn addする方法

この投稿では、YarnでGitHubプライベートリポジトリへの依存を追加する方法を説明します。


## 使用するYarn

本稿で説明する手順はYarn v1.22.17を前提とします。Yarn v2、v3ではやり方が異なるかもしれません。未検証です。

## YarnでGitHubプライベートリポジトリをyarn addする方法

### プライベートリポジトリのURLを取得する

依存に追加したいGitHubプライベートリポジトリを開き、「Code」→「SSH」タブからGitのURLをコピーします。

![20220316_142552.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/8e0d88a4-9917-3def-5cef-b9a10f922778.png)

次の形式のURLが得られるはずなので控えておきます。

```
git@github.com:ORG/REPO.git
```

### どのGitブランチやコミットに依存したいか決める

YarnではGitリポジトリへの依存を追加する際、ブランチやコミットハッシュを指定できます。

その場合、上で得られたURLに`#`でブランチ名を指定します。

```txt:$URL
git@github.com:ORG/REPO.git#BRANCH_NAME_OR_HASH
```

たとえば、mainブランチへの依存であれば次のようになります。

```text
git@github.com:ORG/REPO.git#main
```

### パッケージ名を決める

`yarn add`でGitHubリポジトリへの依存を追加した場合、パッケージ名はリポジトリ名になります。たとえば、GitHubリポジトリが`my-company/my-project`の場合、package.jsonには`"my-project"`として追加されます。

```package.json
{
  "dependecies": {
    "my-project": "git+ssh://github.com/...",
```

たとえば、極端な例ですが、自社のリポジトリ名が`my-company/typescript`だったりすると、Microsoftのtypescriptとバッティングするので、そういった場合はパッケージ名をかぶらないものにする必要があります。

パッケージ名はなんでも構いませんが、おすすめは会社名などをスコープにしたものです:

```txt:$PKG
@SCOPE/MODULE
```

たとえば、会社名がcraftsman-softwareでリポジトリ名がcommonなら次のような形式にします。

```
@craftsman-software/common
```

### Yarnが解決可能な形式を組み立てる

上で作った文字列`$URL`と`$PKG`を使って、`yarn add`が解釈できる文字列を組み立てます。

```shell
"$PKG@git+ssh://$URL"
```

たとえば、`$PKG`が`@craftsman-software/common`で、`$URL`が`git@github.com:craftsman-software/common.git#main`の場合、次の文字列になります。

```markdown
"@craftsman-software/common@git+ssh://git@github.com:craftsman-software/common.git#main"
```

### `yarn add`する

あとは、上で得られた文字列を引数に`yarn add`するだけです:

```shell
yarn add "$PKG@git+ssh://$URL"
```

これを実行すると、通常のNPMモジュールと同じように`node_modules`にコードがインストールされます。

## おまけ

### パッケージをアップグレードする方法

`main`ブランチを指定するなどして`yarn add`した場合に、ブランチをアップデートしたい場合は、`yarn upgrade`を実行するだけです。

```sh
yarn upgrade $PKG
```

たとえば、`@craftsman-software/common`という名前で`yarn add`したのであれば、

```sh
yarn upgrade @craftsman-software/common
```

とすると、最新のコミットを取得してインストールしなおしてくれます。
【iOS】起動するStoryboardを変更して画面が真っ黒になった時の対処法

# 起動するStoryboardを変更する方法

下記、記事を参考。

https://qiita.com/Shotaro_Mori_/items/c9348f3f59308171402a

こちらの記事で画面が真っ黒になったときはエントリーポイントを変更したら良いとのこと。

## エントリーポイントの変更をしてもまだ真っ黒なときの対処法

Info.plistの[Application Session Role]も確認すべし!!

→ https://stackoverflow.com/questions/59123012/xcode-11-2-1-swift-5-cant-change-main-storyboard-main-to-another-storyboa


* 環境
  * Xcode 13.2.1
大学院生がQitta初投稿してみた

# １．概要
4月からある大学の大学院に通い始める学生です．機械学習（ディープラーニング）による画像処理を専門とする研究室に所属しています．
基本的には自分の知識理解のためにアウトプット中心の投稿をしていきますが，最終的にはこれから専門的分野を始める方がみても分かりやすいような投稿ができればと思います．

# ２．投稿内容
大まかな投稿内容は次のようになっています．

1.pythonの基礎知識 
2.Docker,gitの使用 
3.上記のエラーコードの質問・解決策など
4.その他気になった論文・手法などなど．

# ３．余談
マイペースな投稿になるかもしれませんが，ぜひともコメント投資ていただけると嬉しいです．よろしくお願いします．
Git + GithubをMacでの使い方

GitHubでhttpsのパスワード認証が廃止された様でMacのターミナルにてコマンドにての操作を順を追って記載してみました。
GitHubに当方のアカウントshinsaku-jazzbass上にtest及びprivate_gitと言う、2つのリポジトリ作成して、それぞれに対応するMacローカルに、test及びprivate_gitと言う秘密キーを生成。

cd ~/.ssh
ssh-keygen -f ~/.ssh/test
ssh-keygen -f ~/.ssh/private_git
コマンドls -alにて作成確認
```
-rw-------   1 aaa  staff  1876  3 16 13:32 test
-rw-r--r--   1 aaa  staff   401  3 16 13:32 test.pub
pbcopy < ~/.ssh/test.pub
-rw-------   1 aaa  staff  1876  3 16 13:32 private_git
-rw-r--r--   1 aaa  staff   401  3 16 13:32 private_git.pub
pbcopy < ~/.ssh/private_git.pub
```
GitHub上に生成したキー中味をコピーしてそれぞれのリポジトリのdeploy keyとして登録保存する。
![スクリーンショット 2022-03-16 15.25.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/b443131b-210d-ad37-b3c9-eb04fea5b039.png)
SettingsのDeploy Keys選択、Add deploy keyボタンにて追加。
![スクリーンショット 2022-03-16 15.25.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/e837f535-3fb8-9ddc-3285-f293350db00d.png)
![スクリーンショット 2022-03-16 15.30.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/cd4b6c13-4ede-a407-3a53-7709000f3d94.png)

vim ~/.ssh/config参照下さい。以下のように編集保存。
```
Host github-test
  User git
  Port 22
  HostName github.com
  IdentityFile ~/.ssh/test
  TCPKeepAlive yes
  IdentitiesOnly yes

Host github-private_git
  User git
  Port 22
  HostName github.com
  IdentityFile ~/.ssh/private_git
  TCPKeepAlive yes
  IdentitiesOnly yes

```
上記の設定をGitHubに対して下記コマンドにて確認してする。
ssh -T git@github-test
及び
ssh -T git@github-private_git
更にそれぞれのリポジトリをローカルにcloneとしてディレクトリを生成し、そのディレクトリ内にてコマンドによる操作を行う。下記例参照。
アカウント：shinsaku-jazzbassに
~/.ssh/configでのHost名github-test、github-private_git秘密キー.gitを指定してcloneを作成。
```
git clone git@github-test:shinsaku-jazzbass/test.git
git clone git@github-private_git:shinsaku-jazzbass/private_git.git
```
これにて各ディレクトリ移動にてgitコマンド操作可能となります。
p45 Best Cow Line(C#)

### 自分(正解)

```
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.ExceptionServices;

public class Program
{
    public static void Main()
    {
        int N = 6;
        string S = "ACDBCB";
        string T = "";
        char[] list_S = { };

        //（１）Sをstringから配列に変える
        list_S = S.ToCharArray();

        //（２）Sが空になるまでループ
        while (list_S.Any()) 
        {
            //（３）最初と最後を取り出す
            char first = list_S[0];
            char second = list_S.Last();
            Console.WriteLine("firstは{0},secondは{1}", first, second);

            //（４）比較して、小さい方を別の変数に取り出す
            if (first < second)
            { //firstの方が小さい
              //（５）先頭削除、Tにはpushする
                Console.WriteLine("first");
                T += first.ToString();
                list_S = removeChar(0, list_S); 
            }
            else if (first >= second)
            { //secondの方が小さい
                Console.WriteLine("second");
              //（５）末尾削除、Tにはpushする
                T += second.ToString();
                list_S = removeChar(list_S.Length - 1, list_S);
            }
        }
            Console.WriteLine("答え：{0}",T);

        char[] removeChar(int indexToRemove, char[] list_S)
        {
            return list_S.Where((source, index) => index != indexToRemove).ToArray(); 
        }


    }
}

```



### 終わってみて

配列じゃなくて、List使ったらもっと追加、削除のところが簡単だったかも

```
var list = new List<string>() {"Alice", "Bob", "Charlie", "Dave"};
list.Add("Eve");
```
flutterのurl_launcherライブラリのlaunchでLost Connectionになってしまう

# 現象
Flutterの[url_launcher](https://pub.dev/packages/url_launcher)ライブラリを使っていて、
```dart
final badUrl = 'https://sample.com/マルチバイト文字.pdf';
launch(badUrl);
```
↑のような形でlaunchをした際に無言でLost Connectionになってしまいました。

# 原因と解決法
マルチバイトが含まれているせいだったようです。
```dart
final badUrl = 'https://sample.com/マルチバイト文字.pdf';
// ↓の処理を追加
final goodUrl = Uri.encodeFull(badUrl);
launch(goodUrl);
```
↑これで治りました。
【SQL】テーブル名一覧/カラム名一覧を取得する

あまり使用頻度は高くない。けど、いざという時に出てこないSQL
PostgreSQLにて使用していました。
# 特定スキームにあるテーブル名一覧を取得
```sql
select
  tablename
from
  pg_tables
where
  schemaname = '何かあれば記載'
order by
  tablename
;
```

# 特定のカラム名を持つテーブル一覧を取得
```sql
select table_name, column_name from information_schema.columns where column_name ='カラム名';
```

# 特定テーブルにあるカラム名一覧を取得
```sql
SELECT column_name FROM information_schema.columns WHERE table_name = 'テーブル名' ORDER BY table_name,ordinal_position;
```

# 日付カラムを任意の単位にする
```sql
  date_trunc('month', テーブルA.日付カラム)
```
→2022-03-16だとしたら「2022-03-01」になる
【Rails】ルートのルーティング設定の方法

# 目的
Railsチュートリアル学習の備忘録として

## ルート(root)
Railsアプリを作成し、起動した後「http://localhost:3000/」
などのローカルホストにアクセスすると呼び出される

## ルーティング(route/routing)
URLとアクションを結び付けること

# ルートのルーティング設定とは
簡単に言うと、一番最初に表示されるページ（ルート）を指定（ルーティング設定）しちゃおうということです！

# 設定方法
設定方法は簡単で
「config/routes.rb」のファイルを編集し、ルートに結び付けたいアクションを以下のように設定するだけです！
```ruby:config/routes.rb
root 'コントローラー名＃アクション名'
```

たとえば
「applicationコントローラー」の
「helloアクション」をルートに結び付けたい場合は、、
```ruby:config/routes.rb
root 'application＃hello'
```
こう設定すると、
「http://localhost:3000/」
にアクセスしたときにルーティング設定したアクションが呼び出されます！

# まとめ
最初に表示したいページがあるなら、ルートのルーティングを設定すればいいってことですね！！
Rubyで複数の配列を比較して重複の値を取り出したり、排除したりする方法

## 概要
今回は`Ruby`で**複数の配列**を比較して重複する値を取り除いたり、重複する値のみを抽出したりする方法を調べたのでメモとして残しておきます。

## やり方
### 重複した値を抽出

```ruby
a = [1, 2, 3, 4]
b = [3, 4, 5, 6]

a & b
# => [3, 4]
```

### 重複した値を取り除く

```ruby
a = [1, 2, 3, 4]
b = [3, 4, 5, 6]

a - b
# => [1, 2, 5, 6]
```
SQLの呼び出しでプレースホルダを使う理由

# はじめに
本記事ではGo言語とMySQLを使用しています。

Go言語のdatabase/sqlパッケージのチュートリアルを読んでて、プレースホルダを使う意味について分からなかったのですが、42Tokyoで一緒に勉強している学生から教えてもらえました。

http://go-database-sql.org/retrieving.html

> You should, in general, always prepare queries to be used multiple times. The result of preparing the query is a prepared statement, which can have placeholders (a.k.a. bind values) for parameters that you’ll provide when you execute the statement. This is much better than concatenating strings, for all the usual reasons (avoiding SQL injection attacks, for example).

> 一般に、複数回使用するクエリは常に準備する必要があります。このステートメントには、実行時に指定するパラメータのプレースホルダ (別名バインド値) を持たせることができます。これは、文字列を連結するよりもずっとよい方法です。通常の理由（たとえば、SQL インジェクション攻撃の回避など）でもそうです。



```go
stmt, err := db.Prepare("select id, name from users where id = ?")
if err != nil {
	log.Fatal(err)
}
defer stmt.Close()
rows, err := stmt.Query(1)
if err != nil {
	log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
	// ...
}
if err = rows.Err(); err != nil {
	log.Fatal(err)
}
```

`?`を使うこととSQLインジェクションの回避がどう関係してるんだ？？となりました。



# 用語解説
本題に入る前に用語を整理します。

### SQLインジェクション
> SQLインジェクションとは、データベースと連動したWebアプリケーションなどに対する攻撃手法の一つで、検索文字列など外部から指定するパラメータの一部にSQL文の断片などを混入させ不正な操作を行うもの。また、そのような攻撃を可能にする脆弱性。 “injection” は「注入」の意。

https://e-words.jp/w/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3.html
### プリペアードステートメント
> プリペアドステートメントとは、プログラム上で動的にSQL文を生成する必要があるとき、可変部分を変数のようにしたSQL文をあらかじめ作成しておき、値の挿入は処理系に行わせる方式。
プリペアドステートメントはSQL文の特定の箇所を変数のように後から変更できる状態（プレースホルダ）で記述された一種の雛形（テンプレート）で、事前にコンパイルされ高速に実行できる。値の挿入はSQL文の解釈とは別に言語処理系によって行われるため、入力文字列の一部を誤ってSQL文の一部として解釈する危険はない。

https://e-words.jp/w/%E3%83%97%E3%83%AA%E3%83%9A%E3%82%A2%E3%83%89%E3%82%B9%E3%83%86%E3%83%BC%E3%83%88%E3%83%A1%E3%83%B3%E3%83%88.html#:~:text=%E3%83%97%E3%83%AA%E3%83%9A%E3%82%A2%E3%83%89%E3%82%B9%E3%83%86%E3%83%BC%E3%83%88%E3%83%A1%E3%83%B3%E3%83%88%E3%81%A8%E3%81%AF%E3%80%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0,%E9%98%B2%E6%AD%A2%E3%81%99%E3%82%8B%E5%8A%B9%E6%9E%9C%E3%81%8C%E3%81%82%E3%82%8B%E3%80%82

### プレースホルダ
> プレースホルダとは、実際の内容を後から挿入するために、とりあえず仮に確保した場所のこと。また、そのことを示す標識などのこと。

https://e-words.jp/w/%E3%83%97%E3%83%AC%E3%83%BC%E3%82%B9%E3%83%9B%E3%83%AB%E3%83%80.html

# なぜプレースホルダを使うといいのか
用語解説が答えになっている気がしますが、具体例を使って解説します。
下記のように、クエリを作るときに`fmt.Sprintf()`を使用する場合とプレースホルダを使用する場合を比較します。

idは、リクエストパラメータから取得します。

```go
id := r.FormValue("id")
db.Exec(fmt.Sprintf("SELECT * FROM table WHERE id = %s", id))
```

```go
id := r.FormValue("id")
db.Exec("SELECT * FROM users WHERE id = ?", id)
```

## `fmt.Sprintf()`でクエリを作った場合
リクエストパラメータから文字列操作でクエリを作成します。
idはユーザーが自由に入力できる値なので、リクエストパラメータに
`10;DELETE FROM users`が入力された場合、`db.Exec`に渡される文字列は
`"SELECT * FROM users WHERE id = 10;DELETE FROM users"`となり`users`テーブルの全レコードが削除されてしまいます。
怖い。

## プレースホルダを使った場合

1. `"SELECT * FROM users WHERE id = ?"`というプリペアードステートメントがデータベースに送られて、構文が確定する。
1. `?`で確保された場所にリクエストパラメータに入力されたidが代入される。

という2段階で実行されるようです。
このとき、`?`の部分に代入される値はidに固定され、構文は変化しないのでリクエストパラメータに`10;DELETE FROM users`が入力されたとしてもこの文字列はidの値として不正なのでSQLがエラーを吐いてくれます。

# まとめ
プレースホルダはSQLインジェクションを防ぐために使用することが分かりました。
Agora Flutter SDK v5.0.0の概要

## はじめに
Agora SDKは映像音声の送受信においてクライアントサイドのSDKとインフラを提供するPaaSです。
縁起のよさそうな2022年2月22日にFlutter用のSDK v5.0.0がリリースされました。

Agora社公式の[ブログ](https://www.agora.io/en/blog/agora-releases-flutter-sdk-v-5-0-0/)の内容を翻訳した記事になります。

## Flutterのデスクトップサポート
Flutter SDKが、スマホやデスクトップなど、すべてのプラットフォームをサポートするために、より強力で安定したものになってきました。
Flutter SDKの最新のアップデートでは、デスクトップサポートに大きな進歩がありました。
Agoraはデスクトップサポートやその他の優れた機能を備えたv5.0.0をリリースしました。
以下は、その主なハイライトです。

## 互換性の変更
### Flutter2のサポート
パフォーマンスの向上やアーキテクチャの変更に加え、Flutter2ではNULLセーフティのような機能が追加されました。オプションとして定義されない限り、変数にNULLを含めることはできません。

## 新機能
### デスクトップアプリのサポート
Agora Flutter SDKは、さらに2つのプラットフォーム、macOSとWindowsをサポートするようになりました。
そのため、単一のコードベースで、スマホとデスクトップ向けのライブビデオ通話やライブビデオストリーミングのアプリケーションを構築することができます。

### 画面共有
今回のリリースで、WindowsとmacOS用のFlutter SDKに画面共有機能が追加されました。

画面を共有しながら同時にカメラ映像を配信することができるようになりました。以下は、アプリケーションに画面共有を追加するためのいくつかのメソッドです。

getScreenShareHelper : 子プロセスオブジェクトを取得します。
startScreenCaptureByDisplayId：ディスプレイIDを指定して画面を共有する。
startScreenCaptureByWindowId : ウィンドウIDを指定して、ウィンドウの全体または一部を共有する。
srartScreenCaptureByScreenRect : 画面矩形を指定して画面の全体または一部を共有する。

### 動画のレンダリング
2つのプラットフォームが導入されたことで、動画をレンダリングするためのコア技術に変化がありました。

Androidには、SurfaceViewとTextureViewの2つのレンダリングタイプがあり、どちらもSDKでサポートされています。
iOSでは、SurfaceViewはSDKレンダリングで、TextureView rawデータのセルフレンダリングです。
WindowsとmacOSでは、レンダリングタイプは1つだけで、rawデータのセルフレンダリングです。


## 改善
### Framework
プラットフォームの開発アーキテクチャはリファクタリングされ、IRISフレームワークをベースに開発されています。
このアーキテクチャの変更は、Agora.ioのネイティブSDKと整合性のある、より安定した先進的なSDKの構築に役立ちます。

これらは、agora_rtc_enginge 5.0.0リリースに含まれる更新の一部に過ぎません。すべてのアップデートは、[Flutter Release Notes](https://docs.agora.io/en/Video/release_flutter_video?platform=Flutter#v500-native-352)をご覧ください。

パッケージの詳細は[pub.dev](https://pub.dev/packages/agora_rtc_engine)で確認できます。

## サンプルコード
Flutter用にサンプルコードが[Github](https://github.com/AgoraIO/Agora-Flutter-SDK)に公開されています。利用シーンの多いサンプルが多く含まれています。
![スクリーンショット 0004-03-16 13.51.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/53eda484-aea7-04f3-e39a-de9a81797b68.png)

以下は画面共有のデモになります。レイアウトは多少ラフですが、macのデスクトップアプリとして正常に動作しました。

**TOPページ**
![スクリーンショット 0004-03-16 13.46.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/31caff9b-2f9d-7aed-3388-3df3451364dd.png)

**カメラ映像のみ送信**
![スクリーンショット 0004-03-16 13.46.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/854c3596-fa5c-2cf2-5dc7-721976a8fadc.png)

**画面共有も送信**
![スクリーンショット 0004-03-16 13.49.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/896883da-d833-638a-6fdb-e8df2f1a87d3.png)



## 最後に
[**agora.ioに関するお問い合わせはこちらから**](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=64947f02e3b101edbab3)
[<img width="912" alt="Agoraの詳細はこちら" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/5865441c-9d31-c702-3698-3aeb84927f28.png">](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=64947f02e3b101edbab3)
Rust は関数の引数でデストラクティングできる

デストラクティングとは何かというと`match`式でよく使うアレです。構造体とか列挙型の中身を取り出すヤツ。

https://doc.rust-lang.org/rust-by-example/flow_control/match/destructuring.html

関数の引数にも書けるんですね～。知りませんでした。

```rust
struct Name {
    first: String,
    middle: Option<String>,
    family: Option<String>,
}

fn main() {
    let name = Name {
        first: "Benki".into(),
        middle: None,
        family: Some("Tiny".into()),
    };
    let result = hello(name);
    assert_eq!(result, "Hello, Benki!");
}

// 　　　　　　　↓ ここでデストラクティング
fn hello(Name { first: v, .. }: Name) -> String {
    format!("Hello, {v}!")
}

// これはコンパイル出来ない。family が None の場合が未定義。
fn hoge(Name { family: Some(v), .. }: Name) {
    todo!()
}
```

使いどころはありそう？:thinking:
HTMLの超きほん　〜セクション関連要素でつくる文書構造〜

# セクションってなに？

`セクション`とは、見出しのあるコンテンツ、文章、意味のまとまりです。


# セクション関連の要素

以前は意味のまとまりを単に`div`要素でマークアップしていました。

HTML5では、一般的なセクションを表す`section`要素や、
ヘッダー領域・フッター領域を表す`header`要素・`footer`要素など、
特別な意味をもつ要素が追加されました。

引き続きすべてdiv要素で文書構造をつくることもできますが、
新しく追加された要素を使えば、**コンテンツごとの役割を明示的にマークアップ**できます。

## 新しく追加された要素の種類

| 要素名 | 用途 |
|:-:|:-|
|section|一般的なセクション、1セクションにつき１つの見出し(h1~h6)をつける|
|header|ヘッダー領域|
|main|メインコンテンツ領域|
|footer|フッター領域|
|nav|ナビゲーション領域（メニューや目次など）|
|article|独立した主要コンテンツ（記事ページの本文部分など）|
|aside|補足的なセクション（サイドバーの広告など）|

![0316-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2323790/d75b9696-24a8-a9e2-6d3d-107edcc546bd.png)

## （参考: その他の一般的な要素）

一般的な要素についてはこちらにまとめました。

https://qiita.com/yutaka_pg/items/0649d1d34e67b97325a4

# 補足
さいごまでお読みいただき、ありがとうございます！

この記事はプログラミング初心者であるわたしが、毎日の学習ログとして書きました。
ご質問やご意見、間違いのご指摘などがあれば、気軽にコメントください。

また、平日にもくもく作業したり質問しあえる仲間も募集しています。
ご興味がある方は[Twitter](https://twitter.com/yutaka_pg)などでご連絡くださいー！

これからもどうぞよろしくお願いします:rabbit:
なぜWeb標準のAPIがいいのか改めて考える

最近はDenoの普及により、Web APIの利用機会が増えました。Web APIが使えることはメリットの一つとされていますが、なぜWeb APIを使えることが良いことだとされているのか、改めて考えてみたいと思います。

## そもそもWeb APIとは何か

JavaScriptはランタイムによる拡張が許されている言語です。全てのランタイムで使える`Array`、`Map`などの[標準組み込みオブジェクト](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects)のほかに、固有のランタイムでしか使えない`fetch`や`process`などの拡張APIがあります。

この拡張API、ランタイムごとにいくつかの種類が存在します。例えば、

- Node.jsで使える[Node.js API](https://nodejs.org/api/)
- Denoで使える[Deno API](https://doc.deno.land/deno/stable/~/Deno)
- ブラウザなどで使える[**Web API**](https://developer.mozilla.org/ja/docs/Web/API)

などが該当します。

このうち「Web API」は[whatwg](https://github.com/whatwg)で定義されており、みなさんがいつもブラウザで使っている`fetch`、`document`、`HTMLElement`、`URL`などが含まれています。

近年ではWeb APIをブラウザだけでなくNode.jsやDenoにも導入し、サーバーサイドでもWeb APIを使おうという動きが広がっています。
この動きについて、どういうメリットがあるのか整理したいと思います。

## Web APIをサーバー側にも導入するメリット

### JavaScript実行環境はブラウザとサーバー、だけではない

JavaScriptが動く場所はブラウザとサーバーだけでなく多岐にわたります。筆者が認知しているJavaScriptランタイムとしては以下のような種類があります。

- ブラウザ
- Node.js
- Deno
- Google Apps Script
- ブラウザの拡張機能
- Waveformsという波形解析ツールで動くスクリプト

もし仮に、各ランタイムが完全に別々のAPIを採用していたらどうなるでしょうか？

各ランタイム共通で動作するコードを書くためには、
`if (EventTarget) else if (EventEmitter) else if (MyEventEmitter) else if (SugoiEventEmitter) else if (OreOreEventEmitter) else if (EventEmitterPollyfil) else ...`(以下略)となるのが目に見えますね。

このような状況を防ぐためには、事前にWeb APIというランタイム共通の仕様を定めておき、各ランタイムが必要な場合はその仕様に沿って実装するという方法が最善です。

もちろん、全てのWeb APIを実装する必要はありません。APIの中から一部の機能だけ実装することになるとしても、別のAPIを「車輪の最発明」するよりはいいです。

:::note
Denoは（自分が知る範囲では）この方針であり、「導入したいAPIがWeb APIにあれば、それを実装する」「Web APIにあるものでも、Denoにとって必要なければ実装しない」という方針になっています。
:::

かつてInternet explorerとNetScapeという2つのブラウザが主流だった頃、両者のAPIには互換性がありませんでした。違うブラウザでは実装を共有できないのが当たり前だった時代だと思います。しかし、共通のAPIを実装しなかったブラウザは廃れました。
今はブラウザとサーバーで実装を共有できないのが当たり前な時代ですが、いつかはそんな常識も破られる日が来るかもしれません。

### WPTによるテスト

Web APIには「WPT（Web Platform Test）」が存在します。これはその名の通り、Web API向けのテストコードです。

https://github.com/web-platform-tests/wpt

Web APIを実装するランタイムは、WPTにあるテストコードを使って実装をテストします。

仮に、Web APIではない独自のAPIが実装されたランタイムがあるとします。
その場合は当然、テストも1から実装されることになります。普通のユーザーから見れば、テストが正しいかどうかなんて分かりません。

その点、Web APIを使っているランタイムなら、WPTの通過率を見ることでAPIの信頼性を他のランタイムと比較することができます。WPTという信頼度の高いテストが最初から用意されているというのが、Web APIを使うメリットです。

### 仕様が堅牢

JavaScriptは特殊な言語です。一度stable（安定）としてWebに出荷されたAPIは、基本的には後方互換性のために削除できません。

この「削除できない」という理由から過去の古いAPI（`atob`や`XMLHttpRequest`）がまだ残っていることが批判の対象になっていたりしますが、それはまあそういう物です。後方互換性のために残っているだけなので無視してください。

話を元に戻します。一度出荷されたAPIは削除できないことから、最近作られるWeb APIは堅牢な設計になっています。ライブラリのアップデートで使い方が変わり、コードの書き換えを余儀なくされた経験がある方も多いと思いますが、Web APIについてはそういう事が無いので安心して使えます。

Web APIの設計方針については、[こちらのページ](https://triple-underscore.github.io/design-principles-ja.html)が詳しいです。

## まとめ

Web APIが利用できることは以下のようなメリットがあります。

1. 多数のJavaScript実行環境で共通の仕様を持つことで分断を回避する
1. WPTによるテストで信頼性を確保
1. 堅牢なAPI設計
Pythonのopen関数でUnicodeDecodeErrorが出ないようにする

# 問題点
Windows上でPythonを使っている場合、open関数でファイルを開いたときにUnicodeDecodeErrorが出ることがあります。
原因はWindowsがデフォルトでcp932でファイルをエンコーディングしてしまうことのようで、下記のようにopen関数にencodingの指定をすればエラー解消できます。
~~~sample.py
open('sample.csv', encoding='utf-8')
~~~

問題はライブラリパッケージ内でこのエラーが出た時です。自力でライブラリを書き換えたくはないので、上記以外の方法が必要です。

一番簡単なのはシステム環境変数にPYTHONUTF8を1で登録すれば良いらしいです。ただしこの方法だとプログラムを実行する環境ごとに設定が必要で、ちょっと面倒です。

最終的にプログラムのエントリポイントで下記を実行して、環境変数を書き換えることにしました。

```sample.py
import os

os.environ.setdefault('PYTHONUTF8', '1')
```

これで何か不都合あれば再調査しようと思います。

# 参考文献
下記を参考にさせて頂きました。
環境変数を書き換えたくない場合にはこの方法が良いのかもしれません。
[【Windows】黒魔術で Python が CP932 関係で UnicodeDecodeError を出さないように強制する](https://blog.tsukumijima.net/article/python3-windows-unicodedecodeerror-hack/ "【Windows】黒魔術で Python が CP932 関係で UnicodeDecodeError を出さないように強制する")
<備忘録> Railsアプリ新規作成方法

# Rails アプリ新規立ち上げ

railsがインストールされていることを確認
```
$ rails -v
```

### 返ってきたバージョンで立ちたげる

```
$ cd <作成したいディレクトリ>
$ rails new <バージョン> <アプリ名>
```

ズラーとディレクトリやらファイルやら作成される。

rails アプリ立ち上げ完了

以上
クラウドサービスの種類

## クラウドとは
クラウドとは「クラウドコンピューティング」や「クラウドサービス」の略称で、インターネットに接続することを前提とする各種のサービスのこと。

主体がインターネットの向こう側にあり、利用量に応じて柔軟にキャパシティを増やせることが特徴。サービスは、コンピュータリソースだったり、アプリケーションだったり、OSであったり、様々なものを提供している。

## SaaS
「Software as a Service」の頭文字を取った略語で「サース」と読む。
これまでパッケージ製品として提供されていたソフトウェアを、インターネット経由でサービスとして提供・利用する形態のことを指す。

**◆SaaSの特徴**
データをインターネット上に保存する
PC、スマートフォン、タブレットなど端末を選ばずにデータにアクセスできる
複数の人間が同一データを共有し、更に編集もできる

**◆メリット**
・必要なサービスをサブスクリプションですぐに利用できる
・時間・場所を気にせず利用できる
・管理が不要、運用は全てプロバイダーにお任せ

``SaaS``はプロバイダーが提供するアプリケーションやサービスをアカウントを開設するだけでいつでもどこでも利用できるので開発コストやリードタイムを消費せずに簡単かつスピーディーに導入できる。

また料金は従量課金もしくは、サブスクリプション方式の場合が多く、初期費用をかけずに必要なリソースを享受することができる。
管理やアップデートも基本的に全てプロバイダーが行ってくれるので、運用面でのコストも必要ない。

**◆デメリット**
・カスタマイズができない
・データの移行が困難

デメリットとしては基本的にはサービスのカスタマイズはできない（もしくはプロバイダー側によって明確に制約が設けられている）ので、自社の運用要件をサービス側に合わせてカスタマイズする必要があることが多い。

当然サービス同士での連携は期待できないので、もしサービスを移行するとなると、データの移行に際し大きな手間とコストを要する可能性がある。

**◆サービス例**
・Gmailなどのメールサービス
・Slackなどのコミュニケーションサービス
・Google Workspaceなどのグループウェアサービス

## Paas
「Platform as a Service」の頭文字を取った略語で「パース」と読む
アプリケーションソフトが稼動するためのハードウェアやOSなどのプラットフォーム一式を、インターネット上のサービスとして提供する形態のことを指す。

**◆メリット**
・サービス・アプリケーションの開発に専念できる
・初期費用や時間コストの削減が可能

PaaS は、クラウド環境のサーバー、OS、ミドルウェア、データベースなど、アプリケーション開発に必要な環境が揃っている（開発環境がプラットフォーム化されている）ため、インフラの設計や保守・管理を気にすることなくサービスやアプリケーションの開発に注力することができる。

**◆デメリット**
・開発の自由度が低い

最大の障壁は開発環境のカスタマイズ性の低さにある。
インフラがプラットフォームとして開発環境に組み込まれてしまっているのでCPUやストレージの選択ができなかったり、言語やミドルウェアが非対応だったりと、開発の要件を満たすことができないケースが多々ある。

**◆サービス例**
・Salesforce Heroku
・AWS Cloud9
・サイボウズ kintone
　AWSのCloud9など開発環境を提供するクラウドサービス

## IaaS
「Infrastructure as a Service」の頭文字を取った略語で「イァース」もしくは「アイアース」と読む。

情報システムの稼動に必要な仮想サーバをはじめとした機材やネットワークなどのインフラを、インターネット上のサービスとして提供する形態のことを指す。

**◆メリット**
・自由度が高く環境構築がしやすい
・システム管理者の負荷軽減

``IaaS``は環境構築の自由度が非常に高いため、カスタマイズ性に富んでいる。

CPUやストレージなどのスペックも、ユーザーが必要なタイミングで必要な分を自由に選んで利用することができるので、様々なニーズに対しコストを最適化しながらシステムの開発・構築が可能。

また、OSやインフラ部分についてはプロバイダー側にお任せできるので、システムの管理部門にとって大きな負担軽減につながる。

**◆デメリット**
・構築に専門性が必要
・メンテナンス範囲が広い

``IaaS``は、プラットフォームやプログラミング環境の構築を自社で行う必要があるため、専門知識を有するエンジニアが必ず必要になる。

また、メンテナンス範囲も広いので運用負荷は高くなる。
カスタマイズ性は高いが、あくまでもコンピューティングリソースをクラウド上で使えるサービスであり自社で管理しなければならないのは``PaaS``や``SaaS``と比較すると管理コストは高いと言える。

**◆サービス例**
・Amazon Web Service(AWS)
・Google Could Platform(GCP)
・Azure IaaS

## まとめ
IaaS、PaaS、SaaS の区別についてまとめると、ソフトウェアサービスを提供するのに必要な構成要素の提供段階によって区別することができる。

その構成要素は大きく分けて5つに区分される。
```
ネットワーク
ハードウェア
オペレーティングシステム（OS）
ミドルウェア
アプリケーショ
```

基本的にはこの5つはこの逆順に依存関係にある。アプリケーションはミドルウェアが無いと動作せず、ミドルウェアはOSが無いと動作しない、ということを覚えておくと良い。
[![Image from Gyazo](https://i.gyazo.com/785fd1bc89dbf58cfe3bc4389365f9b9.png)](https://gyazo.com/785fd1bc89dbf58cfe3bc4389365f9b9)

## 参考記事
[IaaS、PaaS、SaaSとは  それぞれの違いや概要・事例を5分で入門（図解あり）](https://cloud-ace.jp/column/detail01/)
<備忘録>Herokuインストール


### Herokuがインストールされているか確認する

```
heroku --version
```

バージョンが返ってきたらインストール済み。

### インストール手順

https://cli-assets.heroku.com/heroku.pkg
からpcにインストール

または

```
$ brew install heroku/brew/heroku
```

でhomebrew にインストール

以上
dockerで起動したelasticsearchのsnapshotをs3に保存する方法

# 目次
- dockerfile
- docker-composefile
- aws認証設定
- snapshotrepositoryの登録
- snapshotの作成

## dockerfile
```
FROM docker.elastic.co/elasticsearch/elasticsearch:7.6.0
RUN bin/elasticsearch-plugin install --batch repository-s3
```

## docker-composefile
```
version: '3.8'

services:
  localstack:
    container_name: localstack
    image: localstack/localstack:0.13.3
    environment:
      SERVICES: s3
      EDGE_PORT: 4566
    ports:
      - '4566:4566'

  es01:
    build: ./elasticsearch
    volumes:
      - /usr/share/elasticsearch/data
    environment:
      - discovery.type=single-node
      - cluster.name=docker-cluster
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    ports:
      - '9200:9200'

```
## aws認証設定
コンテナ内部に入る
```
docker container exec -it container_name bash
```
アクセスキーとシークレットキーを登録し確認
```
elasticsearch-keystore add s3.client.default.access_key

elasticsearch-keystore add s3.client.default.secret_key

bin/elasticsearch-keystore list
```
ノードにあるkeystoreをリロード

```
curl -X POST -v "localhost:9200/_nodes/reload_secure_settings" 
```

## snapshotrepositoryの登録
まずs3にバケットを作成したのちに、下記のようなリクエストを送る
```registerrepository.py
import requests

url = 'http://localhost:9200/_snapshot/snapshotrepository_name'
headers ={'Content-Type': 'application/json'}
payload = {
  "type": "s3",
  "settings": {
    "bucket": "bucket_name",
    "endpoint" : "endpoint_name",
    "protocol": "http",
    "path_style_access": "true"
  }
}
response = requests.put(url,headers=headers,json=payload)
print(response.text)
```
## snapshotの作成

```makesnapshot.py
import requests

url = 'http://localhost:9200/_snapshot/repository_name/snapshot_name'
response = requests.put(url)

print(response.text)
```

### 備考
keystoreのリロードを行わないと下記のようなエラーになる
```
{"error":{"root_cause":[{"type":"repository_verification_exception","reason":"[repository_name] path  is not accessible on master node"}],"type":"repository_verification_exception","reason":"[repository_name] path  is not accessible on master node","caused_by":{"type":"i_o_exception","reason":"Unable to upload object [tests-rQf2zvkRSFmXhH4i52mbcg/master.dat] using a single upload","caused_by":{"type":"sdk_client_exception","reason":"Unable to load credentials from service endpoint","caused_by":{"type":"connect_exception","reason":"Connection refused"}}}},"status":500}
```
Google reCAPTCHAの中央寄せ

Google reCAPTCHAを設置しようとすると、

```html
<div class="g-recaptcha" data-sitekey="" data-callback="" data-expired-callback="" style=""></div>
```

こんなようなソースを貼れと言われる。

これを貼ると、その中にdivが作られて、だーっといろいろなソースが生成されて表示されるが、divの中のdivなので中央寄せができない。

ということでcssを以下のようにすればよい。

```css
.g-recaptcha div {
    display: inline-block;
}
```
Google フォーム おぼえがき

# 趣旨：Googleフォームでハマったことをメモしておく
* 同じことでまたハマって時間を空費しないようにメモ。

* 以下、トリガーが返すイベントオブジェクトを `e` として記述します。

# トリガーには Formsイベント と Sheets イベントの２種類があるので注意！
* 回答者がフォームを送信した際に発火するトリガーには２種類あります。
 
* ひとつは、**フォーム** そのものに備わったトリガー
https://developers.google.com/apps-script/guides/triggers/events#form-submit_1
* もうひとつは、フォームにリンクした **スプレッドシート** に備わったトリガー
https://developers.google.com/apps-script/guides/triggers/events#form-submit

## フォームに備わったトリガー
* 回答を取得するには、イベントオブジェクト `e` から取得できる `FormResponse` オブジェクト `e.response` を用います。
* `e.response` は、空欄でないすべての質問への回答を含みます。
    * 以前の回答を編集する場合、フォームには前回送信した値が規定値として書き込まれています。予め入力されていた前回送信内容を編集しなくても、`e.response` には値が含まれます。
    * 回答が必須でない質問を空欄（未解答）で送信すると、`e.response` には含まれません。その質問を指そうとすると属性が存在せず、エラーになります。


## スプレッドシートに備わったトリガー
* 回答を取得するには、イベントオブジェクト `e` から取得できるオブジェクト `e.namedValues` および配列`e.values`を用います。
* `e.namedValues` および`e.values`は、更新のあった質問の回答だけを含みます。
    * 新規回答であればすべての回答を含みますが、以前の回答を編集した場合、前回から更新されなかった質問のデータは含まれません。


# フォーム起動時のトリガーは、フォーム編集画面起動時なので注意！
* Googleフォームには「起動時」のトリガーがあるが、これは、**フォーム回答者がフォームを開いた時ではなく** 、フォーム作成者がフォーム編集画面を開いたときに発火するトリガーなので注意。
    * ~~誰得なの？~~ 起動時トリガーは、フォームの選択肢を作成者が決め打ちせず、スプレッドシートなどに基づいて生成する際などに有用なのかもしれない。（本番運用時には、同じトリガーを１日１回など間隔を決めて実行する感じか）
https://developers.google.com/apps-script/guides/triggers/events#open_3


# フォームに送信された回答は編集できない
* フォームにリンクしたスプレッドシートの内容は、送信後に編集・削除することが可能だが、フォームそのものに登録されている回答を編集することはできない（削除は可能）。
    * スプレッドシートで編集した内容を、フォームの回答に反映することはできない。
    * GAS には、フォームの回答を作成する `createResponse()` 関数が備わっているが、回答の送信者はトリガーを作成したユーザーに設定されるため、任意の回答者の回答を置き換えることはできない。
* 回答者が「回答を編集」して送信済みのフォームを編集する際に、前回の回答をバックエンドで編集して表示するといったことはできない。
    * 例えば、写真をアップロードするフォームで、回答者が前回までにアップした写真の一覧をフォーム画面に表示するような処理は（おそらく）できない。
* また、回答者が閲覧するフォーム画面を動的に編集できるトリガーも存在しないので、回答者のアカウントごとに、フォーム上に掲載する情報を動的に変えることもできない。


# フォームとスプレッドシートは、フォームの回答とスプレッドシートの行が紐づけられている
* フォームとスプレッドシートをリンクしたとき、フォームのそれぞれの回答は、スプレッドシートの行に紐づけられている。より具体的には、おそらく、スプレッドシートの各セルのIDと紐づけられている。
    * スプレッドシート側の行を削除してしまった場合、undo して行を復元しない限り、その行に対応するフォームの回答をスプレッドシート状に復元することは不可能。（紐づけられたIDを持つセルを復元しなければならない）
        * undoで復元できない場合、いったんリンクを解除して、もう一度リンクを設定して新しいシートをつくるしかない（スプレッドシートは同じファイルでも可）。
    * フォームを「以前の回答を編集できる」設定にしてある場合、スプレッドシート上で対応する行が削除されてしまっていると、以前の回答を編集したフォームが送信されても、スプレッドシートは更新されない（新たな行が追加されることはない）。（紐づけられたIDのセルが消失しているため）

# フォームの回答のIDのユニークさの特徴
* フォームの回答にはIDがあり、これに基づき、フォームから任意の回答を削除したりできる。
## 回答を１回に限定した場合の回答IDの性質
* 回答を１回に限定した場合、ユーザーはGoogleアカウントで認証を受け、同一のユーザーは１回しか回答できない。
    * フォーム管理者が回答を削除すれば、再回答可能になるので、正確には「同時に２つの回答を登録することができない」である。
    * この時、**既存の回答が削除され、ユーザーが２度目以降の回答を登録する際、回答に付与されるIDは、既に削除した初回の回答に与えられていたIDと同一である。**
    * フォームには、同時に同じIDの回答は存在しないので、フォームではユニークな回答IDであるといえる。
    * 一方、スプレッドシートにリンクして、フォームの回答を流し込んでいる場合、フォームの回答を削除しても、スプレッドシートのデータは、意図的に更新しない限りそのまま残る。スプレッドシートの回答が残っている場合、２度目以降の回答は、その行を上書きする（新たな行は加わらない）。
    * 既存の回答を削除し、次の回答を過去の回答は別に扱いたい場合、回答IDでは区別できないので、自分で別の方法を用意しなければならないので、注意を要する。

# 全角スペースから半角スペースへの強制変換（自動変換）

* GASを用いてフォームの選択肢に文字列をセットするさい、GASの文字列変数に含まれる全角スペースが半角スペースに強制変換（自動変換）される。
    * そのため、例えば、スプレッドシート中の文字列をフォームの選択肢にコピペし、フォームへの回答データで選ばれた選択肢とスプレッドシートを照合しようとする際などに、スプレッドシートでは全角スペースなのに、フォーム選択肢は半角スペースになっている為に、同じ文字列として照合できない不具合が発生しうる。
    * こうした現象を織り込んで照合をコーディングしないと、スプレッドシートの範囲からプルダウンメニューの質問をつくって１つ選択させたのに、選択した値がスプレッドシートに見つからないといった謎の不具合が発生しうる。
Lets Encrypt 証明書更新

証明書の期間内更新

```
certbot renew
```

証明書の期限切れ後の更新

```
certbot certonly --standalone -d ｘｘｘ.xxx.com
```

エラーが出た場合

```
An unexpected error occurred:
FileExistsError: [Errno 17] File exists: '/etc/letsencrypt/archive/xxx.xxx.com/privkey2.pem'
```
は

```
rm /etc/letsencrypt/archive/xxx.xxx.com/privkey2.pem
```
で解決