OmniAICreator/Qiita-1.07M huggingface dataset:
DynamoDBのローカル開発環境構築(マイグレーション編)

#概要
前回の記事でローカル開発環境にDynamoDBのインストール方法を記載しました。
今回はTBL作成やデータのロードに関する記事となります。

###TBL確認
```javascript:TBL一覧の確認
~/develop/aws/dynamodb/dynamodb_local_latest $ aws dynamodb list-tables --endpoint-url http://localhost:8000                         
{
    "TableNames": []
}
```

###TBL作成

```shell:Musicテーブル作成
aws dynamodb create-table \
    --table-name Music \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5 \
    --endpoint-url http://localhost:8000
```
```shell:MusicTBLへのデータ挿入
aws dynamodb put-item \
    --table-name Music  \
    --item \
        '{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Call Me Today"}, "AlbumTitle": {"S": "Somewhat Famous"}, "Awards": {"N": "1"}}' \
--endpoint-url http://localhost:8000
```
```shell:MusicTBLへのデータ取得
aws dynamodb get-item --consistent-read \
    --table-name Music \
    --key '{ "Artist": {"S": "Acme Band"}, "SongTitle": {"S": "Happy Day"}}' \
    --endpoint-url http://localhost:8000
```
```shell:MusicTBLへのデータ更新
aws dynamodb update-item \
    --table-name Music \
    --key '{ "Artist": {"S": "Acme Band"}, "SongTitle": {"S": "Happy Day"}}' \
    --update-expression "SET AlbumTitle = :newval" \
    --expression-attribute-values '{":newval":{"S":"Updated Album Title"}}' \
    --return-values ALL_NEW \
    --endpoint-url http://localhost:8000
```
```shell:MusicTBLへのクエリ実行
aws dynamodb query \
    --table-name Music \
    --key-condition-expression "Artist = :name" \
    --expression-attribute-values  '{":name":{"S":"Acme Band"}}' \
    --endpoint-url http://localhost:8000
```
LambdaでAWSAPIがときどきタイムアウトになる原因

#結論
サブネットのACLが原因でした。
ACLのポート制御を1024-65535に設定後、解消されました。

#遭遇した事例
・LambdaからS3へのファイルアップロードが10回に1回くらいエラーになる
・LambdaからCloudwatch metricsへのputが3回に1回くらいエラーになる

#この事象が発生するLambdaの条件
VPCサブネット内に構築しているLambda

#なぜ起こったか
ACLのポート制御の設定範囲がAWSのリソースが使用する一時ポートを許可していなかった。

AWSのリソースは一時ポートを使用しているものがあり、その一時ポートの疎通を許可してあげないといけませんでした。
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-network-acls.html#nacl-ephemeral-ports

>
一時ポート
前のセクションでは、ネットワーク ACL の例に 32768～65535 という一時ポートの範囲を使用しています。ただし、使用または通信しているクライアントの種類によっては、ネットワーク ACL に別の範囲を使用してもかまいません。
リクエストを開始するクライアントは、一時ポートの範囲を選択します。範囲は、クライアントのオペレーティングシステムによって変わります。
多くの Linux カーネル (Amazon Linux カーネルを含む) は、ポート 32768～61000 を使用します。
Elastic Load Balancing からのリクエストは、ポート 1024-65535 を使用します。
Windows Server 2003 を介する Windows オペレーティングシステムは、ポート 1025～5000 を使用します。
Windows Server 2008 以降のバージョンでは、ポート 49152～65535 を使用します。
NAT ゲートウェイはポート 1024～65535 を使用します。
AWS Lambda 関数は、ポート 1024-65535 を使用します。

#最後に
エラーを検索しても出てこなかったので、同様のエラーに困っているかたの参考になれば幸いです。
Before starting UiPath:DataTableってなんだ

## 皆もすなるQiitaといふものを、儂もしてみむとてするなり。

と言う訳で、こん＊＊は！はなっち！です。

★★★この記事はUiPathブログ発信チャレンジ2021サマー、7/28の記事です。★★★

今回は、ちょっとしたシリーズです。UiPathを使うに当たって、UiPathの機能ではなく、コンピュータ言語を使う上での基礎知識を展開していこうと思います。

#DataTableってなんだ

文字列型、数値型、日付時刻型と違って、DataTable型ってなんだか分からない方が多いと思います。
DataTable型は、列と行を持ち、その交点に値を保有できる、所謂、EXCELのシートのようなものを想像すればいいと思います。

DataTableを使用するには、二つの方法があります。
　　　　１）出力がDataTable型のアクティビティを使用する。
　　　　　　「CSV を読み込む」アクティビティ
　　　　　　「範囲を読み込み」アクティビティ
　　　　　　「構造化データを抽出」アクティビティ
　　　　　　「データテーブルを生成」アクティビティ
　　　　２）自らが、定義したDataTable型に対して、初期化、列の追加をし、行を追加する。
　　　　　　「代入」アクティビティで、初期化する
　　　　　　「データ列を追加」アクティビティで、列を追加する
　　　　　　「データ行を追加」アクティビティで、行を追加する
　　　　　　「データテーブルを構築」アクティビティで、列も追加定義する（上記三つを１アクティビティで実装も可能）

出力がDataTable型のアクティビティの代表に、以下のものがあります。
　　　　１）「構造化データを抽出」アクティビティ
　　　　　　所謂、WEB上の表からデータスクレイプするものです。
　　　　２）「範囲を読み込み」アクティビティ
　　　　　　EXCELシートから、指定した範囲をもってDataTable型に展開するものです。
　　　　３）「CSV を読み込む」アクティビティ
　　　　　　CSVファイルを、DataTable型に展開するものです。
　　　　４）「データテーブルを生成」アクティビティ
　　　　　　サンプルデータを基に、DataTable型に展開するものです（意外と思い通りにならない）

上記アクティビティを使わずにDataTableを使用するには、以下の手順を踏みます。
　　　　１）「代入」アクティビティ
　　　　　　DataTable型変数を、初期化します(代入アクティビティで、New DataTableする)
　　　　２）「データ列を追加」アクティビティ
　　　　　　初期化したDataTableに対して、必要な列を定義します。
　　　　３）「データテーブルを構築」アクティビティ
　　　　　　DataTableの初期化と、アクティビティ上で定義した列も定義します（上記二つを１アクティビティで実装）
　　　　　　「データテーブルを構築」アクティビティに設定する事で、データ行も追加する事ができます。
　　　　４）「データ行を追加」アクティビティで
　　　　　　列が追加されたDataTableに対して、必要な行を格納します。

最近のUiPath Studioでは、変数を定義する際の型の候補に「DataTable」が追加されています（2018.4.4には無かった）。
それは即ち、UiPath側でもDataTableが多用されている、利便性を向上させようと言う意思の裏付けだと思っています。

##おわりに
いかがでした？

DataTable型は、EXCELのシート上のセルを操作するEXCEL-VBAを作った事がある人には、多少理解しやすいかもしれませんね。
ただ、DataTable型は、もっと奥が深く、LINQ機能で、対象データをフィルタ掛けつつ並び替えをしたり、行の値毎の件数、合計数を計測したりする事ができます。
私も勉強中であります。皆様に負けぬよう、頑張ります。

是非UiPathでのロボ開発の一助になればと思っています。

ありがとうございました！
【Git】チームから学ぶGitの使い方　git resetの使い方編

####My Profile
プログラミング学習歴②ヶ月目のアカウントです！
プログラミングスクールで学んだ内容や自分が躓いた箇所等のアウトプットの為に発信しています。
また、プログラミング初学者の方にわかりやすく、簡潔にまとめて情報共有できればと考えています。
もし、投稿した記事の中に誤り等ございましたら、コメント欄でご教授いただけると幸いです。　



#対象者

* git resetの使い方を知りたい方


#目的

* git resetを使ってaddやcommit前に戻せるようになる

#実際の手順と実例
###0.前回までの流れ

https://qiita.com/nao0725/items/cc0cd8a047100a0dccd9

###1.git reset前に知っておくべきこと

* **working tree**：現状のコード・ファイル変更すると更新される
* **index**：addしたもの（＝commitの対象=変更記録を残す対象）。addすると更新される。
* **HEAD**：今いるブランチの最新のcommit。commitやcheckoutなどで更新される


###2.戻し方
戻し方は代表的なものが三つあります。

#####1.git reset --soft

* **working tree**： ○
* **index**：○
* **HEAD**：✕


#####2.git reset --mixed

* **working tree**： ○
* **index**：✕
* **HEAD**：✕

対応に限れば、GitHubから余計な変更を消し去りたいときには、ファイル変更はそのままで、add/commitを取り消す場合がほとんどです。なので、このコマンドがデフォルトです。

#####3　git reset --hard

* **working tree**： ✕
* **index**：✕
* **HEAD**：✕


###3.どこまで戻るか

```
$ git reset HEAD^
```
直前のadd, commitを取り消します

````
$ git reset commit_id
````
特定のコミットまでresetすることができます。

* commit_idは**git log**で調べることができます。
* **git log --oneline**を実行すると、commit_idが見やすいです。
独習Java(3章)

