OmniAICreator/Qiita-1.07M huggingface dataset:
contentEdiableな要素でのUndoの注意点

## モチベーション

忘備録です。

ブラウザやelectronで、`contentEdiable=true`な要素を使って文章編集をする場合、windows環境では、Undo/Redoに関するショートカットキーを入力すると、次のことが起こります。

- 文字入力時にpreventDefaultせず、デフォルトの動作でDOMに文字入力宇した場合のみ、ブラウザの持つデフォルトのUndo履歴に残る。これはショートカットキー(windowsなら`Ctrl+z`)でUndoできる。
- 文字入力時にpreventDefaultし、独自でDOM編集して文字入力した場合は、ブラウザデフォルトのUndo履歴に残らない。**ショートカットキーでUndoした場合にはスキップされる。**
- IME入力モードの場合は、原則preventDefaultできない。

リッチテキストエディタを作っており、一部で独自でDOM操作する必要があったので、Undo/Redoも自前で実装していました。そのため、半角入力に関してはブラウザ標準のUndo履歴が残っておらず、ブラウザが勝手にUndoすることはありませんでした。一方で、三番目の問題があり、IMEだけはブラウザ標準のUndo履歴に編集履歴が残っており、ショートカットキーなどによってブラウザが勝手にUndoすることがありました。それに気づくまでは、原因不明の挙動として随分悩みました。。。。

## 例

例として、次のような空のdivに、

```html
<div contentEditable="true"></div>
```

カーソルを合わせて、次の手順で文字を入力します、

1. IMEモードで`あああ`と入力
1. 半角英数モードで`aaa`と入力。ただし、keydownでpreventDefault()し、プログラム上から文字`a`をDOMのTextNodeに3回insertする。
1. IMEモードで`いいい`と入力

こうすると、`あああ`と`いいい`の操作だけがブラウザの標準Undo履歴に残っています。ここから、`Ctrl+z`を二回押してUndoすると、`aaa`の編集はスキップされて、次のようになります。

```html
<div contentEditable="true">aaa</div>
```

やっかいですね。

## 対策

独自DOM操作する場合は、Undo/Redoも独自で実装すると思います。その時忘れずに、Undo/RedoのデフォルトのショートカットキーもpreventDefaultしましょう。windowsの場合は、次のキーをpreventDefault()すればよいです。

- Undo : `Ctrl+z`
- Redo：`Ctrl+Shift+z`および`Ctrl+y`

Redoのキーが二種類挙げてありますが、どちらが有効か(もしくはその両方が有効か)はブラウザに依存します。

## 最後に

contentEditableに関しては、そもそもブラウザがどこまでを請け負ってくれるのかクリアでないので、結局は全てをpreventDefaultしてしまった方が楽な気がします。文字入力から全てのDOM操作や独自Undo実装をやるなら、そもそもなぜcontentEditable使うんだという気もするのですが、***編集カ所にカーソル(キャレット)を表示できる***、この一点に尽きるんですよね。カーソルさえ表示できれば、contntEditableなんて動作の曖昧なものを使わずに済むのに、と思います。。。

どなたかcontntEditable=falseでもカーソルを表示できる方法を知っていたら教えてください。
ディープラーニングが苦手な問題についての仮説

## 概要

教師データにノイズが多い問題は、ディープラーニングは苦手なのでは？

## 教師データにノイズが多い問題

株価予測のように、教師データにノイズが多い問題は、ディープラーニングは苦手なのでは？

これは、人間が苦手な問題でもある。
麻雀、ギャンブル、株価などは、統計の知識を使わずに直感的に判断すると認知バイアスにやられて判断を間違えやすい。

こういう問題は古典的なやり方をしたほうが良いかもしれない。
Apache BeamのAvroCoderの話


