OmniAICreator/Qiita-1.07M huggingface dataset:
Python3.6.10でDeepFloorPlanを動かしてみた

# はじめに
ICCV2019で発表された「Deep Floor Plan Recognition Using a Multi-Task Network with Room-Boundary-Guided Attention」(以下、DeepFloorPlan)をpython3版に書き直して動かしてみました。[[paper](https://openaccess.thecvf.com/content_ICCV_2019/papers/Zeng_Deep_Floor_Plan_Recognition_Using_a_Multi-Task_Network_With_Room-Boundary-Guided_ICCV_2019_paper.pdf), [github](https://github.com/zlzeng/DeepFloorplan), [github(python3版)](https://github.com/c-makitahiroki/DeepFloorplan)]

タスクが具体的でビジネス的なニーズがありそうだなと思って気になってました。
今回の記事では、DeepFloorPlanについて簡単に紹介した後、デモプログラムを動かしてみた結果を書いてみます。
学習プログラムを動かした結果なども今後追記予定です。


# DeepFloorPlanとは
一言で言うと「**部屋の間取りを認識する**」DNNです。
![deepfloorplan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268929/030b3548-1197-2bdb-b728-d67987a62be8.png)
部屋の境界予測タスク、部屋タイプ予測タスクごとにデコーダを分けているのが特徴的です。
また、部屋タイプ予測には部屋の境界情報をアテンションとして使用しています。

ネットワーク自体は割とシンプルですが[PSPNet](https://arxiv.org/pdf/1612.01105v2.pdf)や[DeepLabV3+](https://arxiv.org/pdf/1802.02611.pdf)よりも良い性能が出ています。
![deepfloorplan_eval.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268929/91cc5cc6-08d1-c712-1427-31f15c3531fa.png)


# 実行環境
OS: windows10 64bit
GPU: GeForce GTX1060 6GB

# デモプログラム実行結果
学習済みのモデルを使用してデモプログラムを動かしてみました。
ここでは、推論が比較的うまく出来ている例とそうでない例を挙げてみたいと思います。

## 推定できている例
![うまくいっている例.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268929/047ffb2a-4f45-8b4a-451e-78642aa2708a.png)
ホール部分が一部クローゼットやトイレと認識されていますが、背景と各部屋タイプ、ドアと窓まで比較的正しく認識されています。

## 推定できてない例
![うまくいっていない例.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268929/84ed7b0b-2047-2dc9-aebf-690c62a15605.png)
バルコニーとダイニングルームの境界が正しく認識されていません。ドアのタイプが少し特殊なのが影響していそうです。
また、このデータでは背景と部屋の境界が一部正しく認識されていません。入力画像の背景部分に図面の注釈が入っているのが原因っぽいです。

## 考察
この他いくつかのデータを見てみましたが、以下の点が難しそうです。

* ドアのタイプが特殊なもの
* 背景部分に注釈や寸法が入っている
* 部屋の形がいびつなもの（単純な矩形ではなく、円形や台形のような部屋）

この辺を対処するような改良を今後加えてみたいと思います。

# 学習プログラム実行結果
改良して結果を含めて後日追記したいと思います。
精度改良案があれば是非是非コメントお願いします！
MJPG-streamerのストリーミング映像をcanvasタグに描画する

## はじめに

MJPG-streamerのストリーミング映像をcanvasタグに描画するスクリプトを書いたので忘れないようメモ

※canvasじゃなくてvideoタグへの描画はこれ→[MJPG-streamerのストリーミング映像をvideoタグに描画する](https://zenn.dev/zgw426/articles/ed632c88148183e9b902)

## 実行画面

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">実行画面 <a href="https://t.co/G5o0GgftJl">pic.twitter.com/G5o0GgftJl</a></p>&mdash; j4amountain (@zsipparu) <a href="https://twitter.com/zsipparu/status/1310715785816338432?ref_src=twsrc%5Etfw">September 28, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## ソース

作ったソース

```html:sample.html
<html>
<head>
    <title>(sample) MJPG-streamer -> CANVAS Tag</title>
</head>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');

function render() {
    const image = new Image();
    image.onload = function(){
      canvas.getContext("2d").drawImage(image, 0, 0, 400, 400);
    }
    // ↓ MJPG-streamerの静止画像をロード
    image.src = "http://xxxxxx:xxxx/?action=snapshot";
    requestAnimationFrame(render);
}
render();
</script>
</body>
</html>
```

## 補足

- MJPG-streamerは、ラズパイで実装。
- 先ほどのソース(sample.html)は、別にWebサーバーを立ててそこに置く
- ラズパイにMJPG-streamerをインストールする手順 → [リンク](https://qiita.com/zgw426/items/2ae5527869dc13d038a9)
- ↓ は、MJPG-streamerのストリーミング実行のコマンド

```console
$ /usr/local/bin/mjpg_streamer -i "input_raspicam.so -x 400 -y 400 -fps 15 -q 80" -o "output_http.so -p 8090 -w /usr/local/share/mjpg-streamer/www" 
```
IFTTTのおすすめアプレットサイトまとめ

自分の備忘録として、今回調べた、
おすすめアプレットのサイトをまとめておきました。


【超便利】IFTTTのアプレット・レシピおすすめ21選
https://www.webhack.jp/gadgets/21-recommended-applet-recipes-for-ifttt/


IFTTT（イフト）の使い方を解説！おすすめのサービス連携アプレット（レシピ）もご紹介
https://www.hiwell.co.jp/promotion/column/ifttt/


サーヴィス同士をつなげて便利、IFTTTのオススメレシピ15選
https://www.gizmodo.jp/2014/07/ifttt15.html


生活が便利になるIFTTTのレシピ16
http://the-path0126.com/blog-entry-352.html


IFTTT おすすめアプレット5選【LINEと連携で便利！】
https://vacks.paid.jp/?p=4417
漫画『ハルロック』の『ぼっち・ザ・LED』をIFTTTとobnizで作ってみた


今年もMakerFaire東京の季節がやってきました。
（普通は夏ですけど）


MakerFaire東京といえば、メイカー漫画の金字塔『[ハルロック](https://comic-days.com/episode/10834108156631542126?_ga=1.34872553.957165489.1477316788)』を思い出します。

主人公ハルちゃんの作品はどれも面白いものばかりですが、なかでも大好きなのが、単行本１巻に登場する『ぼっち・ザ・LED』です。

「ぼっち」という言葉を含むツイートの位置情報から世界地図の該当箇所にLEDを光らせて、世界中のぼっちを可視化するシステムです。


<br>
というわけで、MakerFaireに落選した私は出場できないかわりに、『ぼっち・ザ・LED』を作ってみました。

といっても、超簡単版です。
僕が作ったのは、日本語で「ぼっち」とつぶやいた人がいた場合に手元のLEDが光るだけです。




##システム

###構成図
世界のどこかで「ぼっちなう」とTwitterで投稿されると、IFTTTよりWebhookでobnizに知らされ、LEDが光るという、ただそれだけの仕組みです。

[![Image from Gyazo](https://i.gyazo.com/5edf7f1ae6297c399b5dc4f2a0d4e119.png)](https://gyazo.com/5edf7f1ae6297c399b5dc4f2a0d4e119)


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【一週一創】ぼっちは僕だけじゃない！この世にぼっちがいたらLEDで教えてくれるマシーンを作りました。<br>〜漫画『ハルロック』の『ぼっち・ザ・LED』をIFTTTとobnizで作ってみました。<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/%E3%83%8F%E3%83%AB%E3%83%AD%E3%83%83%E3%82%AF?src=hash&amp;ref_src=twsrc%5Etfw">#ハルロック</a> <a href="https://twitter.com/hashtag/obniz?src=hash&amp;ref_src=twsrc%5Etfw">#obniz</a> <a href="https://twitter.com/hashtag/%E4%B8%80%E9%80%B1%E4%B8%80%E5%89%B5?src=hash&amp;ref_src=twsrc%5Etfw">#一週一創</a><br>作り方はこちら　→ <a href="https://t.co/ppgeQJUe7e">https://t.co/ppgeQJUe7e</a> <a href="https://t.co/2jy3rRmQEr">pic.twitter.com/2jy3rRmQEr</a></p>&mdash; たつや (@tatsuya1970) <a href="https://twitter.com/tatsuya1970/status/1310875670738694145?ref_src=twsrc%5Etfw">September 29, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<br>
~~本当は、obnizのディスプレイに元のツイートの投稿を表示させたかったですが、以下のQiitaの別記事のとおり、なぞの文字化けにより断念しました~~ 

[（解決済み）【obniz】webhookで始動した時のディスプレイは文字化けするようだ](https://qiita.com/tatsuya1970/items/54864a4a55191dac266a)

~~解決方法があれば、教えてください~~ 


<br>

##IFTTTの設定

[IFTTT](https://ifttt.com/home)　でのTwitterの設定をします。
URLは、obnizのウェブサイトから入手できるwebhookのURLです。

[![Image from Gyazo](https://i.gyazo.com/63c88e1f92559120b6e2095af88f8707.png)](https://gyazo.com/63c88e1f92559120b6e2095af88f8707)

##コード (obniz)
ただのLチカです。

```obniz.html
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
    <script src="https://unpkg.com/obniz@3.8.0/obniz.js" crossorigin="anonymous"></script>
</head>

<script>
    const obniz = new Obniz("YOUR OBNIZ ID");
    obniz.onconnect = async () => {

  let content = req.body.content; //contentはツイート内容
  obniz.display.clear();
  obniz.display.print(content); //contentはツイート内容をディスプレイに表示

  var led = obniz.wired("LED", {anode:0, cathode:1});
  led.on();
  
  setTimeout(function(){
    led.off();
    obniz.display.clear(); 
  }, 5000);

};

</script>

</html>
```
<br><br>
##ぼっちなのは僕だけじゃない
<br>
感覚的に１０分に１回は、ぼっちツイートがあります。
LEDが点灯するたびに、
「ぼっちなのは僕だけじゃないんだ」
って慰められます。
<br>

>ぼっち・ザ・LEDを見ると
私だけじゃなく今日の世界にはぼっちがいて・・・
そうやって心を慰めるのもいいけど、
一歩踏み出して
ぼっちのパーセンテージを減らすのも
いいことだと思う。

>（ハルロック６話「ぼっち惑星」より）

<br>
タスク管理ツールTrelloの今日のタスクを自動でGoogle Calendarに同期させる

# TrelloのtodoをGoogle Calendarに同期させたい

私のタスク管理方法
・Trelloで仕事の全体像を管理
・毎朝、Trelloを確認して、ざっくり今日のタスクを決める
・Google Calendarに細かく細分化して時間管理

という感じで、最近はやってました。

特に問題はなかったんですが、よく考えれば、Trelloに書いてるタスクをGoogle　Calendarに二重に書いているところがあるので、これを自動化できた方がいいかなと思い、調べてみました。


# IFTTTを使えば簡単に設定できる

どうやら簡単にできるようです。

IFTTTの使い方については、前に書いた記事の中でも書いたので、こちらをご覧ください。

https://qiita.com/kaiser355/items/ad9357fb3dfe4ab22827

だいたいの使い方はこれでわかるはず。

## まずトリガーの方をTrelloにして設定する

IF this（トリガー）に、Trelloを選択。

Card added to list（特定のリストにカードが追加された時）
を選択し、

[![Image from Gyazo](https://i.gyazo.com/0fda92aeda3af5848263a8cd96eeab45.png)](https://gyazo.com/0fda92aeda3af5848263a8cd96eeab45)

どのリストにするかを選択します。


## アクションの方をGoogle Callendarに設定する

私は、右側のdetailed eventにしてみましたが、シンプルにQuick add eventでもいいかもしれません。

[![Image from Gyazo](https://i.gyazo.com/767344ddf893aad570d20e9265e9d879.png)](https://gyazo.com/767344ddf893aad570d20e9265e9d879)

入力したら、設定完了。


# こんな感じで同期されます

すると、こんな感じで同期してくれます。

![image30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664861/05665170-58b2-8b61-f749-441304930054.png)


Google Calendar

[![Image from Gyazo](https://i.gyazo.com/ab2b13002a5e08c3b8e2fe900570fcf5.png)](https://gyazo.com/ab2b13002a5e08c3b8e2fe900570fcf5)

僕の場合は、これができると、Macの純正カレンダーにも同期されるので、
純正カレンダーでタスクの細分化とスケジューリングで使いやすくなります。


# これでスケジュール管理もバッチリ

Trelloでは使いこなせば、スケジュール管理も色々できるようです。
ただ私の場合は、仕事の全体像を一画面で見渡せるようにできれば十分なため、細かいスケジュール管理はGoogleカレンダーで同期できれば、良いです。

ちょっとは楽になったかも。


## もし気に入ったいただけたら、LGTMお願いしまーす！
node+dockerでbcryptしたら、エラーおきた

# dockerとnodeの環境でbcryptライブラリを使ったときのエラー
dockerでnodeでbcryptを使うとエラーが起きます。
node_modulesをコピーしてしまうとエラーが起きるので、.dockerignoreを使いましょう

## dockerignoreを使いましょう
```bash:tree
.
├── Dockerfile
├── app.js
├── node_modules
├── package-lock.json
├── package.json
└── .dockerignore ←これを追加
```

```:.dockerignore
node_modules/
```

### ちなみにDockerfileはこんな感じ
```
FROM node:12
WORKDIR /usr/src/app

COPY package.json ./
COPY package-lock.json ./
RUN npm install

COPY . .

CMD [ "npm", "start" ]
```
【Ruby】メソッドジャンプをしたい！

### はじめに

>環境macOS Catalina10.15.5

Rubyで他の人が書いたソースコードを読むときにメソッドの定義場所がすぐわかるようにメソッドジャンプがしたいなと思い、いろいろ試してたどり着いた方法を書き記します

私はテキストエディタはAtomを主に使っていたのですが、RubyのコードをAtomでメソッドジャンプするのは、いろいろ試しましたがうまくいきませんでした、なので

####結論 VSCodeを使うのが簡単

という事になりまりました

###導入手順

####1.こちらでVSCodeをダウンロード
https://azure.microsoft.com/ja-jp/products/visual-studio-code/



####2.日本語化

- メニューバーからviewを選択
- command palette を選択
- configure display languageを選択
- install additional languageを選択
- Japanese Language Pack for Visual Studio Codeのパッケージを探す
- もう一度configure display languageを選択
- jaを選択
- VSCode再起動

####3.パッケージのRubyをインストール
拡張機能の検索ボックスで検索できます

####4.ジャンプの機能を有効化
インストールしたRubyの拡張機能の設定を開いて
Ruby:Intellisenseのところをfalseからrubylocateに変更

####5.メソッドジャンプのやりかた
⌘を押しながらジャンプしたいメソッドをクリックすると定義場所にとべます！

ここまで１５分程度だったのでとても簡単でした！
【PHP初心者向け】MySQLからSQL文で絞り込み、結果をサイトに表示する

##0.概要

デザイナーをやっていると、静的なサイトは作れるものの、
動的なサイトを作る時にはエンジニアに頼むことが多く、
自身で完結できないことが歯痒い時があります（実体験）。

そこで今回は、
データベース（今回はMySQL）に保存したデータを、
条件によって動的に出し分け（PHPで、SQLのクエリを書く）、
サイトに表示する方法を記載いたします。

##1.はじめに（データベースの準備）

まず最初に、データベース自体にデータを入れます。
借りてるレンタルサーバーのコントロールパネルから、
phpMyAdminにログインするか、
データベースをデータベース管理ツールと連携させましょう。

オススメの無料データベース管理ツールは下記の2つです。

|名前|特徴|入手先URL|
|:---|:---|:---|
|DBeaver|クラシカルなUIだが多機能。ER図というDBの繋がりを表示してくれる機能がある。※今回はこれを実例に進めて参ります。|https://dbeaver.io/|
|Metabase|ビジュアライズが充実している。クエリを知らなくともGUI上で色々できるのでデザイナーにも扱いやすい。|https://www.metabase.com/start/oss/jar|

※導入に関しては他の方が書かれた下記の記事を参考にして下さい。

・ データベースツール DBeaver のインストール（Windows 上） 
https://www.kkaneko.jp/tools/win/dbeaver.html
・MetabaseをWindowsにインストールする
https://qiita.com/n-i-e/items/b721687903055659ee2d

上記いずれかのデータベースにて入れたら、
まずはDB上にテーブル・カラム（項目名）を設定するために、
UI上にてテーブルの設定、カラムの設定、レコードの追加を行って下さい。

ここではDBeaverの画面を参考に進めて参ります。

・テーブルの追加
ツリーでDBをクリックし、ウインドウで開いたら[テーブル]を右クリックし、
[新しく作る 表]をクリックすると設定画面に入り、作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/6ece5920-2ec7-752f-c418-1db124f73dff.png)
・カラムの追加
先程作成されたテーブルを開き、[列]にて、右クリックし、
[新しく作る カラム]をクリックすると設定画面に入り、作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/ffebb8b0-99af-c83f-521c-dc6537c25d7c.png)
・レコードの追加
最後に、今設定されたテーブル・カラムにレコードを追加するため、
SQL文のエディタを開きます。
DBeaverであれば、メニューの[SQLエディタ]から開けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/094e4cd9-6059-8438-b82b-3a825ee3b739.png)

開けたらDB上に新規レコードを追加するクエリを記述しましょう。

```sql
INSERT INTO [DB名].[テーブル名]
([カラム名１], [カラム名２])
VALUES('[カラム名１の値]', '[カラム名2の値]');
```
※[]は削除し、中身をご自身のDBに合わせた文字に変えて下さい。

終了したらテーブルの[データ]にてちゃんと追加されているか確認しましょう。
私の場合は2つのレコードを下記のように入れ、問題ないことを確認しました。
![2020-09-25_023529.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/dda7ce71-976b-cb92-88c9-6242c967d17f.png)

##2.PHP側でのMySQLとの連携

データベースの準備が出来たら、
PHPの読み込むファイル（例えばindex.phpなど）に、
MySQLへ接続するための、情報を記載いたします。

```php
<?php 

// MySQLの接続情報をセット
$db = 'mysql:host=[データベースのホスト名];dbname=[データベース名]';
$user = '[ユーザー名]';
$pass = '[パスワード]';

//接続のテスト
try {
    $pdo = new PDO($db, $user, $password);
    echo "接続に成功しました";
} catch (PDOException $e) {
    echo "接続に失敗しました";
    exit();
}

  //次のステップの時にここにSQLを書く

?>
```

こちらを読み込んでみて「接続に成功しました」と出れば成功です。
接続に失敗しましたと表示された場合は、接続設定を見直してみて下さい。

豆知識・・・PDOはPHP Data Objectが正式名称です。

##3.実際にクエリを書いて反映してみる

先程のphpファイルの、

```
//次のステップの時にここにSQLを書く
```
を書き換えます。

が、SQLを書く際はprepare文とexecute文で前処理をする必要があり、
その記述も合わせて書きましょう。

```sql
// SQLを書く（''の中は任意のクエリを記述）
$sql = 'SELECT [表示項目] FROM [データベース名].[テーブル名] WHERE [条件]';

// prepare文で上記のSQLを定義し、execute文で定義したSQLを実行
$prepare = $pdo->prepare($sql);
$prepare->execute();

// 結果を出力
foreach($prepare->fetchAll() as $result){
  // echo $result['カラム名'];にて出力できる
  }
```

私の場合、クエリにてshop_idがtest1のものに絞り、
2つのカラム（shop_nameとshop_id）をh2要素として表示させたため、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/6222620c-fb26-28ae-8f6f-44398146e5b6.png)
と表示されました。

##4.最後に

今回はクエリをこちら側で書きましたが、
サイト閲覧者に入力してもらうことによって、
ユーザー毎にリクエストした結果を表示することも可能です。

今後、その方法も記事にして行きます。
Terraformのjsonencode関数にはJSONを入れても動くよ

※この記事はTerraform v0.12系で検証してます。

## はじめに

まずはこちらをご覧ください。AssumeRoleを定義したこのコード、assume_role_policyにはjsonencode関数を使っていてその引数としてJSONをベタ書きしています。

```terraform
resource "aws_iam_role" "test_role" {
  name = "test_role"
  assume_role_policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Principal" : {
          "Service" : "ecs-tasks.amazonaws.com"
        },
        "Action" : "sts:AssumeRole"
      }
    ]
  })
}
```


なんとこのコード、ちゃんとApplyできるんです！！
引数にはJSONを渡していますが、これはTerraformのMap型として解釈され、その上でJSONにエンコードされます。

## 何が便利か？

上述の例だと便利さがいまいちなので少しだけマシな例を挙げると

```terraform
resource "aws_iam_role_policy" "test_role_policy" {
  name = "test_role_policy"
  role = aws_iam_role.test_role.id
  policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Action" : [
          "s3:ListBucket"
        ],
        # コメントも書けるし当然変数も埋め込める
        "Resource" : [
          aws_s3_bucket.this.arn
        ]
      },# ケツカンマがあっても動く
    ]
  })
}
```

このような感じでJSONといいつつTerraformのMap型なのでコメントが書けたり変数が埋め込めたり、ケツカンマをつけたりできます。（もちろんカンマなしもOKです）

Terraformのリソースの引数にJSONを入れる方法は幾つかありますが、それぞれ大小問題があります。

- ヒアドキュメントでJSON文字列を定義する
  - コメントを書けない
  - カンマをつけ忘れたりつけすぎるとエラー
  - ネストが崩れて見にくい
- 別ファイルとして定義してfileやtemplate関数で呼ぶ
  - コメントを書けない
  - カンマをつけ忘れたりつけすぎるとエラー
  - テンプレートで変数を埋め込んでるケースだと場合によってはリンターに怒られる
- aws_iam_policy_documentのように専用のデータソースで書く
  - JSONからは離れてしまうのでAWSのドキュメントなどにあるJSONサンプルをコピペできない
  - container_definitionsのようにデータソースが無い場合もある

jsonencode関数にJSONを渡す方法はそれらをいい感じに解決できます。（多分）
- 公式ドキュメントのJSONサンプルをコピペできる
- コメント書ける
- カンマなくてもあってもOK
- ちゃんとネストされる
- どんなリソースでも使える

(多分)と書いたのは、私自身、まだそんなにこの書き方を使っていないので思わぬところでハマりどころがあるかもしれなかもと思ったからです。が、この記事で書いたようなサンプルはちゃんと動くので多分大丈夫でしょう。なんかハマったら追記します！


## なんで動くか

そもそもjsonencode関数はTerraformの値をJSON文字列にエンコードする関数です。
TerraformのMap型はKeyとValueの区切りに＝を使いますが、実は＝の代わりにコロンを使うこともできます。
コロン区切りのネスト可能な{}で囲まれたKey Value、つまりJSONのフォーマットはTerraformの構文中ではMapとして解釈されjsonencode関数によって再びJSON文字列に戻されるのでこの書き方が機能します。

- jsonencode関数のドキュメント
  - https://www.terraform.io/docs/configuration/functions/jsonencode.html
- Map型のドキュメント
  - https://www.terraform.io/docs/configuration/types.html#map-


## おわりに

Terraformのjsonencode関数にはJSONを入れても動いてHappy！！やったね。
FIFOを少しいじってみる

過去の記事においてFIFOの性質を実験的に確かめた。
そこで、本記事において実際にFIFOを動かしてみたいと思う。
この記事を更新するか複数記事に分けて記録する自分用メモである。
~~なお、筆者の心が折れた場合は完結しない可能性がある。~~

まず作成。FIFOはファイルに見えるカーネルバッファへのハンドルだ。
形式上はファイルなので作成権限のあるディレクトリなら作成できる。
ターミナルから作成するにはmkfifoコマンドを使う。

```
user@user-virtual-machine:~/git/fifo$ ll
合計 8
drwxrwxr-x 2 user user 4096  9月 29 02:27 ./
drwxrwxr-x 6 user user 4096  9月 29 02:20 ../
user@user-virtual-machine:~/git/fifo$ mkfifo ./testfifo
user@user-virtual-machine:~/git/fifo$ ll
合計 8
drwxrwxr-x 2 user user 4096  9月 29 02:35 ./
drwxrwxr-x 6 user user 4096  9月 29 02:20 ../
prw-rw-r-- 1 user user    0  9月 29 02:35 testfifo|
user@user-virtual-machine:~/git/fifo$ 
```

pがパイプであることを示し、デフォルト属性は664のようだ。
形式上はファイルなので削除もできる。

```
user@user-virtual-machine:~/git/fifo$ ll
合計 8
drwxrwxr-x 2 user user 4096  9月 29 02:35 ./
drwxrwxr-x 6 user user 4096  9月 29 02:20 ../
prw-rw-r-- 1 user user    0  9月 29 02:35 testfifo|
user@user-virtual-machine:~/git/fifo$ rm ./testfifo 
user@user-virtual-machine:~/git/fifo$ ll
合計 8
drwxrwxr-x 2 user user 4096  9月 29 02:38 ./
drwxrwxr-x 6 user user 4096  9月 29 02:20 ../
user@user-virtual-machine:~/git/fifo$ 
```

プログラムからも作成可能。

```f1.cpp
#include	<bits/stdc++.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<fcntl.h>
#include	<unistd.h>

int main(int argc, char* argv[])
{
	//ブロックされないようにNONBLOCK指定で開く
	int fd = open("./testfifo", O_RDONLY | O_NONBLOCK);
	if(fd > 0) {
		printf("./testfifo is already exist.\n");
		close(fd);
	} else {
		int ret = mkfifo("./testfifo",
			S_IRUSR | // ユーザリード権限
			S_IWUSR | // ユーザライト権限
			S_IRGRP | // グループリード権限
			S_IWGRP | // グループライト権限
			S_IROTH   // 他人にリード権限
		);
		if(ret == 0) {
			printf("./testfifo is created successful.\n");
		} else {
			printf("./testfifo is create failed.\n");
		}
	}
	return	0;
}
```

実行するとこうなる。

```
user@user-virtual-machine:~/git/fifo$ ll
合計 32
drwxrwxr-x 2 user user  4096  9月 29 02:59 ./
drwxrwxr-x 6 user user  4096  9月 29 02:20 ../
-rwxrwxr-x 1 user user 16920  9月 29 02:55 f1*
-rw-rw-r-- 1 user user   732  9月 29 02:55 f1.cpp
user@user-virtual-machine:~/git/fifo$ ./f1 
./testfifo is created successful.
user@user-virtual-machine:~/git/fifo$ ll
合計 32
drwxrwxr-x 2 user user  4096  9月 29 02:59 ./
drwxrwxr-x 6 user user  4096  9月 29 02:20 ../
-rwxrwxr-x 1 user user 16920  9月 29 02:55 f1*
-rw-rw-r-- 1 user user   732  9月 29 02:55 f1.cpp
prw-rw-r-- 1 user user     0  9月 29 02:59 testfifo|
user@user-virtual-machine:~/git/fifo$ ./f1
./testfifo is already exist.
user@user-virtual-machine:~/git/fifo$ 
```

とりあえずはここまで。
Dockerを使ってPrivoxy＋Torの環境を一瞬で作る

## はじめに

Dockerを使うとPrivoxy + Torの環境を簡単に立ち上げられます。基本的に下記の公式ページを読めばわかる内容ですが、Dockerの便利さを実感できたので記事にします。

[dperson/torproxy](https://hub.docker.com/r/dperson/torproxy/)

なお今回は`dperson/torproxy`のイメージを利用していますが、Privoxy + Torのイメージは検索するといくつか見つかります。他は試していませんが、今回紹介するような簡単な要件ならばどれを使っても同じように可能だろうと思います。

## Privoxy + Torをなぜ使うか

LinuxではTorを導入して起動するだけで、デフォルト設定だとローカルホストの9050番ポートにSOCKS5プロキシが立ち上がり、そのプロキシを使うことでTor経由のWebアクセスが可能となります。  
しかし、curlなどによるアクセスなら良いのですが、場合によってはHTTPプロキシは使える一方でSOCKSプロキシを直接使えないことがあります。  
その場合はPrivoxyとTorを組合わせて利用することになります。適切な設定をすると、PrivoxyによるHTTPプロキシ（デフォルトでは8118番ポート）を経由することでPrivoxy→Tor→Webサイトのような流れのアクセスが可能になります。  
具体的な設定方法はたとえば次のようなページで紹介されています。

[4.10. How do I use Privoxy together with Tor?](https://www.privoxy.org/faq/misc.html#TOR)

これはこれで問題はないのですが、Privoxyをインストールして設定ファイルを書き換えるなどするのはそれなりに面倒です。  
Privoxyがローカルに残ってしまうのも少し気持ち悪いです。  
Dockerで環境を立ち上げればそれらの問題を解決できます。

## dockerコマンド

### 起動

次のようなコマンドでPrivoxy + Torのコンテナを起動します。

```Docker
docker run -it -p 8118:8118 -p 9050:9050 -d dperson/torproxy
```

`-p 8118:8118`はポートのバインドを指定しています。  
`-p ホスト側ポート:コンテナ側ポート`のような記法です。  
したがってすでにホストの8118番ポートが使用されている場合は

```Docker
docker run -it -p 8119:8118 -p 9050:9050 -d dperson/torproxy
```

のようにポート番号を使われていないものに変更すれば大丈夫です。
また、`-p 9050:9050`はTorのSOCKSプロキシに接続するためのポートなので、もしHTTPプロキシのみが必要な場合は、

```Docker
docker run -it -p 8118:8118 -d dperson/torproxy
```

のように9050番ポートの設定を省略すればHTTPプロキシのみホストからアクセスできる状態で起動します。

### 動作確認

curlで動作確認を行います。

```console
curl -L ipinfo.io
```

このように[ipinfo.io](https://ipinfo.io)にcurlでアクセスすると接続元のIPなどが表示されます。プロキシを何も設定しないと当然自宅のIPアドレスが表示されるはずです。

コンテナを`docker run -it -p 8118:8118 -p 9050:9050 -d dperson/torproxy`のコマンドで起動し、8118番ポートでPrivoxyのHTTPプロキシにアクセスできる場合は次のようなコマンドでプロキシ経由のWebアクセスを行います。

```console
curl -Lx localhost:8118 ipinfo.io
```

（-xオプションでプロキシを指定します）  
コンテナが起動し、正しくプロキシ経由のアクセスできている場合は自宅のものとは違うIPアドレスが表示されるはずです。

同様にSOCKSプロキシも確認します。

```console
curl -Lx socks5h://localhost:9050 ipinfo.io
```

このコマンドでTor経由のアクセスになっていることを確認できるはずです。

:::note info
もし`ipinfo.io`に接続できなければ`https://check.torproject.org/api/ip`を代わりに試してみてください（最近`ipinfo.io`がTorのアクセスをブロックするようになったかもしれません）
:::

### 終了する

次のコマンドで立ち上がっているコンテナを確認します。

```console
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                 PORTS                                                      NAMES
ae9565085d51        dperson/torproxy    "/sbin/tini -- /usr/…"   8 hours ago         Up 8 hours (healthy)   0.0.0.0:8118->8118/tcp, 9050/tcp, 0.0.0.0:9050->9050/tcp   inspiring_brahmagupta
```

ここで`CONTAINER ID`もしくは`NAMES`を確認し、次のコマンドの引数にします。

```Docker
docker stop ae9565085d51
```

`docker stop`の引数に`CONTAINER ID`もしくは`NAMES`を指定します。
これでコンテナが停止します。
githubでローカルからリモートへpushしようとしたら'fatal: Could not read from remote repository.'のエラー

commitも終わりgithubへpushをしようと思ったところエラーが起きました。
また、起こるであろう時に備えて備忘録です。

#### 追記：2021/5/28
毎回`ssh-add -K ~/.ssh/id_rsa`打つの大変だよねって思う。
そう言う時はvimに設定すれば良い。
自分はzshrc使っているので下記コマンドですが、bashの方はbashでvim入って記述すればOKです。

```ターミナル:ターミナル
 vim ~/.zshrc
```
`i`を押すとinsertモードになるので

`ssh-add -K ~/.ssh/id_rsa`を追記。

`esc`→`:wq`エンター

これで設定完了です。パスが通りました。
念の為、物理的にターミナルを再起動かコマンドで再起動して更新完了です。
確か`source ~/.zshrc`だったと思います。
[参照](https://www.webdesignleaves.com/pr/plugins/mac_terminal_basics_03.html)


## 環境
macOs Catalina(10.15.4)
エディター (VSCode)
iTerm2 (Build 3.3.12)

commitはVScodeから作業済み

## エラーの原因
リモートリポジトリへpushしようとしたところ以下のエラーが起きた。
`'fatal: Could not read from remote repository.'`

「リモートリポジトリからの読み込みできない（「SSH 通らん」）」ってエラーなので
下記のコマンドが有効です。(git cloneもmysqlもSSHが通らない時は同様)
`ssh-add -K ~/.ssh/id_rsa`
これはざっくり言うと秘密鍵(id_rsa)をsshに通すよというコマンド。
(ただし、githubに鍵を登録していることが前提です。)

## ①gitのどのブランチ（またはmaster）にいるか確認

`git status`を入力しpushしたいブランチになっているか確認します。

```javascript:ターミナル
On branch ブランチ名
```
問題なければコミットします。（自分はVSCodeから行いました）
異なっていればチェックアウトしてブランチを移動します。

## ②SSHのパスを通す
`ssh-add -K ~/.ssh/id_rsa`

```javascript:ターミナル
//これが出たらOK
Identity added: /Users/pc名/.ssh/id_rsa (pc名@MacBookの名前.local)
```

## ③ブランチへpush
`git push origin ブランチ名`
これでpush完了。

## 備考
push前、リポジトリの場所がoriginでいいか心配になったら
`git remote -v `
これでリポジトリがoriginかどうかわかる

```tarminal:ターミナル
origin	git@github.com:省略.git (fetch)
origin	git@github.com:省略.git (push)
```
https://qiita.com/seri1234/items/e651b3e108a695a92809

## 終わりに
今まではスクールで押していた`githubDesktop`でcommitもpushも行ってましたが、
コマンドで行うよう変更いたしました。
使い慣れないですが一つずつの工程を理解しながら作業するようにしたいと思います。
初学者なため記述の不備やアドバイスなどご指摘、ご教示頂ければ幸いです。
最後までご拝読いただき、ありがとうございます。
constの再代入禁止とオブジェクトの凍結



変数宣言時に`const`を使えば変数への再代入を防ぐことができます。

```js:sample
const con = 1000;
con = 500;

// エラー発生 Uncaught TypeError: Assignment to constant variable.
```

`const`であってもオブジェクトのプロパティの変更や追加削除を防ぐことはできません。

```js:
const con = {
  prop1: 'p1',
  prop2: 'p2',
};

con.prop1 = 'p3';
con.prop3 = 'p3';
console.log(con); // {prop1: "p3", prop2: "p2", prop3: "p3"}
```

`Object.freeze`を使うことでプロパティに変更や追加を防ぐことができます。

```js:
const con = {
  prop1: 'p1',
  prop2: 'p2',
};

// オブジェクトを凍結
Object.freeze(con);

con.prop1 = 'p3';
con.prop3 = 'p3';
console.log(con); // {prop1: "p1", prop2: "p2"}
```

`Object.freeze`の凍結は対象のオブジェクトだけです。より深いオブジェクトは凍結されないので注意。

```js:
const con = {
  prop1: 'p1',
  prop2: 'p2',
  deep: {
    prop4: 'p4'
  }
};
Object.freeze(con);

con.deep.prop4 = 'p5';
console.log(con); // {prop1: "p1", prop2: "p2", deep: { prop4: "p5"}}
```
Javascriptの変数宣言varとconstとletをわかりやすくサンプル付きで説明解説

Javascriptの変数宣言は、
下記のように複数あります。（var,const,let）

```
var HENSU = 'あいうえお';
const HENSU = 'あいうえお';
let HENSU = 'あいうえお';
```

JS覚えてたての場合、人が書いたコードで複数の種類が登場して
訳がわからなくなると思いますので、なるべくわかりやすく
まとめておきます。実際に動かした実験結果も動画で紹介します。

この変数宣言については、ECMAScript2015から
定義されている国際標準仕様です。
※昔は無かったものもあるのでより混乱しやすいですね

##まとめ：
先に簡素にまとめます。後ほど動画付きで説明します。

**var** →　再宣言、再代入が可能
**const**　→ 再宣言、再代入が禁止
**let**　→ 再宣言は禁止、再代入は可能

補足：
・再代入：変数の値を入れ直す事
・再宣言：再度明示的にvar/const/let〇〇と変数を宣言する事

★変数を後でどう使うか？を考えて宣言すればOKですね！
　正直すべてvarだけでも動作させられますが、明示的にする事で、
　人が書いたものでも意図が分かってきますし、
　エラーを起こしにくくなります。

##var：再宣言も再代入もOKな柔軟な宣言
例では、HOTKEYWORDという変数の中身を、
宣言を入れたり入れなかったりして
2度ほど変えていますが問題なく動作します。
　![var-case.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570700/475d3398-9f9f-b305-4224-fb256171ee41.gif)

##const：再宣言、再代入が禁止という厳格な宣言
例(NGケース）ではあえて再宣言や再代入を試みますが、
初回の宣言だけ成功し、その後の記述はエラーで動作しません。
![const-case.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570700/f628573e-3875-4c18-f495-355b76e68433.gif)

##let:再代入は可能、再宣言は禁止という中間の存在
例では代入は成功しています。わざと3回宣言してみたところ
エラーで動作しなくなりました。
![let-case.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570700/5c7695ca-bce1-039d-9161-4905d70c4e09.gif)

##最後に
こうして実験してみると思った以上に厳格な部分があると
わかりました。

例では下記のようにあえて数回宣言したり、
直接文字列を代入していますが、
実務上では「可変させたいものとそうでないもの」があると
思います。また、「同じ変数名使ってしまうミス」も減るはずです。

特徴を捉えてミスなく素早く第三者にもわかりやすい
コードにしていきたいですね。

```
var HOTKEYWORD = "倍返し";
alert(HOTKEYWORD);
HOTKEYWORD = "恩返し";
alert(HOTKEYWORD);
var HOTKEYWORD = "土下座";
alert(HOTKEYWORD);
```

実際に動作するサンプルも用意しましたので
手で動かしてみたいかたはどうぞ★
（もちろんコピペも自由です）

サンプルページ：
http://allcountry.sakura.ne.jp/biz/code/javascript/20201001/const.html
Swift：配列に初期要素を複数セットする時の罠

配列に初期要素を複数セットする方法はいくつかある。

```swift
class Hoge {
    var num: Int
    init(num: Int) {
        self.num = num
    }
}

// 方法1
var array1: [Hoge] = [
    Hoge(num: 0),
    Hoge(num: 0),
    Hoge(num: 0)
]

// 方法2
var array2 = [Hoge]()
for _ in (0 ..< 3) {
    array2.append(Hoge(num: 0))
}

// 方法3
var array3: [Hoge] = (0 ..< 3).map({ _ -> Hoge in
    return Hoge(num: 0)
})

// 方法4
var array4 = [Hoge](repeating: Hoge(num: 0), count: 3)

// 他にもあるかも
```

ここで方法4に注目すると、repeatingに初期要素、countに要素数を渡すことでいい感じに初期化ができそうだが、他の3つの方法と違う点がある。

```swift
// 方法1で要素同士を比較してみる
print(array1[0] === array1[1]) // -> false
print(array1[1] === array1[2]) // -> false
// 結果は方法2,3も同様

// 方法４で要素同士を比較してみる
print(array4[0] === array4[1]) // -> true
print(array4[1] === array4[2]) // -> true
```

方法4では全て同じオブジェクトを指すことになっている。classのインスタンスをrepeatingに渡すと全く同じものを繰り返し配列に詰めてしまう。
[Android] プロフィール画像とかでよく見る画像を丸にくり抜くやり方 [メモ]

#はじめに
プロフィール画像とかでよく見る、画像を円型に表示させる方法。色々なやり方があると思うが、今回はMaterial ComponentのShapableImageViewを使います。

# 目標
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289190/365e6a83-6cf7-311c-4121-3750facb1d8a.png  width=150>

#Gradle
```gradle
implementation 'com.google.android.material:material:1.2.1'
```

# 実装
`shapeAppearanceOverlay`属性に任意のスタイルを当てはめると簡単に円型やひし形などカスタマイズできます。

```xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="@color/black"
    >
    <!--   円 -->
    <com.google.android.material.imageview.ShapeableImageView
        android:id="@+id/circle"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:scaleType="centerCrop"
        android:layout_marginTop="80dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toStartOf="@id/rhombus"
        app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.Circle"
        app:srcCompat="@drawable/test"
        />
    <!--   ひし形 -->
    <com.google.android.material.imageview.ShapeableImageView
        android:id="@+id/rhombus"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:scaleType="centerCrop"
        android:layout_marginTop="80dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/circle"
        app:layout_constraintTop_toTopOf="parent"
        app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.Rhombus"
        app:srcCompat="@drawable/test"
        />

</androidx.constraintlayout.widget.ConstraintLayout>
```

```xml
    <style name="ShapeAppearanceOverlay.App.Circle" parent="" >
        <item name="cornerSize">50%</item>
    </style>

    <style name="ShapeAppearanceOverlay.App.Rhombus" parent="" >
        <item name="cornerSize">50%</item>
        <item name="cornerFamily">cut</item>
    </style>
```

他にも様々なカスタマイズができるようです。[参考](https://howtodoandroid.com/shapeableimageview-material-components-android/)
これからのブロックチェーンビジネス　備忘録

#概要
「これからのブロックチェーンビジネス」を読んだので、自分なりに参考になった点などを備忘録としてまとめました。
なにかご指摘などあれりましたら、メッセージをいただけると幸いです。

##INTRODUCTION
・ブロックチェーンは、ネットワーク上に存在するコンピュータが1対1でやり取りをする「P2P通信」が基本的に使用されている
・ブロックチェーンは、主に金融システム全体に影響を与えるが、AIやVRとも相性がいい

##PART1
###SECTION02
・ビットコインのブロックチェーンは、世界中のノードが共有しているため、システム全体がダウンすることなく動き続けることができる。
###SECTION07

・障害や攻撃に極めて強い
・ネットワーク内の出来事を網羅的かつ透明に記録することができる
・一度ブロックチェーンに取り込まれた情報は、改ざんやコピーができない
・管理者がいないため、「公共性」を持ったシステムを構築できる

##PART2
###SECTION03
・ブロックチェーンが生かされる業界
　　・入出金／管理／決済
　　　　主なプロジェクト　→　「Ginco」、「ImToken」、「BRD」など
　　・為替／トレード
　　　　主なプロジェクト　→　「Kyber network」、「Bancor」、「0x」など
　　・証券
　　　　主なプロジェクト　→　「HARBOR」、「POLYMATH」
　　・融資／ローン
　　　　主なプロジェクト　→　「ETHLend」、「Compound」
　　・保険
　　　　主なプロジェクト　→　「PolicyPal」、「B3i」
　　・信用スコアリング
　　　　主なプロジェクト　→　「Bloom」
　　・信託
　　　　主なプロジェクト　→　「BitGo」、「Xapo」
　　・予測市場
　　　　主なプロジェクト　→　「Augur」、「Gnosis」

###SECTION14
・ブロックチェーンが持つ問題
　　・スケーラビリティ問題
　　　　　DAppsのデータ量増加によってトランザクションが増加し、ブロックサイズやブロック生成スピードによってはトランザクションが遅延する
AWS SAAでインスタンスファミリーの選び方を攻略

#はじめに
現在、SAA試験の合格に向けて勉強していますが、インスタンスファミリーの選択を問う問題が出題されます。
aws公式で`約30種類`確認したが、全部の用途・機能について覚えるのはしんどい。試験によく出るところだけ覚えたい。
今回は、試験合格を意識してニーズや用途に合ったインスタンスファミリーを厳選して、一覧にまとめてみました。

#5つのカテゴリー
インスタンスファミリーは大きく5つのカテゴリーに分類できる。

+ 汎用
+ コンピューティング最適化
+ メモリ最適化
+ 高速コンピューティング
+ ストレージ最適化

##汎用
この分類には「Ax」「Tx」「Mx」シリーズが該当する(**頭文字はATMって覚えるとよいかも**)。
汎用インスタンスは、CPU、メモリ、ネットワークのリソースバランスが取れた基本的なタイプ。
インスタンスのリソースを同じ割合で使用するアプリケーションに最適。

| インスタンスファミリー| 特徴 |
|:-----------|:------------|
| Axシリーズ(A1しかない)| AWS Graviton プロセッサで動作する初の EC2 インスタンス| 
| Txシリーズ| バースト可能| 
| Mxシリーズ| コンピューティング、メモリ、ネットワークの各リソースがバランスよく提供される|

Txシリーズは一時的に負荷集中の傾向が見えるシステムに最適。
Mxシリーズは万能タイプなので、迷ったらこれを選ぶ感じ。

##コンピューティング最適化
この分類には「Cx」シリーズが該当する(**コンピューティングのCと覚えるとよいかも**)。
コンピューティング最適化インスタンスは、コンピューティング負荷の高い集約型ワークロードに最適。
具体的にはバッチ処理、メディアトランスコードなど。

| インスタンスファミリー| 特徴 |
|:-----------|:------------|
|Cxシリーズ| コンピューティング負荷の高いワークロードに最適化| 

高い性能を要求するシステムの場合、コストパフォーマンスの観点からCxシリーズが最適。


##メモリ最適化
この分類には「Rx」「Xx」「Ux」「Zx」シリーズが該当する。
メモリ負荷の高いアプリケーション向けに最適。

| インスタンスファミリー| 特徴 |
|:-----------|:------------|
| Rxシリーズ| RAMを大容量搭載| 
| Xxシリーズ| RAM 単価が最安| 
| Uxシリーズ| EC2の中でも 6～24 TB の最大級のインスタンスメモリ    |
| Zxシリーズ|高速な最大 4.0 GHz の持続的な全コア周波数を提供   |

##高速コンピューティング
この分類には「Px」「Gx」「Fx」シリーズが該当する。
GPU搭載のため、汎用GPUコンピューティングアプリケーションに最適。
ユースケースは、機械学習のようなデータ分析に使用されることが多い。

| インスタンスファミリー| 特徴 |
|:-----------|:------------|
| Pxシリーズ| ハイパフォーマンスで単純計算に長けている| 
| Gxシリーズ| グラフィック集約型アプリケーション用に最適化| 
| Fxシリーズ| FPGAを搭載、ASICが抱える設定変更できないデメリットを緩和    |

##ストレージ最適化
この分類には「Hx」「Ix」「Dx」シリーズが該当する。
ストレージ容量が大きく、高いシーケンシャル読み取り及び書き込みアクセスを提供。

| インスタンスファミリー| 特徴 |
|:-----------|:------------|
| Hxシリーズ| HDDを大容量搭載| 
| Ixシリーズ| SDDを使用| 
| Dxシリーズ| HDDを大容量搭載、ディスクスループットパフォーマンスあたりの価格は Amazon EC2 では最小|


#参考
・[Amazon EC2 インスタンスタイプ](https://aws.amazon.com/jp/ec2/instance-types/)
・[【AWS】EC2のインスタンスとは？インスタンスタイプの特徴と比較,覚え方/選び方](https://milestone-of-se.nesuke.com/sv-advanced/aws/instance-type-and-feature/)
Termuxの意外と知らない日本語入力方法、特殊キータブの項目を増やす小技

#Termuxで日本語入力をする方法

![Screenshot_20200929-005905_Termux.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747802/33f5dad4-5cbe-8ed0-067c-29b334e53093.jpeg)


この方法はキーボードアプリに依存しません。従ってどのキーボードアプリを使っていても日本語入力が可能です。
やり方は簡単。下の特殊キータブの部分を左にスワイプするだけです。
でも意外とこういうの見落としがちですよね。

# 特殊キータブの項目を増やす方法
このように、左右の方向キーなどを追加する方法を紹介します。
![Screenshot_20200929-001020_Termux.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/747802/26eefc40-3018-79be-a1bb-fbfb20797d1d.jpeg)

### 1)テキストエディタをインストールする

```
apt install nano
```
または

```
apt install vim
```

### 2)termux.properties(設定ファイル）を作成

```
mkdir ~/.termux
touch ~/.termux/termux.properties
```

### 3)設定ファイルを編集する
次のように編集して保存します

```
extra-keys = [ \
 ['ESC','|','/','HOME','UP','END','PGUP','DEL'], \
 ['TAB','CTRL','ALT','LEFT','DOWN','RIGHT','PGDN','BKSP'] \
]
```

### 4)設定を反映する
次のコマンドを実行します

```
termux-reload-settings
```
もしくは、Termux自体のアプリを一度閉じて、再度起動しても反映させることができます
TXTレコードって何が入るの？

## 勉強前のイメージ

SSLの認証やSPFレコード入れるために使う？
ほかは知らない...

## TXTレコード

### TXTレコードとは

- 0-255オクテットまでの長さの値を複数保持
- 主に、SPFやDKIM(どちらもなりすましを防ぐ仕組み)で使われる

### 実際に確認してみよう(例:google.com)

```sh
dig txt google.com
==========
...

;; ANSWER SECTION:
google.com.             294     IN      TXT     "docusign=1b0a6754-49b1-4db5-8540-d2c12664b289"
google.com.             3594    IN      TXT     "globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8="
google.com.             3594    IN      TXT     "facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95"
google.com.             294     IN      TXT     "docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e"
google.com.             3594    IN      TXT     "v=spf1 include:_spf.google.com ~all"

...
==========
```

- `google.com.             294     IN      TXT     "docusign=1b0a6754-49b1-4db5-8540-d2c12664b289"`
	- ドキュサインのSAML？(よくわからない)
- `google.com.             3594    IN      TXT     "globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8="`
	- グローバルサインのSAML？(よくわからない)
- `google.com.             3594    IN      TXT     "facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95"`
	- facebookのドメイン認証
- `google.com.             294     IN      TXT     "docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e"`
	- ドキュサインのSAML？(よくわからない)
- `google.com.             3594    IN      TXT     "v=spf1 include:_spf.google.com ~all"`
	- SPFレコード(なりすまし防止)

### TXTレコードって何個もかけるの？

- 複数行に渡って書くことが出来る
	- 以下のように"" で括ることで複数行かける

```txt:記載方法
"v=spf1 xxxx.example.com ~all"  "docusign=XXXXXXXXX"
```

```txt:結果
;; ANSWER SECTION:
google.com.             600     IN      TXT     "v=spf1 xxxx.example.com ~all"
google.com.             600    IN      TXT     "docusign=XXXXXXXXX"
```

## 勉強後のイメージ

SSLの認証やSPFレコード、またSAMLにも使われる。
あながち間違ってなかった？


## 参考

- [TXTリソースレコード （テキストリソースレコード）](https://jprs.jp/glossary/index.php?ID=0223)
- [SPF, DKIMの特徴と違い](https://sendgrid.kke.co.jp/blog/?p=10121)
- [Facebookページ利用者なら知っておくべき、リンク先URLのドメイン認証機能の使い方](https://anagrams.jp/blog/facebook-domain-verification/)
SRGAN VS ESRGAN (colab環境)

広島大学で社会基盤(土木)を専攻している３年生です。
現在は１年間休学して建設系のIT企業でインターンをしています。

今回は超解像度のGANモデルである[SRGAN](https://qiita.com/1998922akito/items/f1f4705f3b82b826f50b)を拡張させたモデルESRGAN(Enhanced Super-Resolution Generative Adversarial Networks)を実装してみた比較結果と試したコードを載せたいと思います。

#ESRGANとは
ESRGANとは2018年に発表されたモデルで上記でも述べましたが2016年に発表されたSRGANの拡張版です。
SRGANの概要については以前記事載せたので主にどのような点が拡張されたのかをまとめてみたいと思います。

[論文](https://openaccess.thecvf.com/content_ECCVW_2018/papers/11133/Wang_ESRGAN_Enhanced_Super-Resolution_Generative_Adversarial_Networks_ECCVW_2018_paper.pdf)を参考にしています。

###・全てのBatchNormalization層の削除
BatchNormalization層をなくすことで超解像度の評価関数であるPSNR(Peak Signal to Noise Ratio:ピーク信号対雑音比)が向上し、計算の複雑さを軽減させメモリの削減されることが証明されています。理由はBatchNormalizationはバッチごとに平均・分散を求めて学習しますがtestデータで推論を行った時に平均と分散に差が生じるためアーティファクトが入ってしまうからです。
###・Residual Block を Residual in Residual Dense Block（RRDB)に置き換える
RRDBに置き換えて層を深くしています。深いネットワークでも学習ができるように残差をResNetのように足算を行うのではなくDenceNetと同様に連結させることで可能にしています。また、残差スケーリングを定数を0と1の間の定数を乗算することにより学習の不安定になるのを防いだり、最初にパラメータの初期値の分散が小さい方が残差構造が学習が簡単になるなど工夫をしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677912/567c1b6f-22a3-561b-bba7-bac2445a9a8e.png)

###・Relativistic Discriminator
識別器の学習では本物を１、偽物を０として出力するように学習を行うため本物画像でしか学習を行うことができません。本物・偽物画像両方からシグモイド関数の出力を受け取ります。両方の損失を平均したものを学習するため本物・偽物画像の両方から学習を行うことができます。

###・Perceptual Loss
活性後ではなく活性化前に特徴を制限を行っています。SRGANではReLU関数の出力を用いていましたがこれでは画素情報が失われてしまうからです。この問題を解消すると「深いネットワークでは特徴量がまばらになりやすい」「明るさが不安定になってしまう」などの問題が解消できます。

#今回のデータセット
今回使用している画像はkaggleで公開されている衛星写真のデータセットです。
[画像のリンク](https://www.kaggle.com/kbhartiya83/swimming-pool-and-car-detection)

#SRGAN と ESRGANの出力結果
実際両方200epoch学習させた結果です。
右から入力画像、推論結果、オリジナル画像です。
ESRGAN
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677912/bfae2177-5aaa-163e-a1bd-d44fbf282695.png)
SRGAN
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677912/d87f8073-ce15-d6e4-fc54-d78f55099fbb.png)
両方ともそれなりに解像度が上がりそれなりに綺麗な画像になっているように見えます。
ただ決定的な違いとしてSRGANではオリジナル画像と比べて全体的な色彩が明るいように見えます。ERGANではオリジナル画像と比べてそのような違いは見られませんでした。もしかしたら活性化前に特徴を制限を行っているため明るさの不安定さが改良されたことが原因かもしれません。

#実装コード、参考資料
実装で参考にした[Github](https://github.com/eriklindernoren/PyTorch-GAN/tree/master/implementations/esrgan)
自分が実装した[Github](https://github.com/Akito-Fujihara/satellite-photo-esrgan)
このディレクトリに画像ファイルをアップロードして実行してください。
[論文](https://openaccess.thecvf.com/content_ECCVW_2018/papers/11133/Wang_ESRGAN_Enhanced_Super-Resolution_Generative_Adversarial_Networks_ECCVW_2018_paper.pdf)
[参考にしたサイト](https://medium.com/@crosssceneofwindff/%E7%B6%9A-gan%E3%81%AB%E3%82%88%E3%82%8B%E4%BA%8C%E6%AC%A1%E5%85%83%E7%BE%8E%E5%B0%91%E5%A5%B3%E7%94%BB%E5%83%8F%E7%94%9F%E6%88%90-a32fbe808eb0)
linuxでリンクを貼る

# lnコマンド

```:シンボリック作成
ln -s リンク元 登録名
```
```:強制的にシンボリックリンクを貼る
ln -sf リンク元 登録名
```

```:登録名に既にリンク元がある場合、リンク元ではなく、コマンドで新たに指定されたリンク元へ上書き
ln -nsf リンク元 登録名
```
リーダブルコード　備忘録

#概要
「リーダブルコード　より良いコードを書くためのシンプルで実践的なテクニック」を読んだので、自分なりに今後開発をする上で参考になりそうな点などを備忘録としてまとめました。
なにかご指摘などあれりましたら、メッセージをいただけると幸いです。

##2章　名前に情報を詰め込む
・クラス名、関数名など名前をつける際に、何を目的とするのか情報を持たせる
・名前をつける際、明確で正確なものにする
・「tmp」、「it」、「retval」など汎用的に使われる名前を使用する時は、使用する理由を明確にしておく
・変数名をつける際、セキュリティの問題や、変数名の意味を間違えた際にバグになりそうな箇所には、属性を追加する

##3章　誤解されない名前
・名前をつける際に、使用する名前が他の意味にとらわれないかを考える
・bool値の変数名は、「is」、「has」、「can」、「should」などを頭につけて分かりやすくする

##4章　美しさ
・コードからすぐ分かることは、コメントに書かない

##5章　コメントすべきことを知る
・コメントは、コードを書いている時の考えを記載する。
・コードに欠陥がある際に使用するコメント
　　「TODO:」　→　後で手をつける場合
　　「FIXME:」　→　既知の不具合がある場合
　　「HACK:」　→　解決策があまりキレイじゃない場合
　　「XXX:」　→　大きな問題がある場合

##6章　コメントは正確で簡潔に
・コメントを書く際に、「それ」や「これ」などの代名詞は使用しない
・関数の動作はできるだけ正確に説明する

##7章　制御フローを読みやすくする
・行数を短くすることよりも、誰が見ても理解しやすいコードを記載する
・条件分岐の際は、基本if-else文を使用する。三項演算子は簡潔になるときだけ使用する。

##8章　巨大な式を分割する
・ひとつのコードの式が大きくなると理解が難しくなるため、分割するようにする。

##12章　コードに思いを込める
・コードを明確にする手順
　　1.コードの動作を簡単な言葉で誰にでも分かるように説明する
　　2.その説明の中で使用しているキーワードやフレーズに注目する
　　3.その説明に合わせてコードを書く

##13章　短いコードを書く
・コードをできるだけ小さく軽量に維持するために
　　・汎用的な「ユーティリティ」コードを使用し、重複コードを削除する
　　・未使用のコードや無用な機能を削除する
　　・コードの重量を意識し、軽量で機敏にしておく
・使用するライブラリは、中を見て機能を熟知しておく

##14章　テストと読みやすさ
・他のプログラマが安心してテストの追加や変更ができるように、テストコードを読みやすくする
・テストに使用する値は、キレイで単純なものを使用する

##15章　「分／時間カウンタ」を設計・実装する
・外部の視点を入れる
　　半年後の自分も含め、誰が読んでもユーザーフレンドリーな状態を保つ
DockerをWindows 10 Homeで試してみる

#概要
Windows HomeでもDocker Desktop for Windowsを使えるようになったらしいので試してみる。

#Docker Desktop for Windowsをダウンロード
https://hub.docker.com/editions/community/docker-ce-desktop-windows/

#Windowsのアップデート
そのままではインストール時にWindowsのバージョンが足らないと怒られるので
Windows Insider Programに登録してリリースプレビューチャネルを選択してWindowsをアップデートする。
![screenshot_20200929_001242.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259220/9187612b-8fa7-d4db-8d69-c9baa83b5717.png)


アップデート後のバージョン
![screenshot_20200929_001000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259220/859635a6-77f2-8a80-86d0-7923d30f0731.png)

バージョンアップ後Docker Desktop for Windowsをインストールする。

# 試してみる

適当にCentOSをPullして起動してみる。

```
> docker pull centos
> docker run -i -t centos /bin/bash
```
![2020-09-29 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259220/b237f838-8a00-00c7-7130-e8c94e57659e.png)

無事起動することができた。
IntegromatでSpotifyとSlackを繋いで遊んでみる

## Integromatとは
WEBサービス同士を簡単に連携できるサービスです。
かるく触ってみた程度なのでわからないことも多いので、こちらの記事が参考になります。
[最強連携サービス「Integromat」がZapier/IFTTTをあっさり超えるラスボス感](https://awe-some.net/2016/10/integromat/)


## アカウント登録
下記のサイトよりintegromatのアカウント登録をお願いします。
https://www.integromat.com/en/

## サービス一覧を眺める
お！Spotifyがあるじゃないですか。
Slaçkもありますし、再生中の曲をSlackのチャンネルに送ってNow Playingみたいなことができないか調査してみます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164405/30786858-763a-5cd8-1550-d01d6b4e7205.png" width="70%">


## Spofityを眺める
SpotifyのTRIGGERSとACTIONSを眺めてみましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164405/e79c4675-3c42-8546-449d-6da2c177af03.png" width="70%">
あー、TriggerにChange Tracksみたいなのがあったらよかったんですが・・・
どうやらNow Playingみたいなことはできなさそうです。
このままでは終われないのでIntegromatでSpotifyを操作してSlackに通知を送る、という一連の動きを確認してみます。

## プレイリストに曲を追加する
Save track to playlistというのがあるので、やってみましょう。
あらかじめSpotifyで任意のプレイリストを作成しておきます。
今回はわかりやすく「インテグロマット」というものをつくりました。
こちらにMartin GarrixのIn the Name of Loveを追加してみます。
TrackIDは右クリックメニューのシェア > Spotify URIをコピーから取得できます。
spotify:track:__0VWUhOUNIVOfUoBaq7xqMo__
この文字列部分を設定してあげます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164405/1b75df46-5aaf-cb39-a4e8-a1e9589a242f.png" width="70%">


## Slack側
Create a Message を選択して連携していることを確認します。
Slackに任意のチャンネルを用意しておいて通知がいくかを確認しましょう。
今回はインテグロマットというチャンネルを用意します。
プレイリストに曲が追加されたら「プレイリストに曲が追加されたよ！!と通知してみます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164405/97a9288c-d7d8-0296-2f7f-c4af7aaeea24.png" width="70%">

##動作確認
動画作成を頑張ろうと思っていますが、いかんせん未熟です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">integromaritでSpotifyとSlackを連携するデモ動画<br>QuickTimeとiMovieを使っていく <a href="https://t.co/ws25tHyl5G">pic.twitter.com/ws25tHyl5G</a></p>&mdash; ウーリズム (@Uh_rhythm) <a href="https://twitter.com/Uh_rhythm/status/1310601107241009152?ref_src=twsrc%5Etfw">September 28, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## まとめ
なんとなく雰囲気はわかりましたが、Spotify側から何か情報を取得できないとなんのこっちゃわかりませんね。
繋げるだけではいまのところSpotifyの活用方法は全く思いつきません。
TrackIDを動的にとってこれれば使い道に広がりが出そうですが、今回はここまでにします。
[Android] Kotlin SerializationでJsonをparseする時に困ったこと [メモ]

APIなどのレスポンスを変換するのにKotlin Serializationを利用しているが少し詰まった事があったのでメモと簡単な使い方のおさらい

#Gradle
```build.gradle
// プロジェクト
dependencies {
    classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
}

// App
apply plugin: 'kotlinx-serialization'

dependencies {
    implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0'
}
```

# 使い方
```user.json
{
    "Name": "hogehoge",
    "Age": "12"
}
```

上記のようなJsonを想定した場合、モデルは以下のようになります。

```kotlin
@Serializable
data class User (
    @SerialName("Name") val name: String,
    @SerialName("Age") val age: String
)
```

classに`@Serializable`アノテーションをつけることでシリアル化に対象することができます。`@SerialName`アノテーションは、parseした際のJsonのKeyを別の変数名に変えることができます。今回は、Name->name, Age->ageに指定しています。

ちなみに、[公式](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/basic-serialization.md#serializable-classes)ドキュメントに書いてありますが、getterだけや委譲プロパティをシリアル化の対象外になるみたいです。

```kotlin
@Serializable 
class Project(
    // name is a property with backing field -- serialized
    var name: String
) {
    var stars: Int = 0 // property with a backing field -- serialized
 
    val path: String // getter only, no backing field -- not serialized
        get() = "kotlin/$name"                                         

    var id by ::name // delegated property -- not serialized
}
```

### Json -> モデル
Json文字列からモデルに変換するには、`parse()`を使います。

```kotlin
val json =
            """
                {
                    "Name": "fuga",
                    "Age": "12"
                }
            """.trimIndent()
val user = Json.parse(User.serializer(), json) // User(name=fuga, age=12)
```

### モデル -> Json
モデルからJson文字列への変換は、`stringfy()`を使います

```kotlin
val json = Json.stringfy(User.serializer(), User("hoge", "22")) // {"Name":"hoge", "Age":"22"}
```

## 詰まったこと

```json
{
    "body": {
        "taro": {
            "age": "22",
            "gender": "man"
        },
        "hanako": {
            "age": "30",
            "gender": "woman"
        }
    }
}
```

上記のようなJsonはKeyを指定できないので、JsonObjectとしてモデルに落とし込もうとした。

```kotlin
val json =
            """
        {
            "body": {
                "taro": {
                    "age": "22",
                    "gender": "man"
                },
                "hanako": {
                    "age": "30",
                    "gender": "woman"
                }
            }
        }
            """.trimIndent()
val users = Json.parse(Users.serializer(), json) // Users(body={"taro":{"age":"22","gender":"man"},"hanako":{"age":"30","gender":"woman"}})
```

ここで`taro`の`age`を抜き出してみる。

```kotlin
val taroAge = users.body.getObject("taro")["age"] // "22"
```

上記のような抜き出し方をしてしまうと、JsonObjectは`Map<String, JsonElement>`なので"22"(ダブルクォーテーションあり）の文字列をひっぱてきてしまう。

なので、

```kotlin
users.body.getObject("taro")["age"]?.content
// or
users.body.getObject("taro").getPrimitive("age").content
```

上記の一個目のやり方だとnullの処理が必要なので、2つ目のやり方で今回は解決できた。基本的にJsonElementから値を抜き出すときは`.content`を使用しましょう。
Integromatの気になるthisメモ

#thisちゃうやんけ
IFTTTの有料化に伴ってIntegromatの需要が高まってるらしい。
IFTTTでいうthis部分で面白そうなのをメモリました。
超個人的な備忘録なので悪しからず。
この記事のIFTTT版は[こちらから](https://qiita.com/canonno/items/b54796d1d2b11b65fba2)


#いくぜthis
・Amazon Lambda・Redshift・S3：AWSサービスがthisで使えるとは思ってませんでした。Redshiftとかは使いようによってはすごい便利そう。Lambdaも無限の可能性。

・BaseCamp 2・3：キャンプ用アプリ？と思ったら仕事効率化のAppなのね。プロジェクトマネジメントに便利そう。

・bubble：ノーコードでwebアプリが作れるApp。これは重宝しそう。

・CSV：すっごい幅があるけどcsvファイルを・・・？どうしたら・・・？どうなるの・・・？

・Discord：コミュニケーションプラットフォームが来ると思ってなかったのでちょっとびっくり。Slackみたいな使い方をするときに使うのかな？

・EasyCSV：何が・・・？Easy・・・？なの・・・？気になる。

・facebookまわり：IFTTTよりかなりvariousな印象。Facebook・Conversions API・Groups・Insights・Lead Ads・Messangers・Offline conversions・Pagesなどかなり幅広い。

・Firebase cloud messaging：そもそもFirebaseでmessagingのサービスがあると思ってなかったのでメモ。

・Googleまわり：これが本当にすごい。Gmail・Goole+・Analystics・Calendar・Dialogflow・firestore・cloud print・cloud speech・cloud vision・contacts・data studio・docs・rive・forms・groups・hangouts・chrome・maps・my business・photos・sheets・shopping・slides・tasks・tsanslateと種類が超豊富。

・Image：何が・・・？画像・・・？なの・・・？

・JSON：何が・・・？JSON・・・？なの・・・？

・line：そういえばIFTTTでlineってなかったな。

・Microsoftまわり：SharePoint Online・SQL Server・Teams・To DO・Calendar・Email・Excel・People・Onedrive・Onenoteなどこちらも幅広い。Excelとかって結構なんにでも使えそう。

・MongoDB・MySQL：DBも名指しで使えるのね。

・pocket：IFTTTでもあったので少し気になった。記事・ビデオ・ストーリーなどあらゆるコンテンツを保存できるアプリらしい。

・Reddit：アプリアイコンどっかで見たことあるなと思いメモ。あるコミュニティの中でトピックやアイデアを共有できるプラットフォームのよう。SNS？なのか？

・Runkeeper：これは個人的に使ってたアプリなのでメモ。今はNike run使ってるけど。

・Slack：そういえばIFTTTってthat側にはSlackあるけどthis側になかった気がする。。。Integromat圧勝じゃないのかこれは。

・Skype：電話とかチャットとかで起動できるのかしら。

・Surveybot・Survey Monkey・SurveySparrow・Survey123・Survicate：多分全部アンケートサービスぽい。

・Uber：何ができるのか気になる。

・Wix・WordPress：自前のWebsite作るときは便利そう。

・Yahoo:これも何ができるのか気になるところ。

・zohoまわり：そもそもzohoは企業向けのオンラインアプリケーションサービス？Saas？のよう。Microsoflt officeと同じカテゴリなのかな？

・Zoom：これも結構色々使いようがありそう。
[OutSystems]Text型のLengthが大きすぎるとDBでの長さが無制限に

ユニットテストに使う、BDDFrameworkではAssertを行う度に比較した値をEntity StepAssertに保存します。
保存対象列（ExpectedとObtained）のLengthが5000なのに、それより多い文字数のテキストを保存できたので理由を確認してみました。

# 環境
Personal Environment(Version 11.9.0 (Build 16900))
Service Studio(Version 11.8.8)
Data Extractor(Version 1.4.0)

# テスト対象Entity
以下のように、Text型の属性を4つもたせます。
それぞれ、Lengthプロパティを2000、3999、4000、5000としました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/63822653-bc96-0589-8068-bb903a7221a2.png)

# DDLでDB上での定義上の長さを確認する
Data ExtractorというForgeコンポーネントを使うと、指定したEntityのDDLを抜き出すことができます。本来はデータを取り出すのが目的ですが、今回はDDLの確認に流用しました。
Personal Environmentで確認しているため、DBツールで覗くわけには行かないため。

結果は以下の通り。Lengthが2000であるLONGATTRIBUTE2000の場合のみ、素直にNVARCHAR(2000)という定義で、それ以外はみんなNVARCHAR(MAX)となっています。

``` sql
CREATE TABLE [DBO].[OSUSR_BTE_ENTITYWITHLONGATTRIBUTE]
(
	  [ID] BIGINT NOT NULL IDENTITY(1,1)
	, [LONGATTRIBUTE2000] NVARCHAR(2000) COLLATE LATIN1_GENERAL_100_CI_AI_SC NULL
	, [LONGATTRIBUTE3999] NVARCHAR(MAX) COLLATE LATIN1_GENERAL_100_CI_AI_SC NULL
	, [LONGATTRIBUTE4000] NVARCHAR(MAX) COLLATE LATIN1_GENERAL_100_CI_AI_SC NULL
	, [LONGATTRIBUTE5000] NVARCHAR(MAX) COLLATE LATIN1_GENERAL_100_CI_AI_SC NULL
	, CONSTRAINT [OSPRK_OSUSR_BTE_ENTITYWITHLONGATTRIBUTE] PRIMARY KEY ([ID] ASC)
)
```

NVARCHAR(MAX)がどういう定義かというと、Microsoftのドキュメントによると

[nchar および nvarchar (Transact-SQL)](https://docs.microsoft.com/ja-jp/sql/t-sql/data-types/nchar-and-nvarchar-transact-sql?view=sql-server-ver15#arguments)：

> max は、ストレージの最大サイズが 2^30-1 文字 (2 GB) であることを示します。

と非常に大きな値となることがわかります。
DB上では、このように非常に大きい定義であるため、Service Studio上の定義幅以上の値を格納できたわけですね。

# OutSystemsの仕様
なんでこういう結果になるかというと、OutSystemのドキュメントに答えがありました。

[データベースのデータ型](https://success.outsystems.com/ja-jp/Documentation/11/Reference/OutSystems_Language/Data/Database_Reference/Database_Data_Types)：(Text型のSQL Serverにおける仕様として)

> 文字数が2,000文字以下の場合はnvarchar(<文字数>)、それ以外の場合はNVarchar(max)。

とあるので、Length=2001以上のText型はDB上でNVarchar(max)になるということのようです。
Personal EnvironmentなのでSQL Serverですが、Oracleでは、

> 文字数が2,000文字以下の場合はVARCHAR2(<文字数>)、それ以外の場合はCLOB。

とCLOB型が使われることになっています。

# 他のドキュメントとの齟齬？
[パフォーマンスベストプラクティス](https://success.outsystems.com/ja-jp/Documentation/Best_Practices/Performance_and_Monitoring/Performance_Best_Practices_-_Data_model#.E9.87.8D.E8.A6.81.E4.BA.8B.E9.A0.85_2)という設計／実装で参考にすべきドキュメントでは、

> 2,000文字を超えるText型のアトリビュートがある場合、データベースではBinary Data型にマッピングされます。

とBinary系のデータ型にマッピングされるとされているのですが、NVarcharもCLOBもText系の型である気がします。妥当な説明は思いつかないのですが、なにかわかったら追記します。