3-1
連続する文字列連結にはString Builderクラスのappendメゾットを用いる
var builder = new String Builder();
for(int i; i<1000; i++){
builder.append("いろは");
}

浮動小数点の演算をする際には内部的には２進数で処理されるので誤差が出る場合がある
よってBig Decimalクラスを用いる
import java.math.BigDicimal;
中略
var bd1 = new Big Decimal(0.2);
var bd1 = new Big Decimal(0.4);
var bd1 = new Big Decimal(0.5);
System.out.println(bd1.add(bd2)multiply(bd3));
ここにはadd/subtract/multiply/divideを用いて演算


3-2　代入演算子
intは基本型だが、Stringは参照型なのでここはしっかり違いを見極める
基本型・・整数/浮動小数点/審議
参照型・・クラス型/インターフェイス型/配列型

定数は値を変更できな変数


3-3関係演算子
同一性・・オブジェクト参照同士が同じオブジェクトを持っている
同地性・・オブジェクトが同じ値
文字列は==で比較すると別で作られたオブジェクトと認識されるのでequalsメゾットを用いる
浮動小数点はBig Dicimalクラスのcompare toメゾットを用いる(同じならば0，大きければ1，小さいときは―１)
定数EPSILONは誤差の許容範囲を示す
配列の比較はjava.utilのequalsメゾット

3-4 論理演算
既知のためパス

3-5ビット演算
利用する頻度は多くないので１度本を終了して２週目に
ActiveStorageの実装方法

#Acitive Storageを使う際の備忘録
##ImageMagickのインストール
`brew install imagemagick`
##MiniMagickのインストール
-imagemagickをrubyで使えるようにしてくれるgem
Gemfile
`gem 'mini_magick'`
ターミナル
`bundle install`
##ImageProcessingのインストール
-画像サイズを調整するgem
Gemfile
`gem 'image_processing'`
ターミナル
`bundle install`
サーバーの再起動
`rails s`
##Active_Storageをインストール
-マイグレーション の作成
ターミナル
`rails active_storage:install`
`rails db:migrate`
##modelにhas_one_attachedメソッドを記述
-テーブルに画像を紐付ける
`has_one_attached :image`
##コントローラーで画像の保存を許可する
`params.permit(:image)`
tempfile

#ファイルの入出力のテストに使います。

```py
import tempfile

#withを閉じるとファイルは削除されます
with tempfile.TemporaryFile(mode='w+') as t:
    t.write('hello')
    t.seek(0)
    print(t.read())

#withを閉じた後もファイルは残ります
with tempfile.NamedTemporaryFile(delete=False, mode='w+') as t:
    print(t.name)
    t.write('test\n')
    t.seek(0)
    print(t.read())

#withを閉じるとディレクトリは削除されます
with tempfile.TemporaryDirectory() as td:
    print(td)

#ディレクトリは削除されません
temp_dir = tempfile.mkdtemp()
print(temp_dir)
```

```txt
hello
/var/folders/0j/3nls1w512cdc4h2fr4543lw40000gn/T/tmplb079t65
test

/var/folders/0j/3nls1w512cdc4h2fr4543lw40000gn/T/tmp_tnjm74h
/var/folders/0j/3nls1w512cdc4h2fr4543lw40000gn/T/tmp1b75osd0
```
docker-compose で Can't separate key from value と怒られた時の対応

Docker for Desktopをアップデートしたら以下のエラーが

```bash
$ docker-compose run
=> Can't separate key from value
```

Docker2をデフォルトで使う設定になってしまっているようなのでチェックを外し設定をオフにします。

![20210728062017.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218/51df2073-870b-6907-76f1-026c1a286f93.png)

https://stackoverflow.com/questions/68206642/how-to-solve-cant-separate-key-from-value-docker

---

※こちらの記事は自ブログからの転載です

https://akinov.hatenablog.com/entry/2021/07/28/062103
Visual Studio 2019をインストールしたのでキーバインドの設定をした

## 概要

Visual Studio 2019 でキーバインドの設定をしました。
VsVimが素直ですぐできました。
Jared Parsonsさんありがとうございます。
https://twitter.com/jaredpar

## キーバインド変更

> 競合したキーは全て外した

| キー           | 動作                                |
| ------------   | ----------------------------------- |
| Ctrl+Alt+S     | ツール.オプション                   |
| Ctrl+Shift+R   | 編集.全てに移動                     |
| Ctrl+Shift+F,F | 編集.検索                           |
| Ctrl+Shift+F,R | 編集.置換                           |
| Ctrl+H         | 編集.フォルダーを指定して検索       |
| Ctrl+Shift+H   | 編集.フォルダーを指定して置換       |
| Ctrl+/         | 編集.行コメントの切り替え           |
| Ctrl+]         | 編集.定義へ移動                     |
| Alt+1          | 表示.ソリューションエクスプローラー |
| Alt+3          | 表示.検索結果1                      |
| Alt+左矢印     | 表示.戻る                           |
| Alt+右矢印     | 表示.次に進む                       |
| Ctrl+Alt+Space | 無し（補完候補をEnterで選択可否切替は不要) |


## VsVimを優先

| キー      | vim .vsvimrc   |
| --------- | -------------- |
| Ctrl+A    | 行の先頭へ     |
| Ctrl+B    | ページアップ   |
| Ctrl+D    | 半ページダウン |
| Ctrl+E    | 行の末尾へ     |
| Ctrl+F    | ページダウン   |
| Ctrl+N    | 下矢印         |
| Ctrl+P    | 上矢印         |
| Ctrl+R    | :redo          |
| Ctrl+U    | 半ページアップ |
| Ctrl+V    | 短形選択       |
| Ctrl+W    | ＜C-W＞        |
| Ctrl+PgDn | :tabnext       |
| Ctrl+PgUp | :tabprevious   |

## ~/.vsvimrc

```vimscript
" 設定の再読み込み
nnoremap <Leader><Leader> :<C-u>source ~/.vsvimrc<CR>

" クリップボード
set clipboard=unnamed

" 検索時に一周しない
set nowrapscan

" 検索文字入力途中に候補へジャンプしない
set noincsearch

" 検索結果をハイライト
set hlsearch

" 検索時の大文字小文字の区別の設定
set smartcase

" コマンドモードに移る時にIMEをOFFにする
set iminsert=0
set imsearch=-1 "-1はiminsertの値に同じ

" 入力中のコマンド表示
set showcmd

" redo undo
nnoremap u uzz
nnoremap <C-r> <C-r>zz

" 直前の編集場所に移動する時は文の先頭
noremap `. '.

" カーソル位置の単語検索 検索前にエスケープを押す
nnoremap # <Esc>#
nnoremap * <Esc>*

" Emacs
nnoremap <C-a> ^
vnoremap <C-a> ^
nnoremap <C-e> $
vnoremap <C-e> $h
inoremap <C-a> <Home> "なぜ機能しない
inoremap <C-e> <End>
inoremap <C-b> <Left>
inoremap <C-f> <Right>
vnoremap <C-n> j^
vnoremap <C-p> k^

" 検索時にカーソル行が画面中央になるようスクロール
noremap n nzz
noremap N Nzz
" 段落移動時スクロール
noremap ( (zz
noremap ) )zz
" 一発で現在の階層の始まりの括弧へ移動
noremap { [{
noremap } ]}

" 検索結果のハイライトを消す
noremap <Esc><Esc> :<C-u>nohlsearch<CR>

" ページ移動時にカーソルを画面中央へ移動させる
noremap <C-f> <C-f>M
noremap <C-b> <C-b>M
noremap <C-d> <C-d>M
noremap <C-u> <C-u>M
" PageDown,PageUp
noremap <PageDown> <C-f>M
noremap <PageUp> <C-b>M

" tab移動
nnoremap <C-PageUp> :<C-u>tabprevious<CR>
nnoremap <C-PageDown> :<C-u>tabnext<CR>

" 選択中の文字列を検索
vnoremap / y/<C-r>*<CR>n
vnoremap ? y?<C-r>*<CR>n
" 選択中の単語を検索
vnoremap * y/<C-r>*<CR>n
vnoremap # y?<C-r>*<CR>n