# AvroCoderとは
データのシリアライズ・デシリアライズにAvro形式を使う、Beam組み込みのcoderです。
ソースコードは[ここに](https://github.com/apache/beam/blob/89fbfbbb4a1e579da2c4c7a1da83d518658c8482/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/AvroCoder.java)、javadocは[ここに](https://beam.apache.org/releases/javadoc/2.15.0/org/apache/beam/sdk/coders/AvroCoder.html)あります。

# Coderとは
[Beamがデータのシリアライズ・デシリアライズに使うクラスです](https://qiita.com/kurtosis/items/23d3c46deb6bf4455d18)

# Avroとは
シリアライズのフォーマット（と周辺のエコシステム）です。
[reflect](https://avro.apache.org/docs/1.7.6/api/java/org/apache/avro/reflect/package-summary.html)という仕組みで、Javaのクラスからスキーマを作成することも出来ます[（例）](https://stackoverflow.com/questions/11866466/using-apache-avro-reflect)。

# どうやって使うの

coder指定したいクラスに、下みたいにアノテーション付ければ良いらしいです。
なお、引数なしのコンストラクタが必要です。

```
 @DefaultCoder(AvroCoder.class)
 public class MyCustomElement {
     ...
 }
 
```

また、Avroのスキーマを明示的に定義してcoderを作ることも[出来ます](https://beam.apache.org/releases/javadoc/2.15.0/org/apache/beam/sdk/coders/AvroCoder.html#of-java.lang.Class-org.apache.avro.Schema-)。
（この場合は、アノテーションではなく[CoderRegistryで登録](https://beam.apache.org/documentation/programming-guide/#default-coders-and-the-coderregistry)？）


# AvroCoderの何がいいの

* 組み込みのcoderなのですぐに使える
* ジェネリクスなので任意のクラスに使える
 * 引数なしのコンストラクタが必要、static/transietなフィールドは含まれないなどの制限はある
* deterministicなcoderになりうる
 * （ならない場合もあります）
 * SerializableCoderやMapCoderはdeterministicにならない


# deterministic？
同じオブジェクトが、どこでもいつでも同じエンコーディングを持つかを示す、[coderの性質です](https://qiita.com/kurtosis/items/23d3c46deb6bf4455d18#deterministic)。

GroupByやDynamic Destinationはdeterministicなcoderを必要とします。


# AvroCoderとdeterministic
AvroCoderがdeterministicかどうかは、シリアライズ対象のクラスによって決まり、[ここらへん](https://github.com/apache/beam/blob/89fbfbbb4a1e579da2c4c7a1da83d518658c8482/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/AvroCoder.java#L351)で定義されています。

Avroのデータ型で言うと、下のような感じです。

* deterministic
 * Avroの組み込み型（boolean,int,long,float,doubles,bytes）
 * Enum
* deterministicでない
 * Fixed（固定長のバイナリデータ）
* 内容次第
 * Map,Record,Array,Union
 * String（※）

動的にスキーマ作る時のJavaの型とAvroの型の対応は、[reflectのドキュメント](https://avro.apache.org/docs/1.7.6/api/java/org/apache/avro/reflect/package-summary.html)にあります。
判定面倒なので、verifyDeterministicメソッド呼んで確認するのもいいかもしれません。

※ StringやURI、BigDecimalなどが[ホワイトリスト](https://github.com/apache/beam/blob/89fbfbbb4a1e579da2c4c7a1da83d518658c8482/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/AvroCoder.java#L386)で指定されており、その他（Stringableアノテーションで指定する）のクラスはdeterministicではありません
GraalVM 入門まとめ

次の仕事での開発をGraalVMで行うとのことだったので勉強がてら纏めてみました
メモのような形式なのでご容赦ください

## Why GraalVM??

>GraalVM offers a comprehensive ecosystem supporting a large set of languages (Java and other JVM-based languages, JavaScript, Ruby, Python, R, and C/C++ and other LLVM-based languages) and running them in different deployment scenarios (OpenJDK, Node.js, Oracle Database, or standalone). This page provides an overview of different scenarios in which GraalVM can make a difference for your applications. Some of versatile GraalVM capabilities, that might be missing on this page are thoroughly summarized and disclosed in Top 10 Things To Do With GraalVM blog post.

(GraalVM公式より　https://www.graalvm.org/docs/why-graal/)

GraalVMとはJVMの技術を利用して作成されたOracle製の多言語対応の仮想マシンです。
通常JVMってJavaやkotlin,Scalaを動かすものですがGraalVMはJavaScriptやRuby,Pythonといった言語にも対応しています。

同一のマシン上で異なる複数の言語を実行でき、複数の言語のコードが混在したプログラムを実行できます。

Twitter社でも採用されているようですね。


## どんな特徴があるの？

- Javeの実行速度の高速化

- 複数言語の対応
  - 複数の言語を対応していることにより相互のAPIを異なる言語で実行ができるようになります。各言語の得意分野を活かしたアプリケーション開発ができるようになる

- java microserviceフレームワーク(Quarkus、Micronaut、Helidon)で動作する
  - https://www.graalvm.org/docs/why-graal/#for-microservices-frameworks

- 新しい言語の開発ができる

長文になってしまうので細かい部分は割愛させて頂きます。


## GraalVMのinstall

1, Oracle Technology NetworkからGraalVMをダウンロード
https://www.oracle.com/technetwork/graalvm/downloads/index.html

oracleのpage移動するのでそのpageから`Oracle GraalVM Enterprise Edition based on JDK8 for macOS (19.3.1).`を選択。
※ Oracelにアカウント登録していない場合はアカウント登録を求められます

2, downloadした`tar.gz`を好きな位置に配置
配置した場所で

```
$ tar -xvf archive.tar.gz
```

4, PATHの設定

```
$ export PATH=<path to GraalVM>/Contents/Home/bin:$PATH

$ echo $PATH
graalvmが表示されていれば成功

$ export JAVA_HOME=<path to GraalVM>/Contents/Home
```

以上です。

バージョンの確認をしてみましょう

```
$ java -version
java version "1.8.0_241"
Java(TM) SE Runtime Environment (build 1.8.0_241-b07)
Java HotSpot(TM) 64-Bit GraalVM EE 19.3.1 (build 25.241-b07-jvmci-19.3-b07, mixed mode)

$ node -v
v12.14.0

$ lli --version
LLVM (GraalVM EE Native 19.3.1)
```

これでGraalVMの動作環境ができました。
次回からkotlinでGraalVMを使用してプログラムを実行していきます

## 追記
Docker Hubに公式imageがあるようですね
https://hub.docker.com/r/oracle/graalvm-ce/

こちらの方が圧倒的に楽なのでこちらでやっていこうと思います

```
docker pull oracle/graalvm-ce:19.3.1

docker run -it oracle/graalvm-ce:19.3.1 bash
```
初学者によるプログラミングMemo　#21 順列

#はじめに
今回は順列のお話です
Twitterで問題が回ってきたので解いてみました
Rails関係なくても書いている下記はすでに決まり文句ともなりました
なお、本記述はMacにおいて、Railsでの開発を前提としています
また、まだまだひよっこですので、不備等ございましたらご指摘いただけると幸いです
*例によって、問題の解釈を間違えていましたので、全体的に修正をいたしました
最初にご覧いただいた５０名ほどのかた、大変失礼いたしました

#目次
- 順列とは
- 問題を解いてみる

##順列とは
あるn個のものの中から、k個を選び、順番をつけて並べられたもののことを言います
「組み合わせ」とは区別されており、「組み合わせ」は順番は関係ありません
実際に順列をみてみましょう

ここに、1,2,3のトランプが一枚ずつあります
このトランプの並べ方は何通りあるでしょう
…と聞かれたとします

そうすると

```.rb
# 1,2,3
# 1,3,2
# 2,1,3
# 2,3,1
# 3,1,2
# 3,2,1
```
この6通りが挙げられます
このように、順番が違えば、それぞれを違うものとみなすことが順列の定義です

##問題を解いてみる
Twitterで、以下のような問題が回ってきました

![sample_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522204/460c5f0d-4b80-03f8-f22d-94f0a3442e9d.png)

＊３つの分数を足した結果が１になると言う数式
問題：
上記の数式の□(四角)のなかに、1~9までの文字を一文字ずつ入れて、等式を完成させなさい

わかりにくかったらすみません
まず、それぞれの四角を区別します

![sample_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522204/b886d461-89b9-f58e-9f74-88949fa73389.png)

このようにして、a~iのなかにそれぞれ数字を当てはめていきます
まずは1~9が入った配列を作りましょう

＊bc,ef,hiは共に二桁の整数です
私は解くときにここを間違えていました

```.rb
array =[]
1.upto(9) do |i|
  array << i
end
```
これがいいか

```.rb
array = [1,2,3,4,5,6,7,8,9]
```

これがいいかわかりませんが、どっちも結果は同じです
下の方が冗長でなくていいですが、応用はききにくいです（分数が倍になってしまったら、その分手打ちしないといけない）

そして、先ほどのa~iのなかに数字を入れていきます
a~iのなかに数字を入れていくには順番が大事ですよね
なので、ここで順列を使います

```.rb
array =[]
1.upto(9) do |i|
  array << i
end

pat = array.permutation.to_a
```
permutationメソッドが出てきました
これが順列を作り出してくれます
[公式リファレンス](https://docs.ruby-lang.org/ja/latest/method/Array/i/permutation.html)を置いておきます

これでpatのなかに、全通りの順列が入りました
ちなみに362,880通りです（9の階乗）
この中から単純に数式に当てはめて解きましょう

```.rb
array =[]
1.upto(9) do |i|
  array << i
end

pat = array.permutation.to_a
ans = []
pat.each do |i|
# 間違っていましたので訂正いたします　コメント欄参照
  x = (i[0].quo(i[1]*10 + i[2])) + (i[3].quo(i[4]*10 + i[5])) + (i[6].quo(i[7]*10 + i[8]))
  if x == 1
    ans << i
  end
end

p ans
# => [[5, 3, 4, 7, 6, 8, 9, 1, 2], [5, 3, 4, 9, 1, 2, 7, 6, 8], [7, 6, 8, 5, 3, 4, 9, 1, 2], 
#     [7, 6, 8, 9, 1, 2, 5, 3, 4], [9, 1, 2, 5, 3, 4, 7, 6, 8], [9, 1, 2, 7, 6, 8, 5, 3, 4]]
```
~~lengthつけないと、127,584通り結果が返されるので注意してください
当てはまる順列は127,584通りあります
確率にすると30％弱なので、適当に数字を入れても正解しそうです笑~~

…どころか、6種類しかないですね
しかも、足し合わせる分数三つを「順列」とした場合は解は6個ですが、「組み合わせ」　の場合解は1つのみです
(1+2+3=6,2+3+1=6　この二つの式はどちらも6になるので、組み合わせとしては同じ、と言う考え方)

#さいごに
問題出題者(この記事においては)なのに、問題の解釈を間違えて申し訳ございませんでした
毎度ご覧いただいてる@scivolaさんには本当に感謝しかないです
…が、こんな恥ずかしいご指摘をいただかないためにも、頑張りたいと思います
自分用メモ

## はじめに
下書きが多すぎて、下書きにストックできなかったので投稿しただけ。

どうもモデルがドメインしてないのにドメイン的に扱われていたりすることがあり、もやっとしてるので、雑にメモしておこうという意図。

## ちょっとやだなという事例

- ドメインから分けるべき処理がモデルの中の種別で管理されているとifの分岐があっちこっちに発生して死ぬ。

多分、汎用的なロール等のカテゴライズができないようなものや、出来たとしても例外が含まれるものはモデルとして分けておいた方がいい。各所であなた何タイプ？と聞くことになって、種類が増えるごとに辛みが増す。

- ModelをORMとして使っており、Modelの追加で拡張していくと、責任の範囲が謎になって死ぬ

Domain = ModelでORMしててRDB使ってる場合、問題ないのは最初だけで、後々苦しい気がする。
テーブルがそんなに柔軟に変更できないし、正規化するとそれに対応するモデルの責任がなんか中途半端な感じ。
なので、一個前の事例みたいな場合もテーブルを分けずにSTIで対応するほうがよさそう。
フレッツ IPv6(IPoE)のセキュリティに関する考察　その2

#はじめに
[フレッツ IPv6(IPoE)のセキュリティに関する考察　その1](https://qiita.com/maron2000/items/c857d01e8a4d2e62c9d5)では、とりあえずホームゲートウェイ(HGW)の**IPv6のセキュリティレベルを「高度」**にするということを紹介した。
一方で、設定を試しに、もしくは誤って「標準」にした場合にはいきなり丸裸に逆戻りになってしまう。
そこで、いわゆるバカよけ(フールプルーフ)のため、パケットフィルタも設定しておくことにした。

##HGWのIPv6(IPoE)パケットフィルタの設定
HGWのトップページ＞詳細設定＞セキュリティ設定＞IPv6パケットフィルタ設定(IPoE)から設定する。
とりあえず設定した順番で優先順位も設定しているが、本当は精査をした方が良いかもしれない。

###1.全ての外部からのアクセスは遮断
通信方向: IPoE→LAN
プロトコル:TCP,UDP
ポート：any(全ポート)
フィルタ：拒否
![deny_in_all.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577966/16da4f32-46aa-5cb7-0988-c1e70be5be29.png)

###2.ファイル共有関係(1.とも重複するが、念のため)
通信方向：両方向
プロトコル:TCP, UDP
ポート: 137-139, 445
フィルタ:拒否
![deny_netbios.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577966/f42e867e-aef7-8585-97a5-81a3a32a31bf.png)
※念のため、LAN→IPoE方向で137-139, 445の送信も遮断

###3.IPv6近隣要請
プロトコル: ICMPv6
通信方向：IPoE→LAN タイプ135
　　　　　　　LAN→IPoE タイプ136
フィルタ：拒否
![deny_neighbor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577966/72de5a5e-32c8-925e-294a-74a6d90ad88b.png)

###4.ノード情報問い合わせ等
RFC4890 4.3.5 で遮断が推奨されている
プロトコル: ICMPv6
タイプ: 138-140
通信方向：下図の通りだが、両方向でも良いかもしれない。
フィルタ：拒否
![deny_nodeinformation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577966/2bbd0b65-86a2-85b6-1108-65ab6637e897.png)

##まとめ
実験的に設定を変えてしまっても、いきなり丸裸にならないようにパケットフィルタを設定しておくことをお薦めする。
ただし、ファイアウォール機能自体をを無効にするという設定には無意味なので、結局は気休めかもしれない。
【入門】PowerAppsでSharePointリストのフォームをカスタマイズ (1)

# はじめに
SharePointのリストをPowerAppsを使っていい感じにカスタマイズする為の道のりを記事にまとめます。
勉強しながら記事をまとめている為、投稿後にも更新するかもしれません。

ある程度SharePointの知識がある人向けです。


# 1. PowerAppsでリストのフォームを開いて発行する
まずは、PowerAppsを起動して、発行するまでをやってみます。
### リストからPowerAppsを起動する

[手順]
1. コマンドバーから[PowerApps] > [フォームのカスタマイズ]をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239956/a6a7cbd5-fabd-296a-5e79-23c8c30ccb0f.png)

読み込みが走って、以下の画面に切り替われば、PowerAppsの起動が完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239956/66e92f3f-5010-e473-0b8d-effe21b5654c.png)

### フォームの画面サイズを変更する
とりあえず、表示する画面サイズを変更してみます。
[手順]
　1. [ ファイル ] > [ 設定 ]をクリック
　2. [ 画面のサイズと向き] を選択
　3. PCで表示することを想定して、横向きに変更します
　　　向き：横
　　　サイズ：L
　4. [ 適用 ]ボタンをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239956/819bf52d-96a4-d31b-9a70-45cf55649f95.png)

### 変更をリストに反映する
変更した内容をリストに反映するには
保存→発行の手順で行います。

[手順]
　1. [ ファイル ] > [ 保存 ] をクリック
　2. バージョンに関するメモに「画面サイズを変更」と記入
　3. [ 保存 ] をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239956/4da170fb-2de2-59e5-2010-edf9f3d57a70.png)


　4. [ SharePointに発行 ] をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239956/6096cfa1-dc4b-4133-3658-bb1ca0b503d0.png)

発行済みの場合は、メッセージが以下のように表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239956/821cb6fe-e57f-3666-b79b-83b24ca00b03.png)

先ほどの編集画面に戻るには左上の「<- 」をクリックすればOK

### PowerAppsからリストに戻る
SharePointに戻る場合は、編集画面の左上にある「SharePointに戻る」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239956/661c5a98-19d0-38c5-9028-d18d85bab585.png)

# 2. フォームの横幅を設定する
1で画面サイズを変更しましたので、フォームのサイズも合わせて変えてみます。

まずはSharePointFormをAppのWidth/heightに合わせます。

[手順] 
1. [FormScreen1] > [SharePointForm1]を選択
2. 以下の内容でプロパティを設定する
　width : Parent.Width
　height :Parent.Height
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239956/762e9cd9-cd8d-9d4f-827d-60ef3156feaa.png)

次に、入力フィールドも設定を変更します。
既存のプロパティに横幅を自動調整してくれる設定があるので、そちらを有効にします。

[手順]
1. [SharePointForm1] 内の各[DataCard]を選択
2. 以下の内容でプロパティを設定する
　 WidthFit : true
　※同等の設定を、右側のGUIからも行えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239956/c531aab6-f3cc-d178-362e-1de3e0668631.png)

全ての変更が完了したら、保存して発行します。


# 3.PowerAppsでカスタマイズしたフォームを削除する
もし、なんか変なことしちゃって、直すことも出来なくなった場合は、
フォームそのものを削除しちゃいましょう。

[手順]
1. [ リストの設定 ] > [ フォームの設定 ]を選択
2. [ 規定のSharePointフォームを使用する]を選択
3. [カスタム フォームを削除します]のリンクをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239956/11d2e085-a09b-6222-350e-4b53a759b784.png)
JavaScript勉強の記録その24:クラスの作成、インスタンスメソッド、継承

#クラスの作成および、インスタンスメソッドの定義・呼び出し

```index.js
class SalesPerson {
  constructor(skill){
    this.skill = skill;
  }

  introduce() {
    console.log(`私は${this.skill}が得意です`);
  }

  call() {
    console.log('お世話になっております');
  }
}

const okuno = new SalesPerson('javascript');
okuno.introduce();
okuno.call();
//=>私はjavascriptが得意です
//=>お世話になっております
```

#クラスの継承

```index.js
class Sales { //親クラスの宣言
  constructor(skill){
    this.skill = skill;
  }

  introduce() {
    console.log(`私は${this.skill}が得意です`);
  }

  call() {
    console.log('お世話になっております');
  }
}

class SalesManager extends Sales { //子クラスが親クラスを継承
  constructor(skill, managementExperience){
    super(skill); //親クラスのコンストラクターを呼び出して、skillプロパティに値をセットしてる
    this.managementExperience = managementExperience; //子クラス特有のプロパティに値をセットしている
  }
  introduce(){
    console.log(`私は${this.skill}を${this.managementExperience}磨いてきました。`); //メソッドのオーバーライド
  }

}

const manager = new SalesManager('マネジメントスキル', '2年');
manager.introduce();
manager.call(); //子クラスで定義されていないが、継承しているので親クラスのメソッッドを使える

//=>私はマネジメントスキルを2年磨いてきました。
//=>お世話になっております
```
基本情報技術者　テクノロジ系　第8章 システム開発技術⑤



# テストの概要

## 単体テスト
モジュール単体が正確に動作するかテストします。

## 結合テスト
組み合わせで正確に動作するかテストします。
モジュール間インターフェースの整合性についてチェックします。

### トップダウンテスト
上位から順に行う
何度も上位はテストすることになるので
上位ほど品質が上がります。
その反面テスト作業を並行して行いにくいです。

#### スタブ
テスト用の仮の下位モジュール
上位だけだと動かないので

### ボトムアップテスト
下位から順に行う
テスト作業を並行して行ええますが。
最終段階にならないと全体の動作テストができません。

#### ドライバ
仮の上位モジュール


### サンドイッチテスト
トップダウンとボトムアップを同時に行う

### ビックバンテスト
単体を終えたのを一度に結合して行う。

### 一斉テスト
単体を省略して、モジュールを一度に結合

## システムテスト
設計仕様を満たしているかテストします。

### 機能テスト
全ての機能が備わっているかテストします。

### 性能テスト
レスポンスタイム、スループットなど
仕様性能のテストをします。

### 負荷テスト

### 障害テスト

## 運用テスト
実際環境下でテストします。

## 退行テスト(レグレッションテスト)
変更、更新などで不具合が出ないかテストします。
Data Safeにフェデレーテッド・ユーザーでアクセスする

ここではフェデレーテッド・ユーザーでData Safeにアクセスするための手順を紹介します。

## Data Safe用のアカウントの作成

- アイデンティティ -> フェデレーションをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/4011b829-22d7-d9a2-d349-1f8a2485ee6d.png)

- Oracle Identity Cloud Service Consoleをクリックし、IDCSにログインする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/d39deb1c-106f-fcec-15a0-f2d71fb5677c.png)