" Error on line 118: Missing quote となるのでひとまず一番最後に
" <Leader>
let mapleader = '\'
```
2021/07/26開催 Connpassイベントランキング

# 申込数TOP5

|順位|イベント名|グループ|申込数|定員|
|:---:|:---|:---|:---:|:---:|
|:one:|[Merpay Tech Fest 2021](https://mercari.connpass.com/event/215035/)|[メルカリ／Mercari](https://mercari.connpass.com/)|801||
|:two:|[AWSの基礎を学ぼう 第五十一回](https://awsbasics.connpass.com/event/217041/)|[AWS エバンジェリストシリーズ　AWSの基礎を学ぼう](https://awsbasics.connpass.com/)|385||
|:three:|[RPA勉強会！Power Automate Talk #13 Power Appsのキャンバスアプリ](https://rpacommunity.connpass.com/event/219031/)|[RPACommunity](https://rpacommunity.connpass.com/)|164|172|
|:four:|[ノーコードツールとLINEで在庫管理ミニアプリを作ろう！](https://linedevelopercommunity.connpass.com/event/218562/)|[LINE Developers Community](https://linedevelopercommunity.connpass.com/)|119||
|:five:|[Agile Tech EXPO mini #5 アジャイルに開発を内製化する方法](https://agiletechexpo.connpass.com/event/219546/)|[Agile Tech EXPO](https://agiletechexpo.connpass.com/)|117|150|
AWS CodeCommitにSSH接続しようとしたら"Permission denied (publickey)"になった件

# 課題
AWS CodeCommitにRepositoryを立てて、サクッとSourceを共有しようとしたら、予想外にハマった件。
接続元は、Fedora34 Workstation.

```
[root@ip-***-***-***-*** ~]# ssh -T A******************D@git-codecommit.us-east-1.amazonaws.com
sign_and_send_pubkey: no mutual signature supported
A******************D@git-codecommit.us-east-1.amazonaws.com: Permission denied (publickey).
```
# 原因
詳細はよく分からないが、[最近のOpenSSHは古い暗号化形式を拒否するらしい](https://qiita.com/asari-mtr@github/items/8327b8cbd6fd49e4bec2)。
これ、昔から使ってるSSH Private Keyを使って最新のAmazon LinuxのEC2に接続しようとするときにもたまに起こる。
# 対応方法
`/etc/ssh/ssh_config`に以下を追記する。

```/etc/ssh/ssh_config
Include /etc/ssh/ssh_config.d/*.conf
PubkeyAcceptedKeyTypes +ssh-dss    # <= 追記
```
`~/.ssh/config`に個別に記述する方法もあるけど、意外とハマりがちなので特別な理由がないなら `ssh_config`に記述した方がSmartっぽい。
# 結果
SSH接続できるようになる。

```
# ssh -T A******************D@git-codecommit.us-east-1.amazonaws.com
You have successfully authenticated over SSH. You can use Git to interact with AWS CodeCommit. Interactive shells are not supported.Connection to git-codecommit.us-east-1.amazonaws.com closed by remote host.
```
もちろん、`Git clone`も上手く行く。

```
# git clone ssh://A******************D@git-codecommit.us-east-1.amazonaws.com/v1/repos/*** 
Cloning into '***'...
warning: You appear to have cloned an empty repository.
```
# その他
CodeCommitを利用するIAM UserにはMFAを有効にしない方が良いっぽい。
どうしても有効にする必要がある場合には、[ここ](https://qiita.com/Morihaya/items/0ab6d5599cca96de3543)とか[ここ](https://qiita.com/ohtsuka1317/items/7a09ac29e0cc17303972)を参考にすると良さそう。
[Rust]JSON APIでデータにフィールドがなくてもエラー回避がしたい!

3回同じことを調べてしまったので結論だけ先に書いておく。

毎回、skip_deserialize_if とか ignore とかで探してしまうが、これをつけるだけ。

```rust
 #[serde(default)]
```

---

### #[derive(Deserialize)] なstructでも #[serde(skip_if_empty)] がしたい!

JSONなAPIでパラメータを受け取るとき、全てのkeyがないとdeserializeの時にエラーになる。
こう言う構造体があって

```rust
use serde::{Deserialize, ...};

#[derive(Deserialize)]
pub struct HogeRequest {
    pub id: i32,
    pub name: String, // <- 必須
    pub memo: String, // <- なくても良い
}
```

memoが入っていないとエラーになる。

```shell
$ curl -X POST https://example.com/api/hoge -d '{
  "id": 1,
  "name": "これは必須"
}'

# エラーレスポンス memoというフィールドがないと言われる
> [ERROR] missing field 'memo' at line 1 column xxx
```

### 対処法としては3つ

1. `"memo": "",` のように必ずフィールドを設定する
    1. react-formだと空白のフィールドを指定してくれない。なので却下
1. Option<String>にする。
    1. 今回はnullと空文字を分ける必要がない。DBも含めて面倒。却下
1. serdeのオプションやエラー回避処理を使う

なので、フィールドがなくてもエラーにせずに空文字が入るようにしたい。
例えばgoだと omitempty 入れれば良いだけ。

```go
type HogeRequest struct {
  ID int `json:"name"`
  Name string `json:"name"`
  Memo string `json:"memo,omitempty"` // フィールドがない場合は空文字が入る
}
```

で、シリアライズ時のものとして`skip_serialize_if=is_empty` というのがあるので
`skip_deserialize_if`みたいなものがあるかと思って探してしまうがそんなものはない。
ignore というオプションもありそうだが存在しない。
正解はdefaultを使うオプション

```rust
use serde::{Deserialize, ...};

#[derive(Deserialize)]
pub struct HogeRequest {
    pub id: i32,
    pub name: String, // <- 必須
    #[serde(default)]
    pub memo: String, // <- ないと空文字が入る
}
```

default traitを実装してやることで、Vec&lt;String&gt; とか HashSet&lt;String&gt;とかでもよしなにやってくれる。
一度の INSERT 文で複数行追加する（Oracle とそれ以外で）

自分用まとめ
[RDBMS の主要製品とそのお試し](https://qiita.com/ryhoh/items/4d7fc1ca6e4b04f11558)を書いていて、気づいたのでメモ

## お約束
間違いが含まれる可能性がそこそこあります。
間違いを見つけたら「どこを」「どのように」修正すべきか教えてください。

## やりたいこと
あるテーブルに対し、一度の INSERT 文で複数の行を挿入したい。

## 設定

このようなテーブルを作る。

| ID  |	NAME| AGE |
| --: | --- | --: | 


```sql:DDL
CREATE TABLE Students (
    id INT PRIMARY KEY,
    name VARCHAR(16),
    age INT
);
```

## INSERT するコード

### MySQL 等

```sql:MySQL等で複数行追加の例
INSERT INTO Students VALUES
    (1, 'Alice', 16),
    (2, 'Bob', 18),
    (3, 'Charlie', 15),
    (4, 'David', 23);
```

MySQL でも PostgreSQL でも SQL Server でもこれでできる。
が、この書き方は**Oracle DataBase ではできない**…

### Oracle Database

```sql:Oracleで複数行追加の例
INSERT ALL  -- ここに ALL がつく
INTO Students VALUES (1, 'Alice', 16)    -- 行末にカンマをつけないこと！
INTO Students VALUES (2, 'Bob', 18)      -- カンマをつけると、
INTO Students VALUES (3, 'Charlie', 15)  -- ORA-00928: missing SELECT keyword 
INTO Students VALUES (4, 'David', 23)    -- となります
SELECT * FROM DUAL;
```

1つずつ `INSERT INTO` するのとほぼ変わらないやん…（絶望）

この構文は、ある表から SELECT して別の表へ INSERT する時の書き方がベースになっているように見える。
ただし、今回は元の表が無いので、元の表を指定する部分は `SELECT * FROM DUAL` として省略している。
（`SELECT 1 FROM DUAL` とかにしても動く。何を SELECT するかはどうでもいいらしい）

逆に、この書き方は、**MySQL 等ではエラーとなる**。
「この書き方ならどの製品でも動く」という書き方はないらしい？

## 余談

MySQL等の書き方は、「1つのテーブルに複数の行を挿入」するものであるが、
Oracle Database の書き方は「テーブルを指定した INSERT を複数行う」というイメージ。
つまり、Oracle では異なる複数のテーブルに対して一度に INSERT することもできる。

```sql:2つの異なるテーブルにINSERT
-- DROP TABLE Students;
-- DROP TABLE Evaluations;

CREATE TABLE Students (
    id INT PRIMARY KEY,
    name VARCHAR(16),
    age INT
);

CREATE TABLE Evaluations (
    name VARCHAR(16),
    subject VARCHAR(16),
    score INT,
    PRIMARY KEY(name, subject)
);

INSERT ALL  -- Students と Evaluations へ INSERT
INTO Students VALUES (1, 'Alice', 16)
INTO Students VALUES (2, 'Bob', 18)
INTO Evaluations VALUES ('Alice', 'english', 30)
INTO Evaluations VALUES ('Alice', 'math', 60)
INTO Evaluations VALUES ('Bob', 'english', 40)
INTO Evaluations VALUES ('Bob', 'math', 80)
SELECT * FROM DUAL;
```

## 検証環境
```sh
$ mysql --version
mysql  Ver 8.0.26 for macos11.4 on arm64 (Homebrew)
$ psql --version
psql (PostgreSQL) 12.7
```
Oracle は LiveSQL を使用。
その他、SQL Server 15.0.2000 でも検証。
[Nuxt]optional chainingでちょっと複雑なAPI埋め込みするときにスッキリ書く

複雑なAPIだとフラットで返ってこないものも多いのではないでしょうか？
javascriptのオブジェクトを辿る時、
`aaa.bbb.ccc.ddd`としますが、途中の`ccc`の返りがnullならエラー。
でも分岐書くの結構辛い・・・
そんな時はoptional chainingですね。

他の言語ではあったりするけど、javascriptはまだ待ちの段階。
いち早く使うならプラグインいれてトランスパイル。

```
npm i -D @babel/plugin-proposal-optional-chaining
```

```js:nuxt.config.js
  build: {
    babel: {
      plugins: [
        '@babel/plugin-proposal-optional-chaining',
       ],
    },
  },
```

`aaa.bbb.ccc?.ddd`
これでいけ・・・
なんとtemplate内の埋め込みでは使えないではないですか・・・
scriptブロックでは使えるけど

vue2では難しいみたいで、vue3対応を待つしかなさそうです。
Nuxtのvue3はいつ・・・

methods経由かcomputedで対応もありですが、記述減らしたいのに増やしてどうする・・・
lodashで対応させるって記事があったのでとりあえずそれで対応するのが妥協かもですね・・・
SSHでWARNING: UNPROTECTED PRIVATE KEY FILE!になってAzure Vmに接続できん！

# Azure VmでビルドしたUbuntsにSSHでアクセスしようとしたらエラーが発生

```
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions for 'C:\\xxx\\xxx\xxx\\xx_key.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "C:\\xxx\\xxx\xxx\\xx_key.pem": bad permissions
azureuser@x0.xxx,xxx.x: Permission denied (publickey).
```

# ネットで調べたら、keyファイルのパーミッションが緩すぎる！って事らしい

しらんがな(*´Д｀)
linuxなら,chmodで済むんだけど、windowsだとややこしい(´;ω;｀)

#こちらのサイトで解決策があった

https://note.affi-sapo-sv.com/ssh-unprotected-key.php

ありがとうございます。

#簡単に手順だけ。。。

## アクセル許可の「継承の無効化」をする
ファイルのプロパティーを開く
![2021-07-28_00h28_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/dceea9c7-04e5-3c06-6813-8f12118f377c.png)

セキュリティータブの「詳細設定」をクリック
![2021-07-28_00h29_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/fa28c632-9cd3-5be7-068b-07e53c836815.png)

「継承の無効化」をクリック
![2021-07-28_00h31_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/c2948b2c-ca2a-400c-7b0d-3672e8b3895d.png)

なんか出たけど「OK」らしきヤツを選択しといた
![2021-07-28_00h33_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/54e5a1eb-3042-bddc-0513-cb74d9013528.png)

##今Windowsにログインしているユーザーにアクセス許可を付ける
「追加」をクリック
![2021-07-28_00h34_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/1570d58b-bbfd-ee3a-79a1-9f9e4d70fe3b.png)

「プリンシパルの選択」をクリック
![2021-07-28_00h36_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/aa36189e-fc55-ba17-b75c-b828ee57944e.png)

「詳細設定」をクリック
![2021-07-28_00h37_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/eb4ca1fb-f750-ae90-3be2-5d10dccc00ca.png)

「検索」をクリック
![2021-07-28_00h37_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/d50f7577-216a-fa18-2d99-2d378cc420b3.png)

検索結果から探すして選択して、「OK」をクリック
![2021-07-28_00h38_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/5fc54e10-1350-d3fd-7118-76f84935afe2.png)

「OK」をクリック
![2021-07-28_00h40_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/16553975-2f77-b6da-4392-cb6b4763dd5b.png)

「FULLコントロール」にチェックを付けて「OK」をクリック
![2021-07-28_00h42_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/45dc1625-e723-f665-7065-327e73dbba97.png)

不必要なアカウントを選択して「削除」をクリックすると、そのアクセス件が消える
![2021-07-28_00h43_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/a96a3153-b856-dd71-8d7b-6916a24ed16e.png)

さっき追加したユーザー以外は消して、「適用」後に「OK」をクリックする
![2021-07-28_00h45_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681950/8ffc22ff-1a95-dbc1-5b34-33191bf232e9.png)

でOK
vimでhtmlタグの自動補完をもっと使いやすく！

#面倒くさいタグの自動補完
デフォルトだと`</`を入力したあとに`<C-x><C-o>`でできるらしい。
ネットでhtmlタグの自動補完について調べるとこれのキーマップを設定するという記事が見つかります。
例えば以下のような設定です。

```
augroup MyXML
    autocmd!
    autocmd Filetype html inoremap <buffer> </ </<C-x><C-o>
augroup END
```

だけど、これだと物足りない。タグを補完したあとタグの中身を書き込めないので無駄にカーソル移動したり、意識して自分で閉じないといけない。これだと面倒くさいし、自分の場合閉じ忘れてしまうこともあります。

```
<div></|    補完➡    <div></div>|    注:縦棒はカーソル位置
これだとやりにくい！

<div></|    補完➡    <div>|</div>
こうしたい！
```

こんなときこの方法では少しやりずらい。そこで自分は以下のように改良してみました。
#改良版タグ補完
改良版⬇

```
autocmd Filetype html inoremap <buffer> </ </<C-x><C-o><ESC>F>a
```

`F>a`を後ろに追加しただけだけど、これだけでも結構楽になりました。
しかし、あともう少し欲しい。リッチなエディタみたいに、divタグ等の間に改行がほしい。

```
<div></|    補完➡    <div>|</div>    注:縦棒はカーソル位置
もう少しほしい！

<div></|    補完➡    <div>
                         |
                     </div>
こうしたい！
 
```

そこで自分は以下のような設定を追加しました。
###改良版タグ補完v2
改良版v2⬇

```
augroup MyXML
    autocmd!
    autocmd Filetype html inoremap <buffer> </ </<C-x><C-o><ESC>F>a<CR><ESC>O
augroup END
```

これでほぼ完成です。
自分の場合は上の設定に加えて、真ん中に改行ないバージョンとあるバージョンで使い分けたかったので、以下の設定も追加しました。

```
augroup MyXML
    autocmd!
    autocmd Filetype html inoremap <buffer> </<CR> </<C-x><C-o><ESC>F>a<CR><ESC>O
    autocmd Filetype html inoremap <buffer> </<Tab> </<C-x><C-o><ESC>F>a
augroup END
```

`</`入力したあと`<CR>`だと真ん中に改行、`<Tab>`だと改行なしにしました。

#参考サイト
https://babie.hatenablog.com/entry/20110130/1296347719
J-Quants入賞者プレゼン 質問回答

# はじめに
UKIです。
7月19日に開催されたJ-Quantsデータ分析コンペティション表彰式での入賞者プレゼンにて頂いた質問に回答します。

# 質疑応答にて回答済みの質問一覧
- XGBRを使われた理由を教えて頂きたいです。 (Lassoを使用していない理由)
- 「方向予測」の定義をもう一度教えて頂きたいです。 上がったものが、さらに上がることがトレンド だと思いますがいかがでしょうか。
- ニュース分析ではファンダメンタル分析チャレンジと異なり、買付タイミングが決算発表のタイミングではないですが、どのようにファンダメンタル分析のモデルを流用したのですか? 元々、任意のタイミングで予測できるモデルだったのでしょうか。
- 今後UKIさんが参加してみたいと思う株コンペのテーマはありますか？
- UKIさんは、hohetoさんと共に、仮想通貨でも活躍されていますが、株と仮想通貨のデータ分析の違いがあったら教えて頂きだいです。
- 7ページ目、CV不要の理由をもう一度お願いできれば嬉しいです。

# 頂いた残りの質問回答
**(1)非定常性に関して特徴量(ファクター)の有効性は局面によって変わると思いますが、構造変化によるものなのか単にオーバーフィットだったのかは区別できるとお考えですか？**
これは区別できると思います。ただしデータのみでの区別は不可能です。合理的な説明ができるかどうか人間による判断が必要で、多角的な観点から検証が必要になると思います。

**(2)ボラ予測に効くのはテクニカル系の特徴量、方向予測に効くのはファンダメンタルズ系の特徴量だったのでしょうか。**
一番効果のあった指標はその通りですが、例えばボラ予測に効くファンダメンタルズ指標もあります。これは時価総額や売上高（生値）などが挙げられます（＝小型株は総じてボラが高い傾向にある）。

**(3)財務データは、クロスセクションかタイムシリーズどちらの分析になるのでしょうか。**
財務データは基本的にクロスセクションでの分析となります。一方、Further Workのスライドで示した通り、来期予測などはタイムシリーズでも分析できる可能性があります。

**(4)ニュース分析をポートフォリオ構築の戦略に取り入れるとしたら、どのくらいの期間のデータが必要と思われますか？また、有効と思われますか？**
経験的な話になりますが、直近5年間のデータが必要です（それよりも長い期間は不要）。決算データと同じく有効だと思います（ニュース当日の終値ベースでは十分な説明力が生じ、翌日仕掛けでもそこそこの利幅が残る）。

**(5)「来期の決算を予想する」というのは、言い換えると 来期のProfit Marginを予想するというニュアンスでしょうか。**
決算において最も値動きへ影響する指標がProfit Marginですので、いったんProfit Marginをターゲットとおいて問題ありません。一方で、利益率を予測するよりもその構成要素である売上高、売上原価などを個別に予測して組み合わせるほうが理に適っていると思います。

**(6)何個くらいの特徴量を試しましたか？**
当初、2月初旬くらいに作ったモデルの特徴量は20くらいでした。このときはモデルの精度よりもモデル構造を重視していました。理論にマッチしたモデル構造が美しいと考えていたためです。3月に入って他の参加者のLBスコアの推移を見てみると「このモデルでは勝てないな」と思ったため、ガンガン特徴量を追加してなりふりかまわず精度を上げる方針に変更しました。最終的には200くらい試したと思います。

**(7)UKIさんの研究として「ボラ予測」「方向予測」を共に含んだ最強の特徴量を探索したりしているのでしょうか？**
私の研究は「実運用で利益を出すにはどうすればよいか」を考えています。当然特徴量の探索も必要となりますが、どうやって特徴量を探せばよいかその探索方法を確立することも重要です。また、「予測ができる」ことと「運用ができる」ことは異なります（予測モデルを作れても実運用まで至れない、また実運用に至っても途中で挫折する方が多いと思います）。実際の運用システムの構築手法も重要な研究テーマです。これらを含めてスライドでは「ファイナンスデータの分析および収益化のためのフレームワークの研究」と書きました。
この観点から付け加えますが、最強の特徴量の探索というのは実はあまり意味がないと考えています。そこそこの特徴量を5個くらい見つければそれがベストだと思います。

**(8)1位望月さんの発表から、どういった点が差になったと考えますか？**
今回のコンペは特徴量では差が付きにくいコンペだったと思います（特徴量追加すれば精度は上がるが、そのうち頭打ちになる）。最終的にはモデルの精度が差になったと考えています。ファイナンスデータへのランク学習適用のフレームワークについて、追加研究してみたいと思いました。

**(9)ATRと標準偏差を両方とも入れているのはなぜですか？**
標準偏差もターゲットとの相関が高いため、ATRと併用することでモデル精度が上がります。

**(10)実運用の投資の際と、今回のコンペで使用した特徴量にて大きな違いはありますか？**
かなり違うと思います。イベント的に価格を動かす特徴量と、普段の市場で説明力を持つ特徴量は異なる、ということです。
また特徴量に限らずモデルの話もすると、もしも実運用する場合は今回作ったモデルは絶対に使わないです。2、3個の指標を使った単純な組み合わせによるモデル（ルールベースモデル）に落とし込むと思います。

**(11)個人の投資にはデータ分析が必要と考えていることですが、今後激化した場合でも個人にも利益は残ると思いますか。**
これは間違いなく残ります。具体的に言うと、個人投資家の最大の武器はポジションを即時建てれることです。例えば、個人投資家と機関投資家が同じ銘柄を買い付けしようとした場合、個人投資家は寄り成りで一括でポジションを建てることができますが、機関投資家はそういうわけにはいきません。VWAPやMOCといった注文を使い、場合によっては複数日に渡ってポジションを作ります。
機関投資家はやられっぱなしで対策してこないのか？これはしてこないです。売買で利益を出す必要のない機関投資家というものも存在するのです。逆に言うと、このような観点からの戦略構築が重要となります。

**(12)日本株のトレードをされていると思いますが、米国株など外国株についても機械学習を用いた手法は有効だとお考えでしょうか。**
これは有効だと考えています。Numeraiという海外のファイナンスデータトーナメントでモデル構築したことがありますが、米国株はじめ外国株のほうが予測しやすいという印象を受けました（理由は不明です）。
pipenv実行時、「ValueError: Not a valid python path:」エラーが発生する

## 現象
pipenvによる仮想環境構築時、「ValueError: Not a valid python path:'C:/Users/%User%/Anaconda3/Scripts/python.exe'」というエラーが発生していました。
Anacondaはすでにアンインストールしており、指定されたパスに実行ファイルはありませんでした。

## 解決方法
レジストリにエラーが表示しているパスのデータが存在していたため、以下のように上位のキーの名前を変更しました。

```
HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\3.5\InstallPath
```
から

```
HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\_3.5\InstallPath
```
に変更

パスを参照しなくなったためか、エラーは解消されました。

## 参考
[pipenv環境作成時に「ValueError: Not a valid python path」が出てハマった](https://qiita.com/itsuneki/items/6fd7acb180662648fb99)
Unityでマルチプレイする方法

Unity間で通信する方法を調べたので調べたアセットについて記録します。

# マルチプレイ向け
## Netcode for GameObjects
* MLAPI(Mid level API) をベースに作成されたUnity公式アセット。
* WANを経由する場合、UnityのRelayサーバー(2021年12月3日現在β版)を利用することでNAT越えが可能。
* パッケージマネージャからインストール可能
* Unity Transport for Netcode for GameObjectsパッケージもパッケージマネージャからインストールする必要がある。
* Simulatorツールから遅延を設定することができ、テストに利用することができる。

https://github.com/wotakuro/NetcodeForGameObjects_UnitychanSample

### 簡易的な使い方の流れ（ローカルネットワークで利用する場合）
* NetworkManagerコンポーネントを配置し、NetworkTransportをUnityTransportに設定、ConnectionDataにIP,ポート番号を設定する。
* 同期させたいオブジェクトにNetworkObject,NetworkTransformをコンポーネントにアタッチする。
* NetworkManagerコンポーネントのPlayerにNetworkObjectを設定する。
* PlayerのコントローラースクリプトにはMonoBrhaviourではなくUnity.Netcode.NetworkBehaviourを継承し、if(this.IsOwner)を処理に追加して、自分の操作に対してのみ受け付けるようにする。
* サーバーのみ実行する処理をif(this.IsServer)に記述する。
* (任意)[Unity.NetCode.ServerRPC]を記述し、サーバーにクライアントの状態を伝えるメソッドを作成する。
* ゲーム開始後にNetworkManagerコンポーネントのStartHost(StartClient)を実行する。
※Animatorを同期させたい場合はNetworkAnimatorコンポーネントをアタッチする。
※サーバーではなく、クライアント側のトランスフォームを優先させて同期したい場合、Unity Transport for Netcode for GameObjectsパッケージのインポート画面のSampleからClientNetworkTransformをインポートし、NetworkTransformの代わりにアタッチする。この場合[Unity.NetCode.ServerRPC]は不要


### リレーサーバーを利用する場合
2021年12月3日時点ではβ版のため、無料で利用できます。（現状Max10クライアントまで接続可能）

* パッケージマネージャからRelayパッケージをインストールする。
* Unity ゲーミングサービス(https://unity.com/ja/solutions/gaming-services)にてRelay Activateを有効にする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1336886/f283ca03-c29f-b09d-b7cd-7245fac5d049.png)
* Relayサーバーへの接続スクリプトを配置（上記Unity黒河さんのリポジトリ参照）

※上記説明はクラウド版について記述、BuildSettings画面でDedicated Serverを選択してビルドすることでサーバーアプリケーションを作成することもできる。この場合はMAX10クライアントの制限はない。

## Photon

専用のPhotonサーバーを介して通信するため、NUTパンチの考慮は不要
利用者が多いので情報が手に入りやすい
Photon～って名前の用語が沢山あるので最初は戸惑うが、現時点ではPUN2が無難な選択
音声通信機能あり
無償版の"FREE"と有償版の"＋"がある
無料版はモバイル向けにビルドするにはProライセンスが必要
マッチメイキング対応で既存の部屋に参加したり、自分の部屋を作成したりできる。
転送量超過すると課金が発生するので注意


https://www.photonengine.com/en-US/Photon

### Photon Unity Networking 2 (PUN2)
推奨バージョン
### Photon Unity Networking  (PUN)
現在非推奨でUnity2020以降サポートなし

### Photon Server
サーバー側でロジックを組むことができるサービス
サーバー側にデータを保持できる
PUN*有償版より高価

### Photon Cloud
Photon Serverで動作するクラウド版
PUN*と同義

### Photon Bolt
ホストクライアント方式(P2P)
NAT超え考慮必要

### Photon Quantum
オンラインマルチプレイヤーゲームのための高性能決定論的ECS（エンティティコンポーネントシステム）フレームワーク
情報が少ないので説明省略


## Unet
公式アセットだが非推奨のアナウンスあり

## MLAPI(Mid level API) 
UNetの代替
無料
現在はUnity公式版に移行中
元々オープンソース個人で開発されていたネットワークゲーム用フレームワーク
1 つのクライアントがホストとして機能し、他のクライアントがそれに接続する、ホスト/リッスンサーバーモデル及び専用ゲームサーバーモデルに対応

https://docs-multiplayer.unity3d.com/docs/getting-started/about-mlapi

旧版

https://unitylist.com/p/1cx/MLAPI

## Mirror
オープンソースのネットワークアセット
非公式のUNETの後継ネットワークライブラリ
P2P

# その他

以下、Unity公式から引用

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1336886/020bb4bd-1623-1b59-a7d5-55ce4b4c0bd1.png)

https://blog.unity.com/ja/technology/choosing-the-right-netcode-for-your-game
Auth0のアクセストークンを検証する

## やりたいこと

Auth0でアクセストークンを取得した上でそれが適切なものなのか検証したい。
言語はJSもしくはTS


## 実装方針

アクセストークンの検証をするには公開されている証明書と署名を使って検証する。
もう少し具体的に書くとSHA256などのハッシュ関数からトークンのペイロードに含まれるMD(メッセージダイジェスト) を作成しそれが証明書と署名から作られたMDと一致するかを検証することで、トークンが改竄されたものでないことを確かめる。

## 調査

### 証明書の取得

この[やりとり](https://auth0.com/docs/tokens/json-web-tokens/json-web-key-sets)を見る限り `https://[your_domain].auth0.com/pem` で公開鍵を取得できる模様です。
もちろん[your_domain]の部分は自身のAuth0のコンソール画面から取得してください。

Auth0コンソール→Applications->APIS->Auth0 Management API

に記載されているはずです。

### 証明書の検証

公開鍵の証明書を用いた署名の検証をするのにいい方法ないかなと探っていると[AWSが手頃な記事](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html)を出していました。

`jsonwebtoken` というライブラリを利用している模様。Cognitoのトークンの検証のために出している記事の模様ですがこの際活用させていただきます。


## 実装

今回実装するに当たってフォルダ構成はこんな感じにしました。

```

verify-auth0-token
 L index.js
 L public.pem

```

先ほどのライブラリを活用するために `yarn add jsonwebtoken` もしくは `npm install jsonwebtoken` でこのライブラリをインストールしてください。
今回の場合はもちろん`cd verify-auth0-token`でディレクトリの移動をしてからインストールします。

先ほどの調査で取得した証明書はpublic.pemとして保存してます。

それでは index.js を記載していきます。

fs で pem ファイルを呼び込んでそれをライブラリの中に使ってトークンと一緒に突っ込みます。

```js

const jwt = require('jsonwebtoken');
const fs = require('fs');
const pem = fs.readFileSync('./public.pem')
// token = アクセストークン
const token = 'eyJhbGc...L9CcGw'
jwt.verify(token, pem, { algorithms: ['RS256'] }, function(err, decodedToken) {
    console.log(decodedToken)
});


```

あとはターミナルで実行するとコンソール上にトークンの中身が見れます。

```sh

node index.js

```

レスポンスはこんな感じでJSONで見れます。

　![スクリーンショット 2021-07-27 23.59.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274030/75baed21-f171-738f-d6c7-a232abed8851.png)

　実際にはトークンをAPIのリクエストで受け取ったり、証明書もバックエンドに保存しておいたり設計する必要がありますが、ひとまずこれでAuth0で公開鍵の証明書を用いた署名の検証方法を認識していただければ幸いです。

## 最後に

Youtubeチャンネルはじめてます！
エンジニアの姿は十人十色。
今後も色んなエンジニア像を捉えて、それを目指す人たちの参考になる動画を作っています。

https://youtu.be/KRTo7MlOd9w

あと、プログラミングもメンタで教えているので興味があったらみてください。

https://menta.work/plan/1734
【PHP】HTTPリクエストメソッドの判別方法

#環境
AWSのEC2インスタンス上に、Apacheと**PHP**をインストールし作業しました。
また、curlを用いて、コマンドラインから**HTTPリクエスト**をサーバーに送りました。
HTTPリクエストには**GET**やら**POST**やら**PUT**、**DELETE**といったメソッドがあり、
無知すぎてこれらを判別するのにかなり苦労しまして、今回ここにまとめておこうと思い立ったわけです。

#はじめに試した方法（失敗）
はじめに、 [$_GET](https://www.php.net/manual/ja/reserved.variables.get.php) と [$_POST](https://www.php.net/manual/ja/reserved.variables.post.php) を使ってHTTPリクエストメソッドを判別できないか、試してみました。

`$_GET` と `$_POST`はそれぞれ、HTTPリクエストメソッドのGETとPOSTによって渡されたパラメータを返します。

例えば、以下のようなコマンドでGETとPOSTをリクエストし、成功したとします。
このとき、`$_GET`と`＄＿POST`からは"apple"が返されます。

```
[GETするコマンド]
curl (サーバーのURL)/?name=apple
----------------
[POSTするコマンド]
curl -d {"name": "apple"} (サーバーのURL)
```


```php:index.php
$get_param = $_GET["name"];
//出力: $get_para => "apple"
----------------
$post_param = $_POST["name"];
//出力: $post_post => "apple"
```

この方法は、HTTPリクエスト時にパラメータが指定されていなければ、
受けたリクエストメソッドがGETなのかPOSTなのかを判別することができません。

さらに、`$_PUT`とか`$_DELETE`は**残念ながら存在していない**ようですので、GETとPOST以外のリクエストメソッドは当然判別することができません。

私はこいつらがメジャーなせいで、かなり悩まされました。
~~（そもそも、もしや世の中ではパラメータを受け取れることが最重要で、それが何のリクエストメソッドかは二の次なのか．．．？）~~

追記：そもそも、HTTPリクエストメソッドを判別する方法は後述の`$_SERVER`が適当であり、
`$_GET`や`$_POST`はパラメータを受け取るために使われるものになります。
（本記事に@tadsan様よりコメントを頂きました。詳細についてはコメントの方をご参照ください。）

#HTTPリクエストメソッドを判別する方法
①で悩み続けた私が、苦行の果てに発見した手法が`$_SERVER['REQUEST_METHOD']`を用いるもの。

まず、[$_SERVER](https://www.php.net/manual/ja/reserved.variables.server.php)というのは、 **サーバー情報および実行時の環境情報を取得する**ものだそうです。

そしてこの`$_SERVER`は、キーはめちゃくちゃたくさんある連想配列なのですが、
キーの中に先述の**`REQUSET_METHOD`**があり、指定するとHTTPリクエストメソッド名を返してくれます。

以下、例を挙げます。

```
[GETするコマンド]
curl (サーバーのURL)
----------------
[DELETEするコマンド]
curl -X DELETE (サーバーのURL)
```


```php:index.php
$method = $_SERVER["REQUEST_METHOD"];
//出力: $method => "GET"
----------------
$method = $_SERVER["REQUEST_METHOD"];
//出力: $method => "DELETE"
```

以上のように、GETやPOSTでパラメータを指定していなくても、
HTTPリクエストメソッドを判別することができます。

また、GETとPOST以外のリクエストメソッドの名前も返すことができるため、
PUTやDELETEなどのHTTPリクエストメソッドを判別することができます。

#おわりに
今回は、PHPでHTTPリクエストメソッドを判別する方法についてまとめました。
それぞれのパラメータを取得する方法は他にもたくさんありましたが、
それらは調べればすぐに出てきましたので、今回は割愛いたしました。

<br>
<br>
[Unity Student Planに加入する方法](https://qiita.com/bigsugarG/items/dc547cf2b0913dabf800)をまとめた記事が、ありがたいことに思ったよりもたくさん見られていて、驚き & 感謝です。
（ちょっと宣伝．．．😶）

それでは、最後まで読んでいただき、ありがとうございました！
また気が向いたら投稿します。('ω')ﾉｼ
UniTask 使用例を集める

```csharp

protected virtual async UniTask<SthResponse> _getAllResponseAsync(CancellationToken cancellationToken)
{
            if (_allResponse != null)
            {
                return _allResponse;
            }

            _allResponse = await GetAsync<SthResponse>("SthAPI/AllResponseApi", cancellationToken);
            _webApiRequester.SetMasterVersion(_allResponse.Version);
            return _allResponse;
}

 public async UniTask<TResponse> GetAsync<TResponse>(string path, CancellationToken cancellationToken)
            where TResponse : class
{
            return await Get<TResponse>(path).GetValue(cancellationToken);
}
```

 続く
Codeforces Global Round 15 B. Running for Gold 最強がいる場合の判定

https://codeforces.com/contest/1552/problem/B

1-indexedで説明します。

# 題意(意訳)
- n 人の人がいる。これらの人は過去に5回の試合に出ており、その順位が与えられる。順位はdistinct(同順はない)である。
- チャンピオンとは、3つ以上の試合において、他のどんな人よりも順位が強い(数値としては低い)人のことである。各試合の間に優劣はない(ポイントの高い試合、などはない)
- チャンピオンがいるならその人を述べよ(複数いるならどれでもいい)。いないならそれを述べよ
    - ※後述の通り、複数の候補が存在することはありません

# こう考えた 前提
まず、`(aがbに)勝つ`を`aはbより順位が強い試合が3つ以上ある`と定義します。

さて、問題のポイントは、`チャンピオンがいるなら、１人に定まる`です。なぜなら、チャンピオン$a$がいるとするなら、その人は3つ以上の試合の順位がほかのすべての人より強いです。もしも、他のチャンピオン$b$がいるとすると、その人は$a$に勝てる試合が3つ以上あることになりますが、これは前提に反します。

ただし、サンプルにある通り、`チャンピオンがいない場合もある`です。

# こう考えた STEP1 チャンピオン候補を決める
STEP1では、チャンピオンがいると仮定します。(<font color="red">この仮定で処理を進めるのがとても重要！</font>)

まず、人$1$をチャンピオンと仮定して、人$2,3,..,n$と比較します。もし、すべてに勝ったなら、人$1$がチャンピオンです。もし、人$k$に負けたとすると、人$k$がチャンピオンかもしれないので、人$k$を基準にして$人k+1, k+2,..n$と比較します。これを繰り返します。$O(N)$です。

こうして最後に残った(最後まで処理した)チャンピオン候補kは真にチャンピオンとは限りません.
$k$よりも前の人に負けることがあるからです。ただし、チャンピオンがいるとするならば、最後に残ったチャンピオン$k$が答えです。なぜなら、前提の通り、チャンピオンはほかの人に負けるはずがないので、どういう順序(例えばソートされても)で上記の施行をしても絶対に最後まで残ります。

# こう考えた STEP2 チャンピオンかを確かめる
そこで、チャンピオンかを判定します。候補$k$を$k$を除く$1,2,..,n$と愚直に比較します。すべてに勝てればチャンピオンです。$O(N)$です。

サンプル2の通り、途中で負けることがありますが、この場合は`-1(チャンピオンはいない)`です。他に本当のチャンピオンがいることはありません。STEP1後段の通り、それが存在するなら、$k$はそれに負けています。

# 実装
結果、$O(N)$で解けました。

私はSTEP1がうまく思い浮かばず、トーナメント形式でSTEP1を処理しました。(2人ずつ取っていき、買ったほうだけ次のリストに残す方法です)。

```Python
from copy import deepcopy
def do():
    n = int(input())
    dat = []
    for i in range(n):
        l = map(int, input().split())
        l = list(l)
        l.append(i)
        dat.append(l)
    odat = deepcopy(dat)
    
    # STEP1: 
    while len(dat) > 1:
        newdat = []
        for i in range(0, len(dat), 2):
            ls = dat[i:i+2]
            if len(ls) == 1:
                newdat.append(ls[0])
                continue
            a = ls[0]
            b = ls[1]
            cnt = 0
            for i in range(5):
                if a[i] < b[i]:
                    cnt += 1
            if cnt >= 3:
                newdat.append(ls[0])
            else:
                newdat.append(ls[1])
        dat = newdat

    # STEP2
    candidate = dat[0]
    for x in odat:
        cnt = 0
        for i in range(5):
            if candidate[i] <= x[i]:
                cnt += 1
        if cnt >= 3:
            continue
        print("-1")
        return
    print(candidate[5] + 1)

q = int(input())
for _ in range(q): do()
```
https://codeforces.com/contest/1552/submission/123939428
Docker起動時に Fatal Error Failed to ping backend API という警告が出た場合の対処法

![スクリーンショット 2021-08-18 9.43.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508002/512ce2d4-1208-17c2-577d-620041f7ea2a.png)


macでDocker起動時に

```
Fatal Error
Failed to ping backend API
```

という警告のウィンドウが出た場合の対処法です。

- `Reset Docker to factory defaults`
- `Diagnose & Feedback`
- `Exit`

この3つの選択肢がありますが、どれを押しても反応しない現象が発生しています。

## 環境

- macOS Big Sur 11.3.1
- Docker Desktop 3.5.2

## 対処法

```
$ killall Docker && cd /Applications;open -a Docker;cd ~
```

まずDockerのプロセスを強制終了させます。
そしてApplicationsフォルダから改めてDockerを起動します。

こちらのissueで詳しく議論されています。

https://github.com/docker/for-mac/issues/5037

こちら頻繁に発生する現象ですので、このissue内でも紹介されているように `.zshrc` 等に以下の記述を追加して、コマンドをエイリアスとして登録すると良さそうです。

```
alias rdocker="killall Docker && cd /Applications;open -a Docker;cd ~"
```

## 参考

※2021年8月3日追記

@y-vectorfield さんに、コメントで別の対処法を教えていただきました。
こちらのやり方も良さそうなので、紹介させていただきます。

https://qiita.com/y-vectorfield/items/09ab4295322b321561c7
Progateで作ったWebアプリをDjangoで作ってみる2！ Part1 -初期設定編-

# 目標物の確認

ProgateのNode.jsコースで作ったブログアプリと同じものをDjangoで作ってみます。

Djangoでのアプリ開発の一連の流れを整理するために記していきます。

**完成イメージ**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471633/147877a6-1b3a-25e2-7956-720596125802.png)





#初期設定
まずは初期設定です。

プロジェクトを作成して、アプリ（blogapp）を作成します。

```console
> django-admin startproject blogapp
> cd blogapp
> python manage.py startapp blog
```

「templates」ディレクトリと「static」ディレクトリを作成して、さらにそれぞれの下層に「blog」ディレクトリを作成します（☆1）。

「blog」ディレクトリ構造は、今の段階でこんな感じです。

```console
blog
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│   └── __init__.py
├── models.py
├── static # ☆1
│   └── blog # ☆1
├── templates # ☆1
│   └── blog # ☆1
├── tests.py
├── urls.py
└── views.py
```

**setting.py**の``INSTALLED_APPS``にアプリ名（``blog``）を登録します（☆2）。

```blogapp/blogapp/setting.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog', #☆2
]
```

プロジェクトの**urls.py**ファイルからアプリの**urls.py**ファイルを呼び出すためのコードを書きます（☆3）。

```python:blogapp/blogapp/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('blog.urls')) #☆3
]
```

トップ画面を作るところまでやっていきます。アプリの**urls.py**にコードを追加します。

アプリの**urls.py**に最低限のコードを書かないとマイグレーションを実行したときにエラーが出てしまいます。

なので、トップページだけ作ります。

namespace（``app_name``）も設定しておきます。

```python:blogapp/blog/urls.py
from django.urls import path
from .views import BlogTop

app_name = 'blog'

urlpatterns = [
    path('', BlogTop.as_view(), name='top'), 

]
```

トップページの表示はTemplateViewで対応します（☆4）。

```python:blogapp/blog/views.py
from django.shortcuts import render
from django.views.generic import TemplateView

class BlogTop(TemplateView): #☆4
    # top.htmlをレンダリング
    template_name = 'blog/top.html'
```

トップページはDjangoのタグで整えます（☆5）。

```top.html
{% load static %} <!--☆5-->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>BLOG</title>
    <link rel="stylesheet" href="{% static 'blog/style.css' %}"> <!--☆5-->
  </head>
  <body>
    <div class="top">
      <div class="wrapper">
        <div class="content">
          <h2>わんこの学びブログ</h2>
          <h1><img src="{% static 'blog/top-logo.svg' %}" alt=""></h1> <!--☆5-->
          <p>プログラミングに関する雑学ブログ。<br>だれかに教えたくなる豆知識をお届けします。</p>
          <a class="btn" href="{% url 'blog:list' %}">読みはじめる</a> <!--☆5-->
        </div>
        <img class="image" src="{% static 'blog/top.svg' %}" alt=""> <!--☆5-->
      </div>
    </div>
  </body>
</html>
```

**models.py**はまだ作成していませんが、Djangoがデフォルトで準備しているUserテーブルを作成するため、マイグレーションしておきます。

```console
> python manage.py makemigrations
> python manage.py migrate
```

これで初期設定は完了しました。

トップページも表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471633/1eabe1fa-d083-7fe7-9584-e48b4bb54a24.png)
each文で表示している記事を、ボタンを押して非表示にする方法

タイトルの通り、Rubyのeach文で表示している記事を、右上につけた×ボタン（アイコン）を押下して非表示にする方法を紹介します。

#Point① document.getElementsByClassNameで要素を取得する
JavaScriptで対象となる要素を取得する時は
document.getElementById("id名")や
document.getElementsByClassName("class名")などを使いますが、
今回はRubyのeach文で表示させた要素になるため、複数のid名（またはclass名）が存在することになります。
idはhtml上に１つしか存在させはいけないルールがあるため、もしこちらを使うと１番最初の要素だけに機能が実装されます（経験済み:joy:）
class名なら複数存在しても全ての要素に適用できるため、document.getElementsByClassName("class名")を使用しましょう。
以下Rubyの参考コードです。（実際に開発中のものをわかりやすいように書き換えているので、あくまでも参考程度に。。。）

```ruby:index.rb
<% @articles.each do |article| %>
  <div class="hide_area">
    <div>
      <i class="hide_btn"></i>
    </div>
    <%= image_tag article.image.variant(resize: "400x400") %>
    <div>
      タイトル　：　<%= result.article.title %>
    </div>
    <div>
      本文 ： <%= result.article.article_text %>
    </div>
  </div>
<% end %>
```

#Point② class名に添字を指定して取得する
単純にdocument.getElementsByClassName("class名")では要素を取得できません。
以下のようにfor文でclassの数分（かずぶん）繰り返し処理をして、class名に添字を指定します。

```JavaScript:hide_article.js
const hide_article = () => {
  const hide_btn = document.getElementsByClassName('hide_btn');
  const hide_area = document.getElementsByClassName('hide_area');

  for (let i = 0; i < hide_btn.length; i++) {
    hide_btn[i].addEventListener('click', () => {
      hide_area[i].style.display = "none";
    }, false);
  };
};

window.addEventListener('load', hide_article);
```

以上です。
最後まで読んでいただきありがとうございます！
間違いなどありましたらぜひご指摘ください。
AnyDeskでリモートPC操作中はホストPCのIMEがONにならないようにAutoHotkeyを使って制御する


## 概要

ここの文章では、操作する側のパソコンを[ホストPC]、操作される側のパソコンを[リモートPC]とします。

無償のリモートソフトのTeamViewerでリモートPCを操作中に、全角を入力しようと全角半角を押してIMEをONにしようとすると、ホストPCでもIMEがONになるため、リモートPCで思った通りに入力ができなくてイライラした事はありますか？

ここでは私の解決方法を紹介したいと思います。それは「ホストPCがAnyDeskを操作中にIMEがONになったら、IMEをOFFにする」です。それを何で実現するかは色々あるのですが、私の場合はAutoHotkeyを使用しました。

ホストPCにAutoHotkeyをインストール後、次のスクリプトに適当な名前(ImeOffAnyDesk.ahkなど)を付けて実行してください。後は通常通り接続してリモートPCを操作してください。リモートPCでIMEをONにしようとして全角キーを押すと、リモートPCだけIMEがONの状態になると思います。

欠点といえばAnyDeskでリモートPCを操作中であるないに関わらずIMEがOFFになるので、AnyDeskの設定画面などで全角が打てない事でしょうか。その時はタスクトレイに入っているこのスクリプトのアイコンを右クリックしてサスペンドするか、終了させてください。

以上です。

## スクリプト

```ImeOffAnyDesk.ahk
; IMEがONかOFFか取得する
; @see https://morakana.hatenadiary.org/entry/20080213/1202876561
; @return int
getImeStatus() {
   WinGet, vcurrentwindow, ID, A
   vIMEstate := DllCall("user32.dll\SendMessageA", "UInt", DllCall("imm32.dll\ImmGetDefaultIMEWnd", "Uint", vcurrentwindow), "UInt", 0x0283, "Int", 0x0005, "Int", 0)
   return vIMEstate
}

; imeをON、OFFする
setImeStatus(status) {
   WinGet, vcurrentwindow, ID, A
   DllCall("user32.dll\SendMessageA", "UInt", DllCall("imm32.dll\ImmGetDefaultIMEWnd", "Uint", vcurrentwindow), "UInt", 0x0283, "Int", 0x0006, "Int", status)
}

While(1)
{
	; 200ミリ秒毎にチェックをする
	Sleep 200

    ; AnyDeskを操作中でない時は何もしない
	if ! WinActive("ahk_exe AnyDesk.exe")
	{
		continue
	}

	; IMEがONだったらIMEをOFFにする
	if (getImeStatus())
	{
		setImeStatus(0)
	}
}
```
【UiPath】CSVファイルを出力する（Bom無し・改行コードLF等）

# はじめに

この投稿は、RPAツール「UiPath」の 実装例 の記事です。

UiPathのコミュニティ「UiPath Friends」が企画する「UiPathブログ発信チャレンジ2021サマー」の 27日目の投稿でもあります。

企画の内容は [**こちら**](https://note.com/shumpei_w/n/n651cbdbec4e8) 。カレンダーのURLは [**こちら**](http://u0u1.net/sUwZ) です。

https://twitter.com/ShumpeiWatanabe/status/1405168150736359427

# 標準アクティビティでCSVファイルを作成すると

UiPathでCSVファイルを作成する場合は、通常「CSVに書き込み（WriteCSV）」アクティビティ を使用すると思います。

https://docs.uipath.com/activities/lang-ja/docs/write-csv-file

このアクティビティでは以下のように「エンコード／ヘッダー追加／区切り文字」オプションを指定してCSVファイルを作成することが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/67f24280-cc8b-50ac-c17f-c9ecf5a4b13b.png)

ここで問題が３つ発生します。

```
　問題1）値をダブル​クォーテーションで囲めない
　問題2）改行コードがCrlf固定で変更できない
　問題3）Bom付きファイルになってしまう
```

1番目は「値として、カンマが入る可能性がある文字列」を扱う際に、使用したい内容です。（ダブル​クォーテーションで囲めば、カンマは区切り文字にならない）
2番目と3番目は特に「Linux系のシステム」にCSVファイルを取り込む際には必要になることがあります。

残念ながら、上記の問題は標準アクティビティでは、現状解決できません。


# InvokeCodeでCSVファイルを作成する

上記の問題は、標準アクティビティではなく「.NET」で対応すれば解決できます。
具体的には以下のようなコードを作成し、実行します。

``` VB
'// InvokeCodeに書く内容

Console.WriteLine(Datetime.Now.ToString & " [CSV出力] start " & filePath)

'Dim sw As New System.IO.StreamWriter(filePath, False, System.Text.Encoding.UTF8)'// BomありUTF8
Dim sw As New System.IO.StreamWriter(filePath, False) '// BomなしUTF8
Dim wk As String

'// ヘッダー行の出力
For i As Integer = 0 To dt_Output.Columns.Count - 1
	wk = dt_Output.Columns(i).ColumnName
	If dt_Output.Columns.Count-1 > i Then
		wk = wk & ","c
	End If
	sw.Write(wk)
Next
'sw.Write(Environment.NewLine)
sw.Write(ControlChars.Lf) '// 改行コード：LF指定

'// データ行の出力
For Each row As datarow In dt_Output.Rows
	For i As Integer = 0 To dt_Output.Columns.Count - 1
		'// ダブルクォーテーションをシングルクォーテーションに変換（エスケープ）し
		wk = row(dt_Output.Columns(i).ColumnName).ToString.Replace(Chr(34), "'")
		'// ダブルクォーテーション（Chr(34)）で囲む
		wk = Chr(34) & wk & Chr(34)
		If dt_Output.Columns.Count-1 > i Then
			wk = wk & ","c
		End If
		sw.Write(wk)
	Next	
	'sw.Write(Environment.NewLine)
	sw.Write(ControlChars.Lf) '// 改行コード：LF指定
Next

sw.Close
sw = Nothing
Console.WriteLine(Datetime.Now.ToString & " [CSV出力] end")
```

InvokeCodeに設定した様子
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/4bcb0233-68c2-e980-d551-085fd4d9d78e.png)

InvokeCodeの引数
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/f81dee80-e1f8-1d6d-d949-70b6a8c8ed7a.png)
実際に実行して、作成されたファイルを見てみると、以下のように、改行コードは「LF」で「BOM無し」で、値は「ダブルクォーテーション」で区切られています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/742b9ea2-b346-8e58-d7a6-9d979a3de50b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/044f44d8-3010-e196-a6bf-c048f295141f.png)

# 終わりに

いかがでしたでしょうか？実装の参考になれば幸いです。
この記事が参考になったら、 LGTMをお願いします。閲覧ありがとうございました。
pingで回線/通信速度の計測

## 概要

pingでおおよその通信速度を調べる方法です。
インターネットVPN越しの遠く離れた２拠点間の通信速度を計測しました。

## 方法

### １.パケットサイズの大きいpingを飛ばす

```
ping -l 61440 192.168.11.11

192.168.11.11 に ping を送信しています 61440 バイトのデータ:
192.168.11.11 からの応答: バイト数 =61440 時間 =30ms TTL=255
192.168.11.11 からの応答: バイト数 =61440 時間 =30ms TTL=255
192.168.11.11 からの応答: バイト数 =61440 時間 =29ms TTL=255
192.168.11.11 からの応答: バイト数 =61440 時間 =31ms TTL=255
```

### ２.計算

60キロバイトのパケットが往復した時間(応答時間の平均の30ms)から、１秒あたりの転送速度は

```
60(KB) * 2(往復) / 0.030(秒) = 4000KB/s
```

次に単位を回線速度の一般的な単位のMbpsにする。
* １バイトは８ビットなので８倍
* キロをメガにするために1024で除算

```
4000(KB/s) * 8 / 1024 = 31.25Mbps
```

## 実際に転送した時の画像

4.14メガバイトパーセックなので33.12Mbsです。
pingで出した31.25Mbpsに近いですね。
インターネットVPN越しの名古屋から札幌へのコピーです。
![ExTT4k3UYAEeyMo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1765459/91f30d82-e37b-f5d4-99c4-7188c2f8a83e.jpeg)

## Twitterで頂戴したご意見

どこから突っ込んだらいいのか分からないぐらい突っ込みどころが多いそうです。
何が問題なのかは教えて頂けませんでした…エンジニアの世界は厳しい…
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1765459/0481e746-0667-be2c-1e79-f8e4bf96f1a1.png)

こういう建設的な意見をいただけるのはありがたいですね。0.8を掛けるといい感じになりそう。

https://twitter.com/JUNKOBAYASHIHoS/status/1374989024289382400?s=20

フラグメントフリー内に収まるため、遅延が一切考慮されていないというご指摘。やはり0.8は掛けた方がいいですね。

https://twitter.com/fugafugaOnline/status/1420023551004917773?s=20


## 一言

疎通監視をするなら、フリーのSNMPツール[TWSNMP](https://www.itbook.info/network/nwope13.html)がオススメです。