- グループ -> 追加をクリックし、グループ名: datasafegrpを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/06c9ac91-c5d5-796c-6c83-9079cbffa3de.png)

- OracleIdentityCloudServiceをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/f1587ed2-7fa9-4773-267b-68847bc51abe.png)

- IDCSグループの作成をクリックし、グループ名: datasafegrpで作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/28294962-82b8-4082-899c-d6d17ad23e24.png)

- グループ・マッピング -> マッピングの編集をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/2518bd01-a05d-f2d3-2d5f-948dcddf55ef.png)

- マッピングの追加をクリックし、IDCSのグループ名: datasafegrp -> OCIのグループ名: datasafegrp をマッピングして追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/44c57985-1cfa-c8f0-1178-9ec760cb163b.png)

- IDCSユーザーの作成を作成する。その際、グループにdatasafegrpを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/fd6ee6c0-925e-2f17-612e-f5d7deea8161.png)

- ポリシーのリンクから、ポリシーの作成をクリック。コンパートメントはrootを選択しておくこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/0a661724-17cf-1748-0b98-24ec86520611.png)



- 以下の通りに入力
    - 名前: datasafepolicy
    - ポリシー・ステートメント: 
    - allow group datasafegrp to manage data-safe in tenancy
    - allow group datasafegrp to inspect groups in tenancy
    - allow group datasafegrp to manage autonomous-database in compartment datasafe
    - allow group datasafegrp to manage database-family in compartment datasafe
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/4d97074f-a5e2-7748-2aee-6c941a61b097.png)

※必須なのは、data-safeとgroupsの権限。それ以外、今回の場合はAutonomousがdatasafeコンパートメントに作成しているので、manage権限を付与しています。ご自身の環境に合わせてポリシーは適宜修正して下さい

- ポリシーが追加された
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/2de9f72d-0080-f7b7-1f25-5b6642aa884c.png)



以上で、Data Safeを操作することができるフェデレーテッド・ユーザーの作成は完了です。次に、[DataSafeの有効化](https://qiita.com/western24/items/ce12012acfc429b363a7#data-safe%E3%81%AE%E6%9C%89%E5%8A%B9%E5%8C%96)を行います。

Oracle Data Safeの関連情報は[こちら](https://qiita.com/western24/items/4824e4b3799b824197c6)
【github】ローカルのmasterを、強制的にリモートのmasterに合わせる方法

こんにちは！あすかです。

自分の備忘録として書いてます。

ローカルをリモートにあげたmasterに
強制的に合わせたい時


// 1) リモートの最新を取ってきておいて・・
`$ git fetch origin master`

// 2) ローカルのmasterを、リモート追跡のmasterに強制的に合わせる！
`$ git reset --hard origin/master`

これで強制的にリモートのmasterがローカルに反映されます！


なんかエラー起きて色々やってもエラー直らないから
リモートのmasterに戻してやり直したい。。。
間違えて消しちゃった。。。

て事が何度かあったので今回の記事を書きました。

[参考記事]
http://www-creators.com/archives/1097

ご覧いただきありがとうございました。
BERTのファインチューニングで威力を発揮する「slanted triangular learning rate」をKerasで実装した

# 概要

Kaggle の自然言語処理のコンペに参戦中で、BERTをfine-tuningしたかった。Slanted triangular learning rate (STLR) が良いという情報を得て、Kerasで実装してみたところ、かなり精度が上がった。

（追記）その後シルバーメダルをゲットできた。

# Slanted triangualr learning rate

参考にしたのは↓の論文。

- [Universal Language Model Fine-tuning for Text Classification](https://arxiv.org/pdf/1801.06146.pdf)

Fig.2 を見れば分かる通り、学習初期の学習率の warm-up と中盤以降の学習率の減衰を、どちらも線形にする。傾いた三角形のようなので「slanted-triangular」。

ちなみにSTLRを使おうと思った元の論文は↓

- [How to Fine-Tune BERT for Text Classification?](https://arxiv.org/pdf/1905.05583.pdf)

# Keras による実装

Keras の `Callbacks` の仕組みを使えば実現できる。STLR は epoch ごとではなく、iteration （Keras の用語でいうところの steps）ごとに学習率を変更させる必要があるので、`LearningRateScheduler` は使えない。`Callbacks` クラスを継承してスクラッチで作る必要がある。

```python
class SlantedTriangularScheduler(Callback):
    
    def __init__(self,
                 lr_max: float = 0.001,
                 cut_frac: float = 0.1,
                 ratio: float = 32):
        self.lr_max = lr_max
        self.cut_frac = cut_frac
        self.ratio = ratio
    
    def on_train_begin(self, logs = None):
        epochs = self.params['epochs']
        steps = self.params['steps']
        self.cut = epochs * steps * self.cut_frac
        self.iteration = 0
        
    def on_batch_begin(self, batch: int, logs = None):
        t = self.iteration
        cut = self.cut
        if t < cut:
            p = t / cut
        else:
            p = 1 - (t - cut) / (cut * (1 / self.cut_frac - 1))
        lr = self.lr_max * (1 + p * (self.ratio - 1)) / self.ratio
        K.set_value(self.model.optimizer.lr, lr)
        self.iteration += 1
```

変数名などは、なるべく原著論文のEq(3)と同じものを用いている。

[How to Fine-Tune BERT for Text Classification?](https://arxiv.org/pdf/1905.05583.pdf) で示されている通り、BERT の fine-tuning には↓この組み合わせがよく効いた。

|ハイパーパラメーター|値|
|----|----|
|`lr_max`|`2e-5`|
|`cut_frac`|0.1|
|`ratio`|32|
Google Cloud FunctionsからCloud Firestoreにpythonコードで接続する方法

# はじめに
Google Cloud Functions for Firebaseではなく、pythonコードかつGoogle Cloud Functionsから繋ぎたい時にどうするかという対応方法をまとめました。

Firebaseから認証情報引っ張ってくるとかは書いてないので、他の記事を参考にしてください。

# 環境
python 3.7で作ったGoogle Cloud Functions

firebase-admin 3.2.1 

# Google Cloud Functionsでpythonコードを作った時の制限
main.pyとrequirements.txtしか受け付けてくれないようです。
よくあるserviceAccountKey.jsonファイルを読み込んでーという方法ではだめでした。
credentials.Certificateにファイルパスくわせて認証する一般的なやり方ですね。

# credentials.Certificateをファイル以外から作成しよう
なので、他の方法を探りました。

まずはAPI仕様書を確認しました。
https://firebase.google.com/docs/reference/admin/python/firebase_admin.credentials

```
A credential initialized from a JSON certificate keyfile.
```

ということでkeyファイルからやるやつだよってことらしいです。
ちなみにjavascript側からだとAPI仕様書にファイル以外から受け付けるやり方書いてますので、javascript使ってる方はAPI仕様書をご覧ください。

それじゃどういう処理してるんだろうと思って、ソース見に行きました。
https://github.com/firebase/firebase-admin-python/blob/master/firebase_admin/credentials.py

``` python
# 上記URLの８１行目から引用
if isinstance(cert, str):
    with open(cert) as json_file:
    json_data = json.load(json_file)
elif isinstance(cert, dict):
    json_data = cert
```

出来るんかーい。
ということでdict型にして渡してあげればそれで読み込んでくれるようです。
ソース読むもんですね。

# それじゃ実装しよう
私の場合はこのコードをgithubで公開しているため、環境変数にserviceAccountKey.jsonの中身をそのまま設定して読み込んでいます。
公開しないよって人はpythonコード内に埋め込んでも大丈夫ですが、これ漏れるとまずいので扱いは気をつけてください。

環境変数部分はpython-dotenvを使っていますが、省略します。

client作成コードを抜き出した版は以下です。

``` python
import os
import json
import firebase_admin
from firebase_admin import firestore
from firebase_admin import credentials

cred = credentials.Certificate(json.loads(os.environ.get("FIREBASE_KEY")))
firebase_admin.initialize_app(cred)
db = firestore.client()
```

依存するライブラリは

```
firebase-admin
google-cloud-firestore
```

の2つなので、入れておいてください。
`firebase-admin`しかコード上には現れませんが、`firebase-admin`が`google-cloud-firestore`に依存しているため、2つとも必要です。

# おわりに
Google Cloud Functions For Firebaseがpythonに対応しますよーに（そうすれば何も問題はなかった）
TRACKER NETWORKのApex Legends Apiを触ってみた

#はじめに
TRACKER NETWORKは自分のfpsゲームのstatsを見るのに使っていましたが、APIがあるなんて初めて知りました。

#TRACKER NETWORKのAPI Key取得方法
####1,TRACKER NETWORKにログイン後、下記で適当なアプリを作る
>https://tracker.gg/developers/docs/getting-started

####2,作成すると、API Keyが出てきます
![tracke.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576886/9956c9df-e819-98f9-ba6a-b05da4807487.png)

#API Keyをheaderに埋め込む
```
//ヘッダーフィールドの配列
$header = array(
"TRN-Api-Key:入手したAPI Key"
);

//headerの設定
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
```

#コード
今までfile_get_contentsを使っていたがcurlのほうがheaderがつけやすそうなのでcurlに変えました。
どうやらcurlは、読み込み速度が早くてパフォーマンスが良いらしい

参考にしたサイト
>https://www.marineroad.com/staff-blog/18954.html

```
<?php
    //ヘッダー
    $header = array(
        "TRN-Api-Key:入手したAPI Key"
    );

    if(isset($_POST["userid"])){
        //userid取得
        $userid = rawurlencode($_POST['userid']);
        //platform取得
        $platform = $_POST['platform'];
        //url
        $url = "https://public-api.tracker.gg/v2/apex/standard/profile/${platform}/${userid}";

        //user情報取得
        $ch = curl_init();

        curl_setopt($ch,CURLOPT_URL,$url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

        $response = curl_exec($ch);
        $profile = json_decode($response, true);

        curl_close($conn);
    }
?>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>apexstats検索</title>
    </head>
    <body>
        <form action="" method="POST">
            <p>useridを入力してください</p>
            <input type="text" name="userid" placeholder="例:RuRey 0w0">
            <select name="platform">
                <option value=""></option>
                <option value="origin">PC</option>
                <option value="xbl">xbox</option>
                <option value="psn">PS4</option>
            </select>
            <input type="submit" value="送信">
        </form>
        <div>
            <?php
                //出力
                echo "name:";
                echo $profile["data"]["platformInfo"]["platformUserId"];
                echo "<br>";
                echo "platform:";
                echo $profile["data"]["platformInfo"]["platformSlug"];
                echo "<br>";
                echo "country:";
                echo  $profile["data"]["userInfo"]["countryCode"];
                echo "<br>";
                echo "level:";
                echo  $profile["data"]["segments"][0]["stats"]["level"]["displayValue"];
                echo "<br>";
                echo "rank:";
                echo  $profile["data"]["segments"][0]["stats"]["rankScore"]["value"];
                echo "<br>";
            ?>
        </div>
    </body>
</html>
```

#結果
![apex.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576886/12422601-2fea-e866-6909-aaeec00bed4a.png)
↓
![ape3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576886/9afe8878-2dac-3208-21c6-599315769128.png)

#最後に
出力する部分で最初はforeachにしていましたが、見にくすぎてやめました。
結局echo連打も見にくいので、ほかのいい方法を探そうと思います。
React NativeのビルドにAndroid Studioに同梱されているJavaを使う

React NativeでAndroid向けにビルドする場合、環境にJavaがインストールされている必要がある。

メジャーなのはOracleの配布しているJava。しかしAndroid StudioにはそれでなくOpen JDKが同梱されている。

Android Studioのと合わせた方がトラブルが生じにくいだろうし、またOracle Javaのライセンス変更[^1]を気にする必要もなくなるため、Android Studioに同梱されているJavaをReact Nativeのビルドに使う。

[^1]: [「Oracle Java」のライセンスが変更 ～無償利用は個人での開発・テスト・デモ目的のみに](https://forest.watch.impress.co.jp/docs/news/1180607.html)

## 環境
- macOS Mohave 10.14.6
- react-native: 0.61.5

## 手順

`.bash_profile`に下記のように記述する。

```sh
export PATH=$PATH:/Applications/"Android Studio.app"/Contents/jre/jdk/Contents/Home/bin
export JAVA_HOME=/Applications/"Android Studio.app"/Contents/jre/jdk/Contents/Home
```

## 参考
Android Studioで使っているJDKをターミナルでも使う
https://qiita.com/tsumuchan/items/43a55789f1cf213611cc
コンテナを起動したはずなのにdocker-compose psで確認するとコンテナがexitとなることの対策

まず最初に僕の環境についてなんですが、Docker Toolboxを使用しています。
なのでこのエラーと対策法はDocker Toolbox特有のものかもしれないのでそこはご了承ください。

#docker-compose psでexitが出た
おそらく僕と同じエラーで引っかかった人はdocker-compose psコマンドを打った時にdb(データベース)はちゃんとupと表示されているのに、railsのところ（？）ではexitと出ていてローカルホストにアクセスできないのではないでしょうか。

    docker-compose down
からの

    docker-compose up -d
をしてコンテナを再起動してもexitのまま、ここで数時間詰まってしまいました

#docker-compose logsでlogの確認
何か原因となるものがあるかとlogの中を見てみると僕の環境の場合、already server up という記述がlogの中rails(?)にあり、そこにapp/tmp/pids/server.pidと書かれていました。

結局このserver.pidが悪さをしていてサーバーを立ち上げることができなかったそうです。フォルダからserver.pidを削除し、

    docker-compose up -d
で再起動してあげたらローカルホストにアクセスできるようになっていました。参考になれば幸いです。
docker-composeでよく使うコマンド(Ruby on Rails)

MySQLを使う場合

```docker
$ docker-compose run web rails new . --force --database=mysql
$ docker-compose build
```

model作成

```docker
docker-compose run web bundle exec rails g model (モデル名)　(カラム名)
```
バックグラウンドでコンテナ起動

```docker
docker-compose up -d
```

コンテナ再起動

```docker
docker-compose restart
```

Gemfile変更時(基本的には)

```docker
$ docker-compose build
```


DBへテストデータ投入

```docker
$ docker-compose exec web bundle exec rake db:seed
```
DBへテストデータを一から入れ直したい時
(テーブル削除、作成、マイグレーション)

```docker
$ docker-compose exec web bundle exec rake db:drop
$ docker-compose exec web bundle exec rake db:create
$ docker-compose exec web bundle exec rake db:migrate
$ docker-compose exec web bundle exec rake db:seed
```

dockerコンテナ、イメージ削除


```docker
$ docker rm $(docker ps -q -a)
$ docker rmi $(docker images -q)
```



補足: kaminari設定ファイル生成

```docker
$ docker-compose exec web bundle exec rails g kaminari:config
```

補足: kaminari(bootstrap4)ファイル生成(bootstrap4)

```docker
$ docker-compose exec web bundle exec rails g kaminari:views bootstrap4
```

補足: kaminariページネーションファイル生成

```docker
$ docker-compose exec web bundle exec rails g kaminari:config
```

Rspecを使う場合（Gemfileにはrspecの記述をする）

```docker
$ docker-compose run web bundle exec rails g rspec:install 
```
関数について

#関数とは
何かの処理を実行してくれるものである。

ミキサーで例えると、
ミキサーが関数
イチゴが引数１
ミルクが引数２
イチゴミルクが返り値
である。

以下のソースがミキサーの関数

```php
function mixer($material1, $material2)
{
    $deliverable =  $material1 . $material2;
    return $deliverable;
}
```

ミキサーにイチゴとミルクを入れてイチゴミルクを完成させる。

```php
mixer("strawberry","milk");
```
「アクション」の概念とエラー処理や通知の場所

アプリを書いているとエラー処理や通知をどこに書くかで悩みます。本稿では、アプリに現れる「アクション」の概念を指摘し、アクションとエラー処理や通知の関係について述べます。

人によっては、こんなのは当たり前のことだと思われるかもしれません。しかし、筆者はアクションの概念を意識していなかったために設計をミスった経験があります。その反省として、この記事でこの概念の言語化を試みることにしました。

もしかしたら逆に全くの間違いだと言われるかもしれませんが、その際はコメントをいただけると嬉しいです。

**おことわり**: 本稿の「アクション」は一般的な用語ではありません。本稿の主張は筆者の経験に基づいて書かれており、普遍的に当てはまるわけではないかもしれません。

## 要約

- アクションは短時間で起こる一連の処理の最上位のこと
- アクションは例外をキャッチする場所
- アクションは結果を持たず、副作用を引き起こす
- アクションの Future は安全に捨てられる
- アクションは認知されている場合に限り実行状況や結果の通知を出す

## アクションの概念

本稿の **アクション** は、平たく言うと **短時間で起こる一連の処理の最上位** を指します。

例えば Web アプリでは、HTTP リクエストを受け取ってから対応するレスポンスを返すまでの処理です。Web サーバが何日も動きつづけるのに対して、リクエストの処理は通常、数ミリ秒〜数分なので、短時間で起こると言って差し支えないでしょう。

逆に、Web サーバなどの通常は **短時間で停止しない処理はアクションとはいわない** ことにします。

別の例としてイベント駆動型の GUI アプリでは、ボタンを押すなどのイベントが発生してから終了するまでの一連の処理が、1アクションになります。コンソールアプリならアプリの起動から終了までで1アクションかもしれません。

また、アクションは関数とは違って他のアクションの一部にはならないことにします。これは言い換えると、外側だけをアクションと呼ぶというわけです。

## アクションのエラー

「例外は **最上位** でキャッチせよ」という主張をしばしば見ます。この「最上位」と本稿の「アクション」は近いものを指していると思います。

Web サーバが「HTTP リクエストを待ち受けている部分」より上で例外をキャッチせよとはいってないはずです。リクエストの処理中に起こった例外がその部分を停止させたら困ります。

したがって前述の主張を言い換えると、 **アクションは例外をキャッチする場所** であるといえます。アクションを1個の関数として実装するなら、以下のように全体が try-catch で覆われることになるかもしれません。

```js
function fooAction() {
    try {
        // アクションの処理
    } catch (ex) {
        // エラー情報をログ出力するかもしれない
        // 「エラーが発生しました」などのメッセージを出すかもしれない
    }
}
```

(場合によります。.NET なら集約例外ハンドラを使う方がいいかもしれません。)

## アクションの結果

アクションは通常、1個の関数です。そして、結果型は void、unit、または int (終了コード) になります。

アクションの「結果」は関数の戻り値としてではなく、HTTP レスポンスの送信、画面への表示、ファイルの生成、データベースの更新、グローバル変数の書き換えなどの副作用として起こります。

## アクションと非同期処理

非同期処理を async/await あるいは Future/Promise/Task によって「非同期的に何らかの処理をして、その結果を返す」パターンで実装するとします。

Future の結果を「受け取る」のも非同期なので、結果を受け取る側も非同期処理になります。しかし、すべての関数を非同期にすることはできません。そのためどこかには「非同期処理を開始するけど、その結果は無視する」ような場所があるはずです。(Fire & Forget. 言語によってはランタイム側にあるかもしれません。)

前述の通り、アクションからは例外が漏れず、特に結果値を持たないので、Future の結果を無視しても安全です。**アクションは Future を捨てる場所** にふさわしいです。

## アクションと通知

アクションを「ユーザーに認知されているアクション」とそうでないものの2種類に分けることにします。

**ユーザーに認知されているアクション** とは、ボタンを押すなどの、ユーザーが何らかの処理を期待する操作によって引き起こされるアクションです。

逆に認知されているとはいえないアクションは、例えばタイマーの指定時間が経過したとか、入力欄に文字を入力したとかです。ずいぶん大雑把ですが、アクションが認知されているかどうかはアプリの UI に依存するので、一概にはいえません。

傾向としては、認知されているアクションの処理が長引いているときは「処理中です」といった表示を出したり、エラーが発生したときは「エラーが発生しました」系のメッセージを出す方が、ユーザーをイライラさせないであろうと思います。

逆に認知されていないアクションがその手の通知を出してくるとうるさいかもしれません。

そのため **実行状況・実行結果の通知を出すか否かは、アクションが認知されているかどうかでおおよそ決まる** といえそうです。

(最後に個人的な好みを書いておくと、メッセージ表示はモーダルダイアログではなくトーストにしてほしいし、GUI フレームワークはトースト通知を出す仕組みを用意しておいてほしいです。)
Google ChromeからSSHポートフォワードを使用してWebサイトを閲覧する

### はじめに
自分のルータにIPv6アドレスしか割り当ててないと、IPv4に対応していないサイトが見れなくなった。
IPv6の設定を無効化すればよいのだが、やんごとなき事情によりできない場合の回避策として、AWSに上にSCOKSサーバを立てることでサイト閲覧ができるようになった。以下では、その方法と解説を簡単に記載する。

### AWSのIPv6対応について
AWSのドキュメントによると、VPCではデュアルスタックで動作しているらしい。

> VPC は、デュアルスタックモードで動作します。IPv4 または IPv6 あるいは両方を経由して通信できます。IPv4 と IPv6 は、互いに独立して通信されます。

このため、クライアントからIPv6でEC2にアクセスし、EC2から各Webサイトにアクセスする際はIPv4またはIPv6でアクセスしにいく。

### VPCとEC2をIPv6化する
以下のURLの通りに設定を行った。詳細に書くと長くなるので省略する。

https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-migrate-ipv6.html#vpc-migrate-ipv6-routes

なお、AMIをCentOSにすると、IPv6が自動的に割り当てられず面倒であるため、今回はAmazon Linux2を使用した。コストを抑えるためにインスタンスタイプはt3.nanoを使用した。


### SSHダイナミックポートフォーワードする
以下のコマンドを実行し、EC2をSOCKSサーバとして利用する。
`$ ssh -D 1080 ec2-user@<IPv6 Address>`

### Google ChromeでSOCKSプロキシ設定を行う。
Chromeの環境設定から、詳細設定>システム>プロキシ設定を開く>プロキシ  の画面を開く。

|設定項目|設定内容|
|:--:|:--:|
|構成するプロトコルを表示|SOCKSプロキシにチェック|
|簡易ホスト名を除外|チェック|
|SOCKSプロキシサーバ|localhost:1080|
|プロキシ設定を使用しないホストとドメイン|localhost,<EC2のIPv6アドレス>|

### 設定確認
以下のURLから接続元IPがEC2のIPｖ６アドレスになっていることが確認できる。
https://linuxfan.info/ip

### 接続速度の確認
Googleのスピードテストを実行したところ、以下の結果となった。
下り : 21.1Mbps
上り : 30Mbps

Youtubeの1080p程度であれば問題なく視聴できる速度である。(4Kは厳しいかも)
注意点としては、SOCKSサーバを経由する以上、遅延は避けられない。
そのため、リアルタイム性が重視されるオンラインゲームなどには向かない。

### おわりに
今回はIPv4に対応していないサイトを閲覧するために、AWSのデュアルスタックを利用してIPv6→IPv4に通信を変換しサイトを閲覧できるようにした。
この方法を実現する前は本当に見れるサイトが少なく、実際に世にあるサイトでIPv6に対応しているサイトは少ないことを身を持って実感した。
IPv4アドレスが枯渇しつつある今、Webサイトを運営している方には是非IPv6の対応を検討してもらいたい。

記事で間違っている内容があればコメントお願いします。
RETROF-16 レジスタ構成と命令毎の内部動作



　①が本機RETROF-16のレジスタ（主メモリを含む）の構成図です。説明の都合上、入出力関係と画像表示関係の回路に相当する部分は割愛しています。図中の赤色の線はアドレスバスを、青色の線はデータバスを、緑色の線はALUバス（演算結果バス）を意味します。
　本機は汎用レジスタを256本有しますが、これらは主メモリの一部をレジスタと見做す「仮想レジスタ方式」です。具体的には主メモリの0x00番地から0xFF番地が0番レジスタから255番レジスタに対応します。従って例えば「0番地に値xを書き込む」と「0番レジスタに値xを書き込む」は同義となります。
![令和版レジスタ - 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535901/86776b7b-1e70-522c-3550-4f6cd6f9f903.png)
 本機の全ての機械語命令はSTAGE-0からSTAGE-6までの7つのSTAGEで処理されます。STAGE-0からSTAGE-5は2クロック、STAGE-6は1クロックを消費します。従って全STAGEは13クロックで処理されます。クロックは16MHz（62.5ns）ですから、全ての機械語命令は812.5nsで実行が完了します。
 STAGE-0でPCの値をWに転送し（図②）、STAGE-1でWで示されるMの内容をIRとW自身に転送します（図③）。この時IRには命令コードの上位8bitをWには命令コードの下位8bit(上位8bitはゼロクリア)が格納されます。
 8ビットリテラルアドレッシングの場合はSTAGE-2、STAGE-3は何もしません。Wには命令コードの下位8bitがそのまま残ります（図④）。
![令和版レジスタ - 3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535901/81bde7c9-6a25-4386-b163-ccc2abd11340.png)
　レジスタアドレッシングの場合（図⑤）はWが示すMの値をW自身に格納します。STAGE-1終了後のWの値は0～255のいずれかですから、この処理終了後はWには主メモリの0～255番地のいずれかの値、すなわち0番レジスタ～255番レジスタのいずれかの値が格納されることになります。
　レジスタ間接アドレッシングの場合（図⑥）はWが示すMの値をW自身に格納する動作を2度行います。これによりWには0番レジスタ～255番レジスタのいずれかが示すメモリの値が格納されます。
　16ビットリテラルアドレッシングの場合（図⑦）は命令ワードの次のワードがWに格納されます。命令ワードの下位8bitは意味を持たなくなります。
#####アドレッシングモードとWの値の関係のまとめ
|モード|STAGE-3終了時のWの値|
|---|---|
|8bitリテラル |命令コードの下位8bit |
|レジスタ | n番レジスタの値 |
|レジスタ間接 |n番レジスタで示される主メモリの値 |
|16bitリテラル|命令コードの次のワード（16bit） |

![令和版レジスタ - 4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535901/bef5b8e3-d8c6-be87-53cd-255b135cb765.png)

　分岐命令は現在のPCの値とWの値との演算結果をPCに格納します（図⑧）。演算種別はWの値をそのまま演算結果とする（絶対分岐）、PCにWの値を加える（前方相対分岐）、PCからWの値を引く（後方相対分岐）の3種類です。但し実際に分岐するか否かは命令コードとフラグレジスタの値で決まります。
　演算命令は現在のAccの値とWの値との演算結果をPCに格納します（図⑧）。演算種別はWの値をそのまま演算結果とする（ロード命令）を含め7種類です。演算命令はフラグが変化します。
　LDM(Load from memory)命令（図⑩）はWで示されるメモリの内容をAccにロードします。LDM(Store to memory)命令（図⑪）はAccの値をWで示されるメモリ番地にストアします。
　シフト命令（図⑫）はAccを単に1bit右シフトするだけです。Wの値（オペランド）は意味を持ちません。ちなみに左シフトはAccにAccの値を加えることで実現できるので機械語命令は存在しません。
　本機では未定義命令は全てHALT命令（実行停止命令）と見做します。命令コードが未定義命令の場合はSTAGE-4でステージカウンタ（回路図のU27 74LS163）を強制停止します（図⑬）。
![令和版レジスタ - 5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535901/571cac08-59c5-136f-2815-527b992bccaf.png)
　入力命令は基板上のスイッチ、もしくはキーボード等を接続する端子のいずれかの値を入力ポートバッファ（図⑭のIN、実体は74LS257）とALUを介してAccに格納します。Wの値（オペランド）は意味を持ちません。
　出力命令はWの値を基板上のLED（上段16個）に、Accの値を基板上のLED（下段16個）に表示します（図⑮）。本機は液晶ディスプレイを表示装置として使えますので、この基板上のLEDに対する出力命令は、ソフトウェア処理の途中経過を表示するのデバッグ的な使い方を想定しています。
　画像メモリからのロード（LDV命令、図⑯）と画像メモリへのストア（STV命令、図⑰）は対象となるメモリが異なるだけで基本的にはLDM命令とSTM命令と同じです。但し、画像メモリはLDM命令とSTM命令実行時以外は、CPUの動作とは無関係に毎秒75回のリフレッシュレートで画像を表示する必要がありますので、アドレスバスとデータバスにバスバッファを挿入し、回路的に独立させています（図⑱）
SQLAlchemyでmulti databaseに対応する

# はじめに
AWS Auroraは書き込みと読み込みのエンドポイントが違います。
そういうケースでのpythonのSQLAlchemy対応方法をまとめました。

なので、前提としては書き込み用と読み込み用でエンドポイントが違うだけでModelが同じであるとしています。

# 環境
python 3.8.1
SQLAlchemy 1.3.12

# query_propertyは使えません
SQLAlchemyの便利機能であるquery_propertyはアプリ内でsessionが１つであることを期待するため、残念ながら使用することは出来ませんでした。
コード的には以下のように書けてとても便利でしたが、multi databaseに対応するにはsessionがどうしても２つ必要になります。

``` python
User.query.all()
```

# それではどうするのか
session2つ作って普通に呼び出せばOKです。
なので、クエリの呼び出しもsessionを使用した形で書く感じです。

``` python
session.query(User).all()
```

また、とあるセッションで取得したデータは別のセッションのinsertやupdateをそのままオブジェクトでやるとエラーになるため注意です。
具体的には以下のコードは動きません。
取得したデータ内の何処かにある状態を削除すれば動くと思いますが、素直に別オブジェクトに移し替えた方が無難です。

``` python
read_session = read_session()
users = read_session.query(User).all()

write_session = write_session()
write_session.add_all()
```

# 全体のソースコード
githubにあげてますので、詳しくはそちらをご覧ください。

https://github.com/tasogarei/sqlalchemy_multi_session_sample

# おわりに
query_property便利ですが、どうにも対応できなく諦めました。
Modelがデータベース毎に分かれているのであれば、declarative_base()を複数個上手く作ってあげればそれぞれ紐付けできて上手く行く気がしています。
ただし未検証。今やりたいこと終わったら検証してみます。
【基礎of基礎】cloud9でMySQLを使う方法【MySQLのよわよわが読むやつ】

#MySQLの基本的な使い方


この記事はMySQLを今日勉強はじめたよ〜って人向けの記事です
私は一昨日はじめて勉強しました
MySQLを自分で導入したら面倒くさいけど、cloud9だったらパパッと使えちゃう！



##1.データベースサーバ

###サーバ起動

`$ sudo service mysqld start`

このコマンドでMySQLサーバが起動するよ！ぶおんっ
ちなみに **$** このマークは入力しないよ

---

###起動しているか確認したい

`$ sudo service mysqld status`

これで確認できるよ〜

---

###サーバ停止~!

`$ sudo service mysqld stop`

これで止められます。

---

###サーバに接続！

`$ mysql -u root`

これでサーバに接続すると、
***mysql>*** これが出てくるので、この状態でデータベースやテーブルを作成します。





##2.文字コードをutf-8に設定して文字化けしないようにする

以下のコマンドを実行して***etc/my.cnf***というファイルを開く

`sudo nano /etc/my.cnf`


[mysqld]と[client]の一番下にそれぞれ以下の記述を追加する

``` /etc/my.cnf
[mysqld] 
...省略...
character-set-server=utf8 

[client]
...省略...
default-character-set=utf8 
```

保存して終了です！
保存方法は ***esc*** 押してから ***:wq*** 押す！
 


`show variables like "chara%";`と打つと

```
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
```

と出てきて、utf-8に変わっていることが確認できます〜！！！！！


##3.データベース作成したり消したり

###データベース作成

`$ mysql -u root`

でサーバ接続した状態で

`CREATE DATABASE hoge;`

で"hoge"というデータベースができます！！！

---

###データベース削除

`DROP DATABASE bookstore;`

これでデータベース消えます。さよなら〜
間違って消すことがないように！

---

###データベース何あるかな〜って確認


`show databases;`

これで確認できます！！！

---

あとはテーブルを好きなように作れば良いね！！！！！
Oracle Database の Docker で タイムゾーンを変更する

# 概要
Oracle Database の Docker にてタイムゾーンを変更するための手順になります。

Oracle Database の Docker導入の手順に関しては、下記記事が非常に参考になりました。
[DockerでOracle Databaseを使う](https://qiita.com/gorilla0513/items/f22e8cce4e08da031abe)

詳細な手順については、公式リポジトリを参考にいただくと良いかと思います。
https://github.com/oracle/docker-images/blob/master/OracleDatabase/SingleInstance/README.md

# 環境
- Docker for Windows
- Windows10
- Oracle Database 12c

# 結論
docker-compose.yaml に環境変数TZを設定すればOKです。

```yaml
version: '2'
services:
  db:
    image: oracle/database:12.1.0.2-se2
    container_name: oracle
    ports:
      - 1521:1521
      - 5500:5500
    volumes:
      - ./oradata:/opt/oracle/oradata
    environment:
      - ORACLE_PWD=Oracle01
      - ORACLE_PDB=pdb01
      - TZ=Asia/Tokyo ★★★ これ ★★★
```

# 右往左往した記録
(※) 以下、調査した過程を備忘録として残します。完全に蛇足なので、興味のある方だけご覧ください。

Oracle Database の Docker を利用している際、 `SYSDATE` 関数を実行した結果が UTC になっていることに気付きました。
docker exec でコンテナに接続し、dateコマンドを叩いてみると案の定、 UTC になっていました。

```bash
$ date
Sat Feb  1 15:07:28 UTC 2020
````

Linuxサーバのタイムゾーンを変更するには、timedatectlを使う方法 (RHEL7系 / CentOS7系) やタイムゾーンの設定ファイル (/usr/share/zoneinfo)をコピーする方法があります。

OSの情報を確認したところ、RHEL7.7となっていました。

```sh
$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.7 (Maipo)
```

試しにコンテナ内で timedatectl を叩いてみると、エラーが発生します。

```bash
$ timedatectl
Failed to create bus connection: No such file or directory
```

調査してみたところコンテナの実行権限に起因する可能性があり、特権モード (privileged) を設定したり、ケーパビリティの設定を変更する事で解消する可能性があるという情報を見つけたのですが、解決することが出来ませんでした。
(※) 情報をご存じの方がいらっしゃれば、教えていただけると助かります。

よって、タイムゾーンの設定ファイルのコピーによって対応することにしました。

```bash
# シンボリックリンクを設定する方法もあります
# ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

$ cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
cp: cannot create regular file '/etc/localtime': Permission denied
```

パーミッション不足で怒られたため、rootユーザでコンテナにログインします。

```bash
PS > docker exec -it --user root {コンテナ名} /bin/bash
OCI runtime exec failed: exec failed: container_linux.go:346: starting container process caused "chdir to cwd (\"/home/oracle\") set in config.json failed: permission denied": unknown
```

良く判らないエラーが発生しました。。。
ググってみると、同様の事象を対応している記事を発見しました。

> [Logging in as root on Oracle Database Docker image](https://rmoff.net/2018/11/30/logging-in-as-root-on-oracle-database-docker-image/)

記事のよると、`--workdir`オプションを使ってDockerfileの`WORKDIR`の設定を上書きするといいよ[^1] とのことなので、早速試してみます。

```bash
PS > docker exec -it --user root --workdir / {コンテナ名} /bin/bash
bash-4.2# cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
bash-4.2# date
Sun Feb  2 21:55:24 JST 2020
```

上手くいきました。
ただ、今回の場合は 環境変数TZ を変更する方が簡単ですので、そちらを実践される方が良いかと思います。

[^1]: イメージの元となっている Dockerfile に `WORKDIR /home/oracle` が指定されていることに起因しているようです。(https://github.com/oracle/docker-images/blob/master/OracleDatabase/SingleInstance/dockerfiles/12.2.0.1/Dockerfile#L105)
俺の甲子園で挨拶しまくるスクリプトを作った

「俺の甲子園」というブラウザゲーム内のとある作業を、Pythonを使って自動化してみました。
Pythonは普段全然使わないので、初心者レベルのコードです。ご了承ください。

# 俺の甲子園とは
高校野球シミュレーションゲームです。
野球ゲームですが、実際の試合はCPUによって行われていて、プレーヤーは監督となって指導することがメインになります。
この指導のためにはポイントが必要で、いくつかあるポイントの中に**情熱PT**というものがあり、他校（他のプレーヤー）に挨拶することで増やすことができます。

今回、この挨拶を自動化するスクリプトを作成しましたので、紹介したいと思います。

# ライブラリ
自動化にあたって、Pythonの以下のライブラリを使用しています。
- random
- urllib
- requests
- Beautiful Soup
- Selenium

Selenium使用のため、別途Chrome Driverをダウンロードする必要があります。

# スクリプト
```python:orekou.py
import random, urllib, requests
from bs4 import BeautifulSoup

def getSchoolURL():
    #地区をランダムに選択
    area_num = random.randint(1, 49)

    #学校のリンク情報をリストで取得
    html = urllib.request.urlopen("http://orekou.net/profile/school_list/" + str(area_num)).read()
    soup = BeautifulSoup(html)
    link_elem = soup.select(".sub_content a")

    #リストにある学校の中からランダムで1つ選択
    school_num = random.randint(1, len(link_elem))
    school_url = "http://orekou.net" + link_elem[school_num-1].get("href")
    
    return school_url
```
```python:greet.py
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

import orekou

#既存のプロファイルを読み込んでChromeドライバを生成
options = webdriver.ChromeOptions()
options.add_argument("--user-data-dir=C:\\Users\\<ユーザー名>\\AppData\\Local\\Google\\Chrome\\User Data")
chrome = webdriver.Chrome("./chromedriver_win32/chromedriver.exe", options=options)

#Chromeブラウザを開く
chrome.execute_script("window.open('', '_brank');")

#ランダムに選んだ100校に挨拶する
for index in range(100):
    chrome.get(orekou.getSchoolURL())
    chrome.switch_to.window(chrome.window_handles[0])
    chrome.execute_script("document.getElementsByTagName('input')[2].click();")

chrome.quit()
```
ブラウザゲームのログインが必要なので、既存のプロファイルを取得する処理を入れています。
上記の<ユーザー名>の部分はユーザー毎に異なるので、各自で変更してください。
挨拶によるポイント獲得は**100回まで**なので、ループも同じ回数しています。

# 結果
1校へ挨拶するのに約3秒かかりますので、100校終えるのに**約5分**です。
手作業でするより遥かに速い！

# 実は...
他校に練習試合を申し込むと、挨拶するより効率的にポイントを稼げます。。。
もっとポイントを稼ぎたいんだ！！っていうガチ勢の方、是非スクリプトを活用してみてください。
[漏洞通告]CVE-2020-7799/FusionAuth存在Freemarker模板注入导致远程命令执行

### 漏洞描述
在FusionAuth 1.11.0之前的FusionAuth中发现了一个问题.经过身份验证的用户被允许编辑电子邮件模板（主页->设置->电子邮件模板）或主题（主页->设置->主题）,可以通过滥用freemarker.template.utility.Execute在服务器上执行任意命令。由于该组件使用了Apache FreeMarker模板引擎,且未对用户输入数据做任何过滤,严重危害服务器安全.该漏洞自带命令回显.

### CVE编号
CVE-2020-7799

### 漏洞威胁等级
由于该漏洞需要使用一定的有效账号登录,亚信安全网络攻防实验室评级为`中危`

### 影响范围
FusionAuth <= 1.11.0
### 漏洞验证
使用payload进行验证
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/c387ef0a-a319-7cd7-8a57-4be38f5cd150.png)
### 修复建议
升级至官方最新版本1.14.0
### 时间轴
[0] 2020/01/28 NVD发布该漏洞
[1] 2020/02/02 亚信安全网络攻防实验室分析&复现该漏洞并发布漏洞通告
### Reference
https://cxsecurity.com/issue/WLB-2020010208
https://nvd.nist.gov/vuln/detail/CVE-2020-7799
https://lab.mediaservice.net/advisory/2020-03-fusionauth.txt
https://fusionauth.io/
https://freemarker.apache.org/
https://www.mediaservice.net/
Mac + IntelliJ IDEAでJUnit5が動くようになるまでの手順メモ

<font color="red">※色々とアレなので参考にしないでください。JDKはSDKMAN!とか使って入れたほうがいいですし、IDEAでGradleプロジェクトを作ればほとんど自動でやってくれます</font>

# はじめに
タイトルの通りの雑多なメモです。個人的な備忘録なので、画面キャプチャもない手抜き記事です。
また、「こうやったらできたよ」という内容なので、もっといい方法があるかもしれません。

## 環境
* macOS Catalina

# 内容
## JDKのインストール
もともと入っていたので今回作業をしてないですが、以下のような手順でやった覚えがあります。
まずHomebrewをアップデートします。

```
$ brew update
```

次に下記コマンドでインストール(現時点で最新版のJava13がインストールされる)。

```
$ brew cask install java
```

## IntelliJ IDEAのインストール
もともと入っていたので（ｒｙ
公式サイトからインストーラをダウンロードして、ポチポチやるだけだと思うので省略してもいいですよね？いいってことにしよう。

## Gradleのインストール
下記コマンドでインストールします。

```
$ brew install gradle
```

が、既に入っていると怒られたので下記で再インストールしました。

```
$ brew upgrade gradle
```

## IntelliJ IDEAでプロジェクトの作成
「Create New Project」からプロジェクトを作成します。Project SDKにはさっきインストールしたJDKを指定します。
あとは特に変更せずにNextボタンをポチポチ押していって、最後のProject nameに好きな名前を付けてFinishボタン押下で終了です。

## ソース階層の作成
もともとあるsrcディレクトリの下にmain/javaディレクトリとtest/javaディレクトリを作成します。
そしてFile -> Project Structure... -> Modulesを開き、上で作ったmain/javaディレクトリ（mainディレクトリの下のjavaディレクトリ）を選択し、画面上のMark as: でSourcesを選択します。また、もともとあったsrcはSourcesを外します。
同様に、test/javaディレクトリ（testディレクトリの下のjavaディレクトリ）でTestsを選択します。

## build.gradleの作成
プロジェクトディレクトリの直下に下記のようなファイルを作成します。JUnit5の依存性解決が目的ですが、現時点で最新の5.6.0を指定しました。

```build.gradle
apply plugin: 'java'
apply plugin: 'idea'

repositories {
    mavenCentral()
}

test {
    useJUnitPlatform {
        includeEngines 'junit-jupiter'
    }
}

dependencies {
    testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.6.0'
    testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.6.0'
}

```

## Gradle Wrapperの作成
IDEA上のターミナルから下記コマンドを実行します。現時点で最新の6.1.1を指定しました。

```
$ gradle wrapper --gradle-version=6.1.1
```

## 依存性の解決
下記コマンドを実行し、しばらく待ちます。ここまでできれば、JUnit5を動かせるようになっているはずです。

```
$ ./gradlew idea
```

## 動作確認
適当なJavaクラスを作ります。ここでは下記のようなクラスを作りました。

```Calc.java
package com.github.dhirabayashi.calc;

public class Calc {
    public int add(int x, int y) {
        return x + y;
    }
}
```
できたら、メソッド内にマウスポインタを移動させて右クリック -> Go To -> Test -> Create New Test...を選択します。
Testing libraryにJUnit5が選択されているのを確認し、OKを押下するといい感じにJUnit5のテストクラスの雛形を作ってくれます。
今回はそれをもとに下記のようなテストクラスを作りました。

```CalcTest.java
package com.github.dhirabayashi.calc;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalcTest {
    @Test
    public void testAdd() {
        var calc = new Calc();
        assertEquals(5, calc.add(2, 3));
    }
}
```
これで右クリックからテストを実行し、成功すればOKです。また、値を変えて失敗することも確認しましょう。

# 参考
[MacのBrewで複数バージョンのJavaを利用する + jEnv](https://qiita.com/seijikohara/items/56cc4ac83ef9d686fab2)
[Gradle wrapper のバージョン更新についてのメモ](https://qiita.com/nobuoka/items/09cbdcd4716b930abdc4)
[No tests found for given includes Error, when running Parameterized Unit test in Android Studio](https://stackoverflow.com/questions/30474767/no-tests-found-for-given-includes-error-when-running-parameterized-unit-test-in)
[Gradle4.6 からの JUnit5 実行方法](https://mike-neck.hatenadiary.com/entry/2018/03/02/073000)
Camera２APIを使用する時に見落としてたこと

Android5.0以降ではCamera２APIを使用することになっていますが、カメラのパーミッションを取ることを忘れていて、３、４時間くらい悩みました。

アプリを実行してもスクリーンに何も表示されませんでした。

 //パーミッションチェック

        try {
            if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                //ここを記述していないで、苦戦した
                final int REQUEST_CODE = 1;
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{
                        Manifest.permission.CAMERA
                }, REQUEST_CODE);
                return;
            }
            manager.openCamera(selectedCameraId, mStateCallback, yBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

皆さんは、お忘れなく！

camera2APIのソースです。https://github.com/Tetsuya922/camera2
こちらの記事を参考にさせていただきました。https://woshidan.hatenablog.com/entry/2017/09/06/083000