OmniAICreator/Qiita-1.07M huggingface dataset:
【Swift】FireStore × TableViewの実装（データの取得から反映までの格闘）

# はじめに
TableViewとFireStoreを掛け合わせた実装の際、データ取得から反映（特に反映）で詰まっていたので、次回実装時にスムーズに実装できるようにメモに残したい。


# TL;DL
```:実装の際のポイント
// tableView.reloadData()の実装のタイミングを間違うと表示されない
tableView.reloadData()  // こいつ！！！
```
# 実装例
## ① 取得するデータを格納する配列を用意
```:ViewController.swift
var memoDataArray: [MemoDataStore] = []
// ついでにFirestoreの下準備も
let currentUser = Auth.auth().currentUser
let db = Firestore.firestore()
``` 

## ② TableViewのデータの取得と更新
今回ここが抜けていたのが原因で表示されませんでした。

```:ViewController.swift
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // 毎回データ更新してくれるように、viewWillAppearの中に記述する
        memoDataArray = getData()
}

func getData() -> [MemoDataStore] {
    let ref = db.collection("todos")
    ref.getDocuments { (snaps, err) in
        if let err = err {
            print("Error getting documents: \(err)")
            return
        }
        self.memoDataArray = snaps!.documents.map { document -> MemoDataStore in
            let data = MemoDataStore(document: document)
            return data
        }
        
　　　　　// こいつ！！！！
        // データ取得が終わったタイミングでtableViewをリロードデータ
        self.tableView.reloadData()
    }
    return memoDataArray
}

class MemoDataStore: NSObject{
    var todoText: String?
    var detailText: String?
    var dateText: String?
    init(document: QueryDocumentSnapshot) {
        let dic = document.data()
        self.todoText = dic["todo"] as? String
        self.detailText = dic["detail"] as? String
        self.dateText = dic["date"] as? String
    }

}
```


## 配列に格納されたデータをTableViewに適応
```:ViewController.swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // カスタムセル使用しているが、今回は記載を省略
    let cell = tableView.dequeueReusableCell(withIdentifier: "MemoCell") as! FirstViewTableViewCell
    cell.setCell(memo: memoDataArray[indexPath.row].todoText!, date: 
    memoDataArray[indexPath.row].dateText!)
    return cell
}
``` 


これでFireStoreからデータを取得して、TableViewに表示するまでの実装できました。


# まとめ
1. tableView.reloadData()は、tableViewのデータを更新ためのメソッドであり、TableView上のデータにコード上で変更を加えた際は、変更が完了したタイミングで、reloadData()を忘れないこと

2. 今回で言うと、FireStoreからデータが取得される前に、tableViewの表示が実装されて、データが配列に格納されていない状態を参照していたので、何も表示されなかった。

3. つまり、TableViewの表示のコードが読み込まれてから、用意した配列にデータが入っているため、何も表示されていないイメージ。

4. 特に外部APIを叩いた際は、取得までに時間がかかり、非同期的にデータが取得されるため、iOSのライフサイクルに準拠して、実装することが大切
apt updateのエラーを一旦消す「リポジトリ http://ppa.launchpad.net/xorg-edgers/ppa/ubuntu focal Release には Release ファイルがありません。」


出たエラーはこれ

```
sudo apt-get update && sudo apt-get upgrade
ヒット:1 https://repo.steampowered.com/steam stable InRelease                  
ヒット:2 http://jp.archive.ubuntu.com/ubuntu focal InRelease                   
ヒット:3 http://jp.archive.ubuntu.com/ubuntu focal-updates InRelease           
ヒット:4 http://jp.archive.ubuntu.com/ubuntu focal-backports InRelease         
ヒット:5 https://download.docker.com/linux/ubuntu focal InRelease              
ヒット:6 http://packages.microsoft.com/repos/code stable InRelease             
ヒット:7 https://packages.microsoft.com/ubuntu/21.04/prod hirsute InRelease    
ヒット:8 http://security.ubuntu.com/ubuntu focal-security InRelease            
ヒット:9 http://ppa.launchpad.net/apandada1/brightness-controller/ubuntu focal InRelease
ヒット:10 http://ppa.launchpad.net/gezakovacs/ppa/ubuntu focal InRelease
ヒット:11 http://ppa.launchpad.net/graphics-drivers/ppa/ubuntu focal InRelease
ヒット:12 http://ppa.launchpad.net/obsproject/obs-studio/ubuntu focal InRelease
無視:13 http://ppa.launchpad.net/xorg-edgers/ppa/ubuntu focal InRelease
エラー:14 http://ppa.launchpad.net/xorg-edgers/ppa/ubuntu focal Release
  404  Not Found [IP: 91.189.95.85 80]
パッケージリストを読み込んでいます... 完了
E: リポジトリ http://ppa.launchpad.net/xorg-edgers/ppa/ubuntu focal Release には Release ファイルがありません。
N: このようなリポジトリから更新を安全に行うことができないので、デフォルトでは更新が無効になっています。
N: リポジトリの作成とユーザ設定の詳細は、apt-secure(8) man ページを参照してください。
```

GUIで親フォルダーが/etc/aptの「sources.list」をダブルクリックすると、「ソフトウェアトアップデート」が開かれるので「他のソフトウェア」をクリック。

そこで、エラーが出たURL（今回は「http://ppa.launchpad.net/xorg-edgers/ppa/ubuntu focal」）を探して、チェックマークを外す。

これで一旦はエラーが出なくなるが、根本は解決していないので注意が必要だ。
ABC187 C - 1-SAT から学んだ

https://atcoder.jp/contests/abc187/tasks/abc187_c

![abc187_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/dafc3c38-e9ba-3f2e-81c0-27387d9f429c.png)

んー、何とかなりそうかも。

![abc187_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/d674b064-604d-24e4-f32e-54069297e333.png)

サクッと書いたが見事に TLE

```SAT_rev1.py
from sys import exit
n = int(input())
lis = []
_lis = []
 
for _ in range(n):
    s = input()
    if s[0] == "!":
        _lis.append(s)
    else:
        lis.append(s)
 
for x in lis:        # len(lis) = 10**5
    if "!"+x in _lis:# len(_lis) = 10**5 の場合、10**10 となり TLE
        print(x)
        exit()
print("satisfiable")
```

https://qiita.com/Hironsan/items/68161ee16b1c9d7b25fb

※リスト x in s の計算量 O(n) を参照

じゃあ、試しに辞書にしてみよう。
以下で通った。

```SAT_rev2.py
from sys import exit
n = int(input())
lis = []
dic = {}
 
for _ in range(n):
    s = input()
    if s[0] == "!":
        if s not in dic:
            dic[s] = 0
        dic[s] += 1
    else:
        lis.append(s)
 
for x in lis:       #計算量 O(N)
    if "!"+x in dic:#計算量 O(1) 
        print(x)
        exit()
print("satisfiable")
```

https://takeg.hatenadiary.jp/entry/2019/06/02/172831

神曰く、辞書、set は in演算子は O(1) で済む。
勉強になった。
html文字列をReactElementに変換する

## やりたいこと
html文字列をReactElementに変換する．

例えば，`"<img src='sample.png'>"`という文字列をアプリ上で入力すると画像が表示されるなど．

## 方法
[react-html-parser](https://www.npmjs.com/package/react-html-parser)というライブラリを使う．

## 実装例
`"<img src='sample.png'>"`という文字列をReactElementに変換して表示する例

```react:index.tsx
import React from "react";
import ReactHtmlParser from "react-html-parser";

const Index: React.VFC = () => {
  const imgHtml = "<img src='sample.png'>";
  return (
    <div>
      {ReactHtmlParser(imgHtml)}
    </div>
  );
};

export default Index;
```


文字列をtextareaに入力し，ReactElementに変換して表示する例（TypeScript）

```react:index.tsx
import React, { useState } from "react";
import ReactHtmlParser from "react-html-parser";

const Index: React.VFC = () => {
  const [html, setHtml] = useState<string>("");

  return (
    <>
      <div>
        {ReactHtmlParser(html)}
      </div>
      <textarea onChange={(e) => setSlide(e.target.value)} />
    </>
  );
};

export default Index;
```
【個人開発】「あのアイコンの名前がわからない」あなたへ。手書きで探せるアプリを作りました。

アイコン探しって、結構大変じゃないですか？

開発をしていると、アイコンが必要になります。
しかし、たまに **検索するための名前がわからない** という問題が起きる...

例えば、メニューに使われる「⋯」のアイコン。
なんて検索すればいいかわからない...

なので、 **手書き検索** できるようにしました！
![light_light_light.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516428/59cb4dd7-63ec-365f-2ca7-b5a1e4974786.gif)




# 作ったアプリ
**手書きアイコン検索アプリ iconow** 
アイコンの名前がわからなくて探せない...という問題を解決するため、**手書き**で検索できるようにしたアプリです。 

みんな大好き **FontAwesome** と、Web や Flutter のアイコンに採用されている **Material Icon** を検索できます。

#### iOS

https://apps.apple.com/jp/app/iconow/id1571152071

![QR_386675.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516428/11e768ad-cf53-985a-f917-41542d0d398f.png)



#### Android

https://play.google.com/store/apps/details?id=com.goodbyeunivlife.iconow&hl=jp

![QR_386719.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516428/9e9ac345-790b-8dad-2de7-2816c1e994dd.png)



# 使用した技術

* Flutter
* Firebase
    * Authentication
    * Firestore
* AWS 
    * Lambda
    * ECR
    * API Gateway
    * DynamoDB
    * S3
* Serverless
* Docker
* TensorFlow


## フロントエンドについて


フロントエンドは Flutter を使っています。
iOS、Android を同時に開発できる Flutter はやはり非常に強力です。

状態管理は Riverpod + freezed + StateNotifier を採用しました。
ユーザー管理周りは Firebase を使っています。

技術的な点では、今回のアプリの肝である手書き部分にこだわりました。
画面をなぞったところを検知し、そのポジションを `Riverpod` で管理することによって、高速かつ軽量に手書きが実現できます。
また、手書きの基本的な Undo、Redo 機能も実装しています。
詳しい実装方法は以下の記事に書いています。

https://qiita.com/tigeeer/items/efa4ce8a4025bbda607b

## バックエンドについて

画像を受け取り、それを学習モデルに解析させ結果を送る API を作成しています。
学習モデルが動くコンテナを構築しておき、それを ECR にあげて Lambda で展開し、API Gateway で接続する構成です。
CircleCI と Serverless を用いて GitHub にあげたときに自動展開できるようにしました。
詳しくは以下の記事に書いています。

https://qiita.com/GleamingCake/items/7e52a6941f3991a0283c

また、DynamoDB や S3 は学習モデルのログを保存するために使っています。

## 機械学習について

特に苦労したところ。
基本的に、機械学習は大量のデータを学習させることで汎用性を高め、精度を上げます。
つまり、学習データが少ないと精度が上がらないのです。
しかし、このアプリは製作者が2人しかいないため、大量の手書きデータを用意するのは不可能でした。

というわけで、考え方を変えて精度ではなく**汎化性能**を重要視しました。
検索結果には推論結果の 1位 から 20位 までくらいを出して、その中からユーザーに判断してもらうという作戦です。
これなら1位をズバッと当てられなくとも、検索アプリとしては成り立ちます！

まずは似ているアイコンの画像をグループ分けし、グループをターゲットとします。
そしてこれらをもとに手書きして、教師データを作成しました。1グループにつき 5～20枚ほど手書きしています。
教師データの画像はぐにゃぐにゃにしたもので 100倍に水増ししておきました。これにより汎化性能が大幅に向上しました。

![qiita-20.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516428/5285f3b7-a8e7-800f-903d-9472d4743396.jpeg)



そして、学習時には「上下/左右移動」「カットアウト」「回転」「ズーム」「スキュー」などの DataAugmentation を使っています。（フリップは矢印などのアイコンに悪影響のため使っていません。また、グレースケールとして処理しているため色の DA は使っていません。）
モデルは、ドロップアウトの確率を多めに設定し、畳み込みを広く取ることで、損失率を出来るだけ抑えるネットワークを構築しています。

# 開発者
#### バックエンド, 機械学習担当
@GleamingCake
[Twitter](https://twitter.com/CakeGleaming)

https://github.com/kobayashiharuto


#### フロントエンド担当
@tigeeer
[Twitter](https://twitter.com/tigeeer8)

# さいごに

使ってみての感想やご意見、バグ報告などありましたら、ぜひコメント欄にお願いします！
Git コマンド（メモ）

#Gitコマンド一覧

###ローカルリポジトリ作成

```
$ git init
```
###変更分を全てをステージする（指定も可）

```
$ git add .
$ git add ファイル名
```

###変更を記録する（コミット）（変更、削除、新規作成、複数ファイルの変更内容）

```
$ git commit -m 'コミットメーセージ'
```

###一つ前のコミットをやりなおす（※プッシュしていないもの）

```
$ git commit --amend 
```

###リモートリポジトリを新規追加する

```
$ git remote add origin(リモートリポジトリ名)git@~
```

###プッシュする（リモートリポジトリをGitHubに送る）

```
$ git push origin ローカルブランチ名 
```

###現在の状況を確認する（変更、削除、新規作成、複数ファイルの変更内容）

```
$ git status
```
###git addする前の変更分

```
$ git diff
```
###変更履歴を確認する

```
$ git log
```
###履歴を一行で表示（見やすい）

```
$ git log --oneline
```
###リポジトリをコピーする

```
$ git clone リポジトリ名
```
###ファイルを削除を記録

```
$ git rm ファイル名
$ git rm -r　ディレクトリ名
```
###ファイルへの変更を取り消す

```
$ git checkout ファイル名
$ git checkout ディレクトリ名
$ git checkout .
```
###ステージした変更を取り消す（ワークツリーのファイルには影響なし）

```
$ git reset HEAD　ファイル名
$ git reset HEAD　ディレクトリ名
$ git reset HEAD .
```
##ブランチ
###ブランチを新規作成する

```
$ git branch ブランチ名
```
###ブランチ一覧を表示

```
$ git branch
```
###ブランチを切り替える

```
$ git checkout ブランチ名
```

###変更履歴をマージする

```
$ git merge ブランチ名
```
###ブランチを変更する

```
$ git branch -m ブランチ名
```
###ブランチを削除する

```
$ git branch -d ブランチ名
```

## リモート
###リモートを表示する

```
$ git remote
```

###リモートから情報を取得する（フェッチ）

```
$ git fetch リモート名
```
###リモートから情報を取得してマージする（プル）

```
$ git pull　

#　これと同じ
$ git fetch origin　リモート名
$ git merge origin　リモート名
```
###リモート変更

```
$ git remote rename 旧リモート　新リモート
```
###リモート削除

```
$ git remote rm リモート名
```
###リモートの詳細情報を表示

```
$ git remote show リモート名
```
###URLを表示

```
$ git remote -v
```

###HTTPS接続をSSH接続に変更
(SSH接続からHTTPSの場合も同様、HTTPS用のURLを入力）

`origin`の後にSSH用URLを入力

```
$ git remote set-url origin git@gitlab.com:...
```
Oracle Linux OS(or any arm64)にdocker compose v2を入れる方法

:::note warn
Update: 2023/06/07
久々にOracle Cloudを触ったので `sudo yum update` をしたら、公式レポジトリからdocker-compose-pluginが自動でインストールされました。
下記の文章は読まずに、公式サイトのインストール方法を参照してください。
https://docs.docker.com/compose/install/linux/#install-using-the-repository
:::

# はじめに
自分自身がOracle Linux OSにdocker-composeをインストールするのに手間取ったので備忘録も兼ねて書いておきます。

現状の`docker-compose`は、インストールにpipが必要だったので、Docker Engine自体の上で`docker-compose`を動かしていました。

下記のようにpipがうまく行かなかったりv1でarm64用バイナリがなかったりしました。
https://qiita.com/kure/items/d691bc6afd912bbbc545

linuxserver/docker-compose

https://hub.docker.com/r/linuxserver/docker-compose

しかし、新たに登場したGolang製の`docker-compose v2`[^1] が、シングルバイナリかつarm64に対応していたのでインストールしてみました。

:::note info
🎉 v2.0.0が正式リリースしました。
:::

https://github.com/docker/compose/tree/v2

# インストール

```bash
# cli-plugins用ディレクトリを作成
$ mkdir $HOME/.docker/cli-plugins

# ダウンロード&インストール
# (最新バージョンは適宜 https://github.com/docker/compose/releases からご確認お願いします。)
$ curl -sSL --fail https://github.com/docker/compose/releases/download/v2.0.0/docker-compose-linux-arm64 -o ~/.docker/cli-plugins/docker-compose
$ chmod +x ~/.docker/cli-plugins/docker-compose

# インストール確認 (docker'-'composeのハイフンが消えてることに注目)
$ docker compose version
Docker Compose version v2.0.0
```

[^1]: 🔍`docker-compose v2` とかで検索してると、`docker-compose.yml`のバージョンに引っかかってしまうのでネーミングちょっと変えてほしかったですね...
rails かしこさ

-----
##railsのかしこさに感動
-----



```java:title
$ rails g model Friendly
Running via Spring preloader in process 12491
      invoke  active_record
      create    db/migrate/20210913142600_create_friendlies.rb
      create    app/models/friendly.rb
      invoke    test_unit
      create      test/models/friendly_test.rb
      create      test/fixtures/friendlies.yml
```

```java:マイグレーションファイル
class CreateFriendlies < ActiveRecord::Migration[5.2]
  def change
    create_table :friendlies do |t|

      t.timestamps
    end
  end
end
```

##ちゃんとfriendliesになっている！？？
friendlysになると思ったけどならなかった
すげぇ
以上ｗ
エラーへの対応

##例外への対応
**例外**とはプログラムの実行中に発生する、処理を継続することができないエラーのこと。
このような例外が発生した場合の対応方法をあらかじめ記述する必要がある。
この対応を**例外処理**という。

##tryキーワード、catchキーワード
C#にはtryキーワードとcatchキーワードを使い、**例外処理**を記述します。

```C#
 public static void Practice_Q15_2_2()
        {
            try
            {
                var total = 1000;
                var line = Console.ReadLine();
                var count = int.Parse(line);
                var ans = total / count;
                Console.WriteLine(ans);
                Console.WriteLine("正常終了");
            }
            catch (System.DivideByZeroException) //DivideByZeroException例外をキャッチする
            {
                Console.WriteLine("ゼロは入力できません");
            }
            catch (System.FormatException) //FormatException例外をキャッチする
            {
                Console.WriteLine("数値を入力してください");
            }
            catch (System.Exception)
            {
                Console.WriteLine("予期しないエラーが発生しました");
            }
        }
```

このように例外によって種類を分けられる

:::note alert
ただし下記のコードはコンパイルエラーになる
:::

```C#
try
{
   :
}
catch (System.Exception) 
{
   Console.WriteLine("予期しないエラーが発生しました");
}
   catch (System.FormatException) 
{
   Console.WriteLine("ゼロは入力できません");
}
   catch (System.Exception)
{
   Console.WriteLine("数値を入力してください");
}
```

コンパイルエラーになる理由は二つあります

- System.Exception例外は全ての例外の継承元のクラスである
- try-catch構文では、コードに書かれた順番に例外の種類をチェックしていく

>全ての例外はSystem.Exceptionクラスの派生クラスなので、System.ExcepExceptionクラスとは必ずis aの関係になります。
>そのため、**catch(System.Exception)**ブロックが先頭にあると、全ての例外がここキャッチされてしまうのです。
つまり、

```C#
Console.WriteLine("ゼロは入力できません");
Console.WriteLine("数値を入力してください");
```
は絶対に実行されることはありません。

##例外オブジェクトにアクセスする##
>例外のさらに詳しい情報を取得したいとき、例外オブジェクトにアクセスすることで、些細なエラー情報を取得できます。

```c#
 try
 {
     Book book = null;
     var title = book.Title; //bookはnullなので、Titleを参照できず例外が発生
     Console.WriteLine(title);
 }
     catch (Exception ex)
 {
     Console.WriteLine($"Type: {ex.GetType().Name}");
     Console.WriteLine($"Message: {ex.Message}");
     Console.WriteLine($"TargetSite: {ex.TargetSite}");
     Console.WriteLine($"StackTrace: {ex.StackTrace}");
 }
```

######実行結果######

```C#
Type: NullReferenceException
Message: Object reference not set to an instance of an object.
TargetSite: Void Practice_Q15_2_3()
StackTrace:    at practice.Program.Practice_Q15_2_3() in /Users/tamuratoorunin/Projects/practice/practice/Program.cs:line 44
```

:::note info
exは、catchブロックで利用できる変数で、Exception例外オブジェクトを表しています。
:::

今日の記事は以上です。ありがとうございました。
何か指摘、ご意見あればご連絡ください。
AtCoderログ：0111 - ABC 218 A

# 問題

https://atcoder.jp/contests/abc218/tasks/abc218_a

## 問題文
> 明日からの $7$ 日間の天気予報を表す文字列 $S$ が与えられます。
> $i$ 日後の予報は $S$ の $i$ 文字目が o であるとき晴れ、x であるとき雨です。
> $N$ 日後の天気予報が晴れかどうかを教えてください。

## 制約
> ・$N$ は $1$ 以上 $7$ 以下の整数
> ・$S$ は長さ $7$ の文字列であり、o と x のみからなる

# 回答
## 回答1 (AC)
文字列の $N$ 文字目が o か x かを判定する問題です。文字列の長さは $7$ 文字に固定されているので、悩むところはないと思います。コードは以下のようになりました。

```C++:abc218a-1.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int n;
  string s;
  cin >> n >> s;

  if ( s.at(n-1)=='o' ) {
    cout << "Yes" << endl;
  } else {
    cout << "No" << endl;
  }
}
```

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/abc218/tasks/abc218_a/editorial) → [公式解説](https://atcoder.jp/contests/abc218/editorial/2579)
回答1と同じ方針でした。

# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0110 - ABC 218 に参加しました](https://qiita.com/RoadLynton/items/79e45efdc0a06123255d)
- 前の記事 → [AtCoderログ：0112 - ABC 218 B](https://qiita.com/RoadLynton/items/5f8127d0fdaf8c135322)
VS Code Remote SSHで、Could not establish connection to : Permission denied(publickey,gssapi-keyex,gssapi-with-mic,password).

#解決までの経緯

![スクリーンショット 2021-09-13 20.58.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536974/1bbff16e-eea1-21a8-d119-269dcc2d3c86.png)

#💡解決方法

##エラー内容

```
Could not establish connection to "OFLog-dev-env": Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
```

**結論：私の場合は、エラーでもなんでもありませんでした。**

![スクリーンショット 2021-09-13 23.09.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536974/f1e4c32f-71d7-69f9-7156-451e0eb9acdc.png)

エラーが表示される前に上記の画面が表示されると思いますが、入力欄に
**設定したssh接続用のパスワード**を入力 → Enterするだけでした。

エラーが出る原因はおそらく

* パスワードが違う
* 本当に権限がない

どちらかだと思います。

## 権限の設定（おまけ）

![スクリーンショット 2021-09-13 23.18.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536974/4de3bcfd-42db-3593-dc20-1835dcea2860.png)

出力のLogの少し上の方に、警告が出た時ですが、
権限を与えすぎていて安全性が低い事原因だと思います。

>プライベートキーファイルは、その他のすべてのユーザーの読み取りおよび書き込み操作から保護されている必要がある。
https://qiita.com/leomaro7/items/662699dcb7a7adc36f40

```
$ chmod 600 ~/.ssh/xxxxxxxxxxxx.pem
```

**プライベートキーの記載されたファイル**の、権限を変更してあげましょう。

#終わり

接続後はVScodeの左下、こんな感じになると思います。

![スクリーンショット 2021-09-13 23.15.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536974/0ef14d47-0c31-696a-2c3e-f93aab09921b.png)
タップやスワイプの処理をさせない様にする（isUserInteractionEnabled）

# 今回の内容

* `.isUserInteractionEnabled`でタップや長押しやスワイプ時の処理をさせない。
#コードと簡単解説

* これだけでviewに対するタップ、長押し、スワイプ時の処理を働かせることができなくなります。

```Swift:
    view.isUserInteractionEnabled = false
```

#使ってみる

* viewを5回タップしたら`@objc func screenTap(){}`の処理が働かなくなります。

```Swift:
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var detectionResultLabel: UILabel!

    var tapCount = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        let tapDetection = UITapGestureRecognizer(target: self, action: #selector(screenTap))
        view.addGestureRecognizer(tapDetection)
    }

    @objc func screenTap(){
        
        if tapCount == 5{
            
            self.view.isUserInteractionEnabled = false
            
        }else{           
     
            tapCount += 1
            detectionResultLabel.text = "\(tapCount)回、画面をタップしました"     
        }   
    }

}
```

# 終わり
ご指摘、ご質問などありましたら、コメントまでお願い致します。
PyTorch の Define by Run を可視化

# Deep Learningフレームワークにおける計算グラフ

TensorFlow, PyTorchなどのDeep Learningフレームワークにおける計算グラフの構築方法が，大きく分けて2パターンに分類される。1つ目は Define by Run 型で，2つ目は Define and Run 型である。

## それぞれの特徴

#### Define by Run型
* Chainer, PyTorchがこちらの方式を採用している
* データを流すときに，計算グラフの構造を決定
* 動的な計算グラフを定義することが可能


#### Define and Run型
* TensorFlow(v1)がこの方式を採用している
* 計算グラフの構造を予め定義しておき，そこにデータを流す



## Define by Run が動的な計算グラフを構築できることを確認

#### 概要
* 入力データによって計算グラフが変化することを確認
* 本稿では，Recurrent Neural Net (RNN) を可視化
* torch_vizのmake_dot()を用いて，系列長が2と3の場合の計算グラフを出力

#### 結果
* 系列長2の場合 (左)
    * ループに対する重みとバイアス(fc_h.weight と hc_h.bias)が1度しか使用されない
* 系列長3の場合 (右)
    * ループする回数が増えたため，2度使用されていることがわかる

![スクリーンショット 2021-09-13 21.08.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359849/230099ea-ac2a-0fcc-1998-9617002943cc.png)

#### ソースコード
##### 可視化
```python:visualize_RNN.py
import torch

from torchviz import make_dot
from RNN import RNN

INPUT_SIZE = 1
TIME_LENGTH = 3
# TIME_LENGTH = 2

model = RNN()
data = torch.randn(1, TIME_LENGTH, INPUT_SIZE)

y = model(data)

image = make_dot(y, params=dict(model.named_parameters()))
image.format = "png"
image.render(f"RNN_{TIME_LENGTH}s")

```

##### ネットワークの定義
```python:RNN.py
import torch
import torch.nn as nn

class RNN(nn.Module):
    def __init__(self):
        super(RNN, self).__init__()
        # 入力に対する全結合層
        self.fc_in = nn.Linear(1, 64)
        # ループに対する全結合層
        self.fc_h = nn.Linear(64,64)
        # 出力用の全結合層
        self.fc = nn.Linear(64, 10)

    def forward(self, x):
        _, length, _ = x.size()
        h = self.fc_in(x)
        h = torch.tanh(h)

        # 入力データの系列長に合わせてループする
        for i in range(1, length):
            h = self.fc_in(x[:, i, :]) + self.fc_h(h)
            h = torch.tanh(h)

        h = self.fc(h)

        return h
```
CBC Bit-Flipping Attack

# はじめに
ブロック暗号のCBC(Cipher Block Chaining)暗号化モードを利用した暗号文に対する攻撃として、CBC bit flipping attackとよばれる攻撃があります。下記のCTFを解く際に勉強したまとめ。

**PicoCTF WebExploitation more cookies**
`I forgot Cookies can Be modified Client-side, so now I decided to encrypt them! `
[http://mercury.picoctf.net:56136/](http://mercury.picoctf.net:56136/)

参考にした記事
[CBC Bit-Flipping Attack](https://masterpessimistaa.wordpress.com/2017/05/03/cbc-bit-flipping-attack/)
[Bitflip effect on encryption operation modes](https://www.sjoerdlangkemper.nl/2018/04/25/bitflip-effect-on-encryption-operation-modes/)
[暗号技術入門04 ブロック暗号のモード〜ブロック暗号をどのように繰り返すのか〜](http://www.spiritek.co.jp/spkblog/2016/12/01/%e6%9a%97%e5%8f%b7%e6%8a%80%e8%a1%93%e5%85%a5%e9%96%8004-%e3%83%96%e3%83%ad%e3%83%83%e3%82%af%e6%9a%97%e5%8f%b7%e3%81%ae%e3%83%a2%e3%83%bc%e3%83%89%e3%80%9c%e3%83%96%e3%83%ad%e3%83%83%e3%82%af/)
[Bit Flipping Attack on CBC Mode](https://crypto.stackexchange.com/questions/66085/bit-flipping-attack-on-cbc-mode/66086#66086)

# CBC暗号化モードとは
ブロック暗号の暗号化方式の一つ。まずブロック暗号って何って人は[この記事](https://wa3.i-3-i.info/word16597.html)を読むといいかも。
暗号化アルゴリズムは、以下の図のように平文と一つ前の文のXORを取ったものを鍵を用いて暗号化するという特徴がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1196804/c949efca-4666-8ea5-74e2-fc4f0c8560e2.png)
一番最初のブロックには一つ前の暗号文が存在しないため、IVと呼ばれるブロック長同じ長さのランダムなビット列を生成する。

復号アルゴリズムはこの逆を行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1196804/b25a37d7-444f-9d49-84a7-635f0f7f1854.png)

# Bit-flipping攻撃
この攻撃は、暗号文のどこか１ビットを改ざんすることで、対応する箇所の平文の文字列を書き換える攻撃。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1196804/f8a00f69-f703-61c0-b35d-2a91be493150.png)
上図のように２番目のブロックのあるビットを改ざんすることで３番目のブロックの複合の際に、平文の対応する箇所のビットが書き換わるという影響を受ける。
攻撃者の前提条件としては以下
- 攻撃者は暗号文を改ざんすることができる

具体的な例を考える。
平文`{"user": "johndoe", "nick": "john", "admin": 0}`を暗号化すると以下のように暗号文`Ho2aajuAtfJJEJMmtHEOacvccrCRkkQH6WXZVlvvQTx0ptDJ`がえられたとする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1196804/c949efca-4666-8ea5-74e2-fc4f0c8560e2.png)

この暗号文で以下のように赤い文字の箇所を`k→j`に書き換える。すると複合した際の平文で`"admin:0"`という元の平文から`"admin:1"`というように書き換えられていることがわかる。攻撃者は暗号文さえ改ざんすることができれば、平文を得ること無く平文のあるビットを書き換えることができている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1196804/8c1a4baa-1922-9bc2-805d-e8ed4d0f3613.png)

# どんな使い方が考えられるか
`"admin:0"`という元の平文から`"admin:1"`と変更できているように認証の際に管理者権限に昇格することができる。
BigQueryのテーブル利用状況を可視化してみる

# 方針

- BigQueryのINFORMATION_SCHEMAを利用してジョブメタデータを取得し、テーブルごとのジョブ実行回数を集計する。

# 直近1ヶ月のジョブ実行回数を取得するクエリ

``` sql
SELECT 
  referenced_tables.project_id
  , referenced_tables.dataset_id
  , referenced_tables.table_id
  , COUNT(job_id) AS count_job
FROM
  `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT -- BigQuery の INFORMATION_SCHEMA ジョブビューはリージョン化されています。これらのビューに対してクエリを実行するには、リージョン修飾子を使用する必要があります。
  , UNNEST(referenced_tables) AS referenced_tables
WHERE 
  creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP, INTERVAL 1 MONTH) -- creation_timeは時間単位の列パーティションになっている
  AND job_type = 'QUERY' -- ジョブのタイプ
  AND statement_type = 'SELECT' -- クエリステートメントのタイプ
  AND state = "DONE" -- ジョブの実行状態
GROUP BY
  1,2,3
ORDER BY
  count_job DESC
```

## ポイント

- RECORD型の`referenced_tables`カラムに、クエリが参照したプロジェクト、データセット、テーブル情報が格納されている。(めっちゃありがたい！)
- なので、UNNESTでフラット化した上で、`job_id`カラムをCOUNTしてあげればOK。

# 応用：ジョブが実行されていないテーブルを取得するクエリ

``` sql
WITH 
  count_jobs AS (
SELECT 
  referenced_tables.project_id
  , referenced_tables.dataset_id
  , referenced_tables.table_id
  , COUNT(job_id) AS count_job
FROM
  `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT -- BigQuery の INFORMATION_SCHEMA ジョブビューはリージョン化されています。これらのビューに対してクエリを実行するには、リージョン修飾子を使用する必要があります。
  , UNNEST(referenced_tables) AS referenced_tables
WHERE 
  creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP, INTERVAL 1 MONTH) -- creation_timeは時間単位の列パーティションになっている
  AND job_type = 'QUERY' -- ジョブのタイプ
  AND statement_type = 'SELECT' -- クエリステートメントのタイプ
  AND state = "DONE" -- ジョブの実行状態
GROUP BY
  1,2,3
  )

SELECT
  tables.table_catalog AS project_id
  , tables.table_schema AS dataset_id
  , tables.table_name AS table_id
  , count_jobs.count_job
FROM 
  `region-us`.INFORMATION_SCHEMA.TABLES AS tables -- BigQuery の INFORMATION_SCHEMA ジョブビューはリージョン化されています。これらのビューに対してクエリを実行するには、リージョン修飾子を使用する必要があります。
LEFT JOIN 
  count_jobs
ON 
  tables.table_catalog = count_jobs.project_id
  AND tables.table_schema = count_jobs.dataset_id 
  AND tables.table_name = count_jobs.table_id
ORDER BY 
  count_jobs.count_job, tables.table_catalog, tables.table_schema, tables.table_name
```

## ポイント

- INFOMARTION_SCHEMA.TABLESに、テーブルのメタデータが格納されている。
- 冒頭で記載したクエリの結果を結合することで、ジョブが発行されていないテーブルも含めて取得している。

# まとめ

- 今回の件で初めてINFORMATION_SCHEMAの存在を知りました。
- `start_time`カラム(ジョブの開始時間)、`end_time`カラム(ジョブの終了時間)もあるので、パフォーマンスの悪いクエリの抽出もできそう。
Laravelログイン認証のリダイレクトについて

#はじめに#
　Laravelを使うと簡単にログイン機能を実装できますが、反面、完成されすぎていてカスタマイズするには結構調べないといけません。大した内容ではありませんが、今回はそんな中でもリダイレクトについて備忘録として残して行きたいと思います。

#ログインしていないユーザーをリダイレクト#
　まずは、ログインしていない状態で、あるページにアクセスしようとするとログイン画面にリダイレクトする方法をご紹介します。ログイン前に表示させたくないコントローラーに下記のように書いてください。

```HomeController.php
public function __construct()
    {
       $this->middleware('auth');
    }
```

　これだけでOKです。何が起きているのかは正直よく分かりませんが、とにかくこれでログイン画面へリダイレクトされるようになります。認証に関わるものはMiddlewareで定義されています。ちなみに、リダイレクト先を変更する場合もMiddlewareで変更することが出来ます。

```App\Http\Middleware\Authenticate.php
　protected function redirectTo($request)
    {
        if (! $request->expectsJson()) {
            return route('リダイレクト先');
        }
    }
```
　
　デフォルトではloginがリダイレクト先になっていますが、自由に変えることが出来ます。


#ログアウト後のリダイレクト#
　認証機能を実装すると当然ログアウト機能も付いてきますが、ログアウトするとLaravelのトップページへリダイレクトされます。これも変更していきたいと思います。こんな感じで書き換えてみましょう。

```App\Http\Controllers\Auth\LoginController.php
//use AuthenticatesUsers;
use AuthenticatesUsers{
      logout as doLogout;
    }

    public function logout(Request $request){
      $this->doLogout($request);
      return redirect('/home');
    }
```

　これで、ログアウトするとhomeへリダイレクトするようになります。loginとするとログイン画面へ遷移します。

#まとめ#
　こんな感じで結構簡単に書き換えることは可能ですが、中身を理解しようとすると結構時間かかると思います・・・。（自分も全然理解できてませんので、もっと勉強していこうと思います。）
私達の最悪実行時間計測アプローチ

# はじめに
組込みソフトウェア開発では、処理負荷（最悪実行時間）を計測することが重要である。

炎上している大きな要因は、開発終盤での性能問題である。
炎上を退けるためには、早く性能の検証ができることが、ポイントである。
性能の検証の一つが、処理負荷（最悪実行時間）を計測することである。

私たちのプロジェクトで実施している処理負荷（最悪実行時間）計測のアプロ―を記録しておく。
私たちのプロジェクトの開発対象は、C言語で実装されたミドルウェアである。

# 私たちのプロジェクトでの最悪実行時間計測アプローチ
私たちのプロジェクトでは、最悪実行時間を計測するために、以下のようなハイブリッドな解析アプローチをとっている。

1. 公開APIの最悪実行時間の基準値（限界値）を決める
1. 関数単体で測定ベース解析により、最悪実行時間を算出
1. 関数コールツリーをもとに、関数単体の最悪実行時間を合計する
1. 3.で合計した最悪実行時間が、1.で決めた基準値を超える関数コールパスを特定する
1. 4.で特定した関数コールパスから、関連する公開APIを特定
1. 5.で特定した公開APIに対して、ソフトを結合して、実際の動作条件下で、測定ベース解析により最悪実行時間解析をする

ポイントは、難しい測定ベース解析での計測対象をできるだけ小さくする・減らすということである。

# 参考情報
## NCESの公開講座「リアルタイム性保証技術」
名古屋大学 大学院情報学研究科 附属組込みシステム研究センター（NCES）で、最悪実行時間計測に関連する以下の講座が実施されている。
https://www.nces.i.nagoya-u.ac.jp/NEP/courses/2021/T02.html

>講座概要
自動車や工作機械の制御システムなど，機械を制御する組込みシステムにおいては，与えられた時間要件を満たして動作することを保証すること（リアルタイム性保証）が求められます．
この講座では，このようなシステムにおけるリアルタイム性保証のための技術について，理論面と実践面の両面から解説します．特に，リアルタイムOSを用いて複数の処理を並行に実行している時に，各処理が時間制約を満たすことを検証するための理論体系であるリアルタイムスケジューリング理論について詳しく解説します．また，リアルタイムシステムの性能評価手法についても解説します．

>講義計画
1時限
・リアルタイムシステムとリアルタイム性保証
 -リアルタイムシステムとは？
 -リアルタイム性保証のアプローチ
 -リアルタイムOS（RTOS）とは？
・リアルタイムシステムの性能指標と最悪実行時間解析の困難性
 -リアルタイムシステムの性能指標
 -最悪実行時間解析の困難性
2時限
・最悪実行時間解析
 -タイミングスキーマによる解析
 -最適化問題への帰着による解析
・リアルタイム処理の性能評価
・リアルタイムスケジューリング理論(1)
 -Rate Monotonic Analysis
3時限
・リアルタイムスケジューリング理論(2)
 -Critical Instant定理
 -最適な優先度割付け
 -プロセッサ使用率によるスケジュール可能性判定
 -優先度逆転とその解決アプローチ
4時限
・リアルタイムスケジューリング理論(3)
 -非周期タスクの扱い
 -過負荷に対する対策とQoS制御
 -リアルタイムスケジューリング理論
 -適用事例
・アプリケーション統合のためのスケジューリング

### 講義受講メモ
・最悪実行時間解析は重要かつ困難
・解析結果と真の最悪実行時間の差が大きい悲観的な解析になりやすい
・起こり得ない実行パスがあると最長実行時間の合計が、全体の最長の時間になるとは限らない
・解析のアプローチには、静的解析と測定ベース解析とハイブリッド解析がある
・測定ベース解析は、実行時間が最長となるパスを特定することが難しい

# 参考記事

https://qiita.com/kazuo_reve/items/2c9a2d13bd57282bec1f

https://qiita.com/kazuo_reve/items/847a7b0a7988078c6cce
SDK とは

## 勉強前イメージ

開発するときに使うイメージ

## 調査

### SDK とは

Software Development Kit の略で、ソフトウェア開発キット が直訳になります。
あるシステムに対応したソフトウェアを開発するために必要なプログラムなどをひとまとめにしたパッケージのことで、
販売元が配布や販売をします。
1から作ると膨大な時間が必要なので、多くの開発者は必要な要素をまとめたSDKを使用してアプリケーションを開発します。

### SDKには何が入っている？

SDKには
APIや、サンプルコードやテストプログラムが入ったものまであります。
これらを利用して高度なアプリケーションを作成、追加、維持していくことが出来ます。

### よく聞くSDK

代表的なものとしては 
AndroidOS搭載のスマホアプリの開発用の Android SDKや
Java言語のSDK などがあります。
基本的には `○○DK(○○ Development Kit)` と呼ばれることが多いです。

## 勉強後イメージ

ほぼ開発したことがないので、まとまってるものなんだなぁって感じ

## 参考

- [今更ながら SDK について調べてみた](https://sitest.jp/blog/?p=12949)
- [SDKとは？～ソフトウェア開発環境を作るためのツールセット～｜データ分析用語を解説](https://www.gixo.jp/blog/12426/)
- [「SDKとは？」　SaaS連携の専門家が分かりやすく解説！](https://www.strategit.jp/column/about-sdk-1/)
【備忘】DynamoDBの確認に使うコマンド&ローカルで操作する際の気づき

# DynamoDBをローカルで操作する際のコマンド
Dockerを使ってローカルでDynamoDBを操作する際に使ったコマンドを備忘として書きます。
対象テーブル:users

## コマンド(随時更新する予定)
### テーブルの作成(簡易的な例)
```
aws dynamodb create-table --profile default --endpoint-url http://127.0.0.1:8000/ --table-name users --attribute-definitions AttributeName=id,AttributeType=S AttributeName=name,AttributeType=S --key-schema AttributeName=id,KeyType=HASH AttributeName=name,KeyType=RANGE --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
```

### テーブルの中身を見る
```
aws dynamodb scan --profile default --endpoint-url http://127.0.0.1:8000/ --table-name users
```

### テーブル削除
```
aws dynamodb delete-table --profile default --endpoint-url http://127.0.0.1:8000/ --table-name users
```

### DynamoDB Localのテーブル一覧の取得
```
aws dynamodb --profile default --endpoint-url http://127.0.0.1:8000/ list-tables
```

## 上記コマンドを実行する際の注意点
Dockerを使ってローカルでDynamodb操作をしたのですが、ローカルといえど事前にダミーのconfigとcredentialsを用意しないと「The config profile (default) could not be found」「Unable to locate credentials. You can configure credentials by running "aws configure".」といった感じでエラーが出ました。

下記コマンドを打ってダミーのcredentials, configを作成する必要がありそう。

```
C:\Users\Hoge>aws configure
AWS Access Key ID [None]: dummy
AWS Secret Access Key [None]: dummy
Default region name [None]: dummy
Default output format [None]: json
```
evil-define-keyが設定されない時に確認すること

## 背景

下記のようにinsertモードのキーバインド設定を行なった。
しかし所定のキー入力を行なっても想定した関数が呼び出されなかった。

    (evil-define-key 'insert org-mode-map
      (kbd "<tab>") `my/org-cycle
      (kbd "<S-tab>") `my/org-shifttab)


## 検証


### 1. キーマップを確認する。

```
M-x descrive-keymap RET org-mode-map
```

    ...
    <insert-state> <S-tab>          my/org-shifttab
    <insert-state> <tab>            my/org-cycle
    ...


### 2. 現在のモードを確認する

insertモードで下記のコマンドを実行

```
M-x describe-variables RET evil-state
```

    evil-state is a variable defined in `which-key.el'.
    Its value is hybrid

設定すべきstateは `insert` ではなく `hybrid` であることがわかる。


# 結論

`'insert` を `'hybrid` に修正したところ、想定どおりの挙動が確認できた。

    (evil-define-key 'hybrid org-mode-map
      (kbd "<tab>") `my/org-cycle
      (kbd "<S-tab>") `my/org-shifttab)
AtCoder 218_d SetとListの違いの復習

# はじめに
- この記事は、以下の問題の復習記事です
    - AtCoder 218_d Rectangle
        - https://atcoder.jp/contests/abc218/tasks/abc218_d
- いつもの感覚でListで処理したらTLE、解説ACでSetで処理したら通るので、どのくらい違うのか疑問に思って調べました。

# ACのソースコード
- https://atcoder.jp/contests/abc218/submissions/25830932
- Setで実装するとAC
- いつもだとListでやりがち
    - ○：p = set([tuple(input().split()) for _ in range(N)])
    - ×：p = [(input().split()) for i in range(2000)]
    
# テスト用データセットと計測の条件
- 以下の２パターンとする
    - Set ○：p = set([tuple(i, i) for i in range(2000)])
    - List ×：p = [(i, i) for i in range(2000)]
- テストデータセットとしては、単純に,(i,i)の点を2000個用意する
- 計測は、2点を選んで、他の２点を探索する部分だけを計測。（SetとListの入力部分を含まない）

# 計測結果
## Setでの実行結果
- elapsed_time:0.4602658748626709[sec]
- elapsed_time:0.46323299407958984[sec]
- elapsed_time:0.5020439624786377[sec]

## Listでの実行結果
- elapsed_time:210.26401782035828[sec]
- elapsed_time:225.0454020500183[sec]
- elapsed_time:206.4326469898224[sec]

# 結論
- こりゃListでTLEしたわけだ
- ポイントは以下の記事が参考になりました。inの処理が、ListだとO(N)、SetだとO(1)なのですね。勉強になりました。
    - https://qiita.com/bee2/items/4ab87d05cc03d53e19f9#in%E6%BC%94%E7%AE%97%E5%AD%90
【Jest入門】テストのグループ化

# はじめに

今回は、前回Jestが動く環境が作成できたので、テストのグループ化についてまとめたいと思います。

https://qiita.com/YSasago/items/6f23055c971a091f9993

## テストのグループ化

* Jestではテストを定義するために```test関数```を使います。
* test関数のエイリアスとして、```it関数```を利用することができます。
* テストをグループ化するためには、```describe関数```を利用します。
* テストをグループ化することで、グループ毎のテストができるようになり、わかりやすくなります。


## describe関数で、it関数とtest関数をグループ化

下記のコードは、引数で受け取った値がbirdであればtrueを返し、それ以外はfalseを返す簡単なコードです。

```javascript:src/group.js
export const isFly = (animal) => (animal === "bird" ? true : false);
```

```javascript:src/group.test.js
import { isFly } from "./group";

describe("#isFly", () => {
  test("A bird can fly", () => {
    expect(isFly("bird")).toBe(true);
  });
  it("A horse can not fly", () => {
    expect(isFly("horse")).toBe(false);
  });
});
```

describeでテストの結果がグループ化され、わかりやすくなっていることが確認できます。

```terminal:terminal
$ npm test /Users/jest-basic/src/group.test.js 

> jest-basic@1.0.0 test /Users/jest-basic
> jest "/Users/jest-basic/src/group.test.js"

 PASS  src/group.test.js
  #isFly
    ✓ A bird can fly (2 ms)
    ✓ A horse can not fly

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.384 s, estimated 1 s
Ran all test suites matching 
```
Blazor WebAssembly 社内IIS環境で公開まで

#はじめに
この記事ではBlazor WebAssemblyをIISを使い公開するまでの記事です。 今回公開するBlazor WebAssemblyのプロジェクトは認証あり、ASP.NET Coreでホストされたプロジェクトとなります。　※思い出しながら記事を書いています。抜けなどあるかもしれません。

#インストールが必要なもの
・IIS
・ASP.NET Core Runtime
・Hosting Bundle
・.NET Runtime 
・URL Rewrite

ASP.NET Core Runtime　/ Hosting Bundle / .NET Runtime / URL Rewrite
https://dotnet.microsoft.com/download/dotnet/5.0

URL Rewrite
https://www.iis.net/downloads/microsoft/url-rewrite

※すべてインストールしたら再起動が必要です。

#Visual Studioから発行
ターゲットランタイムはwin-x64にしています。 配置モードはフレームワーク依存でも、自己完結でも問題ないはずです。
![キャプチャ22.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110251/d9406e5a-9535-c0e7-c43e-eee8a2815d94.png)

![8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110251/8b807c82-a341-9d27-4f54-32d049b2d2c1.gif)

「正常に公開されました」と出たら任意のフォルダへコピーします。

#IIS上の設定
・自己証明書の発行
IIS公開する際にSSL証明書を選択する必要があります。自己証明書を発行すれば取りあえずは社内環境で使えるようになります。
![9.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110251/cf2e0366-e4e1-a04f-c8eb-f630c2f63b9a.gif)

#サイトの作成
アクセスされるIPアドレスとポートを設定しますが、ファイアウォールを開ける必要があります。
![10.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110251/beb614c0-f33e-fba4-2fbc-a2fa719cb110.gif)

#ユーザー権限の設定
コンテンツディレクトリの物理パスで設定したファイル全てに「IIS_IUSRS」「IUSR」ユーザーつ追加する必要があります。

#appsettings.jsonの編集 ※Identityを使っている場合のみ
テストで動かすためにappsettings.jsonを以下のように変更します。外部に公開する際などはNG.

```
  "IdentityServer": {
    "Clients": {
      "DAIZ.Client": {
        "Profile": "IdentityServerSPA"
      }
    }
  },
　　　　　　↓　
"IdentityServer": {
  "Key": {
    "Type": "Development"
  }
}
```

<br>
以上でIIS社内環境で使えるようになると思います。
文字列の全角・半角変換

# 全角文字を半角にしたい。
C#でコーディングしている同僚から、

> 全角から半角に変換したいんだけど、調べても「`Microsoft.VisualBasic.dll`を追加して`StrConv`を使え」というのばかり。C#で作ってるのにVisualBasicを使うのはなんか違和感

と。
うん。<font color="red">答え出てるよね。</font>
~~その変な違和感なんて捨てちゃって~~`StrConv`を使えばええやん。こんな感じやん。

```cs
Strings.StrConv(testStr, VbStrConv.Narrow, 0);
```
<br>
<br>




・・・と思いつつ、なんか方法ないかな？と調べてみたら

https://qiita.com/tricogimmick/items/5640798024837b782476

いいのあるよね。(@tricogimmickさん ありがとう)
<br>


と思ったのもつかの間、
> 同僚：　濁音、半濁音が混ざると文字が欠けるんだよねー

<br>
・・・・何言ってんだ？？欠けるわけないやん・・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1909386/5993b739-49d0-8d48-988b-7eee6450309f.png)
<font color="red">ほんまや！</font>・・・いや、だから素直にStrConvをと・・・（笑

と思いつつ私なりの改変を施した。

# 改変
```c#
// 文字列を変換する
public static string StringConvert(this string str, dwMapFlags flags)
{
    var ci = System.Globalization.CultureInfo.CurrentCulture;
    // すべての文字が濁音or半濁音かもしれないので２倍化
    string result = new string(' ', str.Length * 2);
    LCMapStringW(ci.LCID, (uint)flags, str, str.Length, result, result.Length);
    return result.TrimEnd();
}
```
・なんとなーく直感で、`str.Length`分の文字数しか返ってこないのでおかしいのかなー
　　→　２倍化してみるか
・なんとなーく`TrimEnd()`で締めくくろうか（なんか要らんかもしれんけど）

というテンションで改変（笑）

#結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1909386/c16396f3-bb24-d40d-571b-42072f483074.png)

うん。できたね。
もっとスマートな方法があるかもしれないし、この方法は実は違っている可能性もあるけれども、
要件はクリアしたので今回は良しとしよう。


# 改善
いただいたコメント、および「？」と思ったところがあったので書き換えました。
`string.EndTrim();` だと、元の文字列が`"あいうえお "`などのように末尾にスペースがある場合におかしくなったんだよなぁ・・・ 

```CS
/// <summary>
/// 文字列を変換する
/// </summary>
/// <param name="str"></param>
/// <param name="flags"></param>
/// <returns></returns>
public static string StringConvert(this string str, dwMapFlags flags)
{
    var ci = System.Globalization.CultureInfo.CurrentCulture;
    // すべてが濁音 or 半濁音かもしれないので２倍化しておく
    string result = new string(' ', str.Length * 2);
    // resultCount に変換後の文字数が格納される
    int resultCount = LCMapStringW(ci.LCID, (uint)flags, str, str.Length, result, result.Length);

    // 変換後の文字数分だけ返却
    return resultCount > 0 ?
        result.Substring(0, resultCount) :
        result;
}
```
<br>

実行結果が以下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1909386/8b753d28-6fb1-a84d-e207-d0fb68496d00.png)

いい感じかな？（だといいな）
Node-REDで2つの配列を結合する

Node-REDで２つの配列を結合する方法がわからなかったのでメモします。
Functionノードを使う場合と、JSONata式を使う場合を記載します。

# Functionノードを使う場合

array_1とarray_2を結合したい場合はconcatを使うと2つの配列を結合できます。
例えば、Functionノードに以下のように記載すると結合した結果がmsg.payloadに代入されます。

```javascript
let array_1 = [1,2,3];
let array_2 = [4,5,6];
msg.payload = array_1.concat(array_2);
return msg;
```


# JSONata式を使う場合

array_1とarray_2を結合したい場合は`$append`を使用します。


```json
$append(array_1,array_2)	
```

例えば、changeノードに以下のように記載すると、結合した結果がpayloadに代入されます。

![Screenshot 2021-09-13 22.41.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432669/2083a7db-9d86-f4fc-d30b-1c9fdb885f9b.png)



ノードの例を以下に記載します。

```
[{"id":"e5a5772ff8540a69","type":"inject","z":"9e623264ef90ad1e","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":250,"y":120,"wires":[["7ca3081dcf96fa12"]]},{"id":"d1b43237f8c4ac75","type":"debug","z":"9e623264ef90ad1e","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":670,"y":120,"wires":[]},{"id":"7ca3081dcf96fa12","type":"change","z":"9e623264ef90ad1e","name":"配列の結合","rules":[{"t":"set","p":"array_1","pt":"msg","to":"[1,2,3]","tot":"json"},{"t":"set","p":"array_2","pt":"msg","to":"[4,5,6]","tot":"json"},{"t":"set","p":"payload","pt":"msg","to":"$append(array_1,array_2)\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":120,"wires":[["d1b43237f8c4ac75"]]}]
```

# まとめ

配列を結合する方法を2通り紹介しました。
個人的にはFunctionノードをあまり使いたくないため、JSONata式を利用した方法を活用していきたいと考えています。

その他、もっとかんたんな結合方法をご存じの方がいれば教えて下さい。
言語ごとの命名規則を整理する

記念すべきQiita投稿1回目です。宜しくお願いします。

#はじめに
私はこれまでJavaをメインで使ってきましたが、半年前くらいにC#の開発にアサインされました。
既存コードを参考になんとなくコーディングしてきましたがあやふやな部分も多く、
今更ですが命名規則についてまとめておきたいと思いました。

#スタイル
まずは命名規則に使われるスタイルのおさらいから。
覚えるの苦手でいつも忘れてしまう・・・

| 種類       |説明         |
|:-----------|:------------|
| キャメルケース<br />camelCase  | 最初の単語を小文字から始めて、それ以外の単語を大文字から始める。<br />単語と単語はそのままつなげる。|
| パスカルケース<br />PascalCase |すべての単語を大文字から始める。<br />単語と単語はそのままつなげる。|
| スネークケース<br />snake_case |すべての単語を小文字にする。<br />単語と単語はアンダーラインでつなげる。|
| アッパースネークケース<br />SNAKE_CASE |すべての単語をすべて大文字にする<br />単語と単語はアンダーラインでつなげる。|


#命名規則
Java、JavaScript、C#で比較します。

| 種類 | Java |JavaScript  | C# |
|:-----------:|:-----------:|:------------:|:------------:|
| クラス       | Pascal        | Pascal        |Pascal|
| インターフェース     | Pascal| - |"I" + Pascal|
|パッケージ / ネームスペース|camel| - |Pascal        |
| メソッド     | camel| camel|Pascal|
| メンバ変数       | camel| camel|Pascal        |
| ローカル変数         | camel| camel|camel|
| 定数       | SNAKE_CASE|SNAKE_CASE|Pascal        |

並べると違いがよく分かりますね。
Javaしかやってこなかった人間として感じた違和感の正体があらわになった気がします。
メソッドとメンバ変数はPascalなんですね。ここが違和感あり。
あと今のC#の現場で定数はアッパースネークケース使っている気がします。
ローカル変数だけcamelで他はPascalと覚えておけばよさそうですね。

#おわりに
たぶんまだ忘れてしまうんだろうな・・・と思いながらもまとめてみました。
こんな感じで基礎的な知識でも気になったことを中心に、毎週投稿を目標にしたいと思っています。
Raspberry pi にRTL8814AUのWiFiアダプタのドライバをインストールする

#Raspberry piにWiFiアダプタのドライバをインストールするには,このコマンドが最強だと思っていた

```
sudo wget http://downloads.fars-robotics.net/wifi-drivers/install-wifi -O /usr/bin/install-wifi
sudo chmod +x /usr/bin/install-wifi
sudo install-wifi
```

####しかし、このコマンドは[ここ](http://downloads.fars-robotics.net/wifi-drivers/8812au-drivers/)にあるドライバしか自動でインストールできない...
:::note info
8812auのドライバなら上記のサイトでOK
:::
:::note alert
8814auのドライバはNG
:::

しかし、8814auのチップのWiFiアダプタでも8812auのドライバで動いていたから、私は気づかなかった。
ちゃんとチップを調べないと....


######さあ困った

raspberry piは8812auのドライバでも8814auのチップのWiFiアダプタを認識し、AP化もできた。

####しかし、遅延するは、再接続できない、など問題多発。

###そうなると、8814au用のドライバが必要だ！

####調べた結果....


#GitHubに上がってました！
[https://github.com/aircrack-ng/rtl8814au](https://github.com/aircrack-ng/rtl8814au)

####これです！これ！これを求めていたんです！

しかし、readmeだけを読んでもうまいこといかない...

気づきました、[こっち](https://github.com/aircrack-ng/rtl8812au)のやり方を真似したらいいんだ！


ということで、まとめます。

##GitHubをまんまコピーしてもできない

```
git clone https://github.com/aircrack-ng/rtl8814au.git
cd rtl8814au
make
make install
```

##こうしました！


```
sudo apt-get install raspberrypi-kernel-headers
git clone https://github.com/aircrack-ng/rtl8814au.git
cd rtl8814au
```


***
####raspberry pi 1/2/3/ & zeroはこちらのコード

```ruby:RPI1/2/3/&0/Zero
sed -i 's/CONFIG_PLATFORM_I386_PC = y/CONFIG_PLATFORM_I386_PC = n/g' Makefile
sed -i 's/CONFIG_PLATFORM_ARM_RPI = n/CONFIG_PLATFORM_ARM_RPI = y/g' Makefile
```
***


####raspberry pi 3B+ & 4Bはこちらのコード

```ruby:RPI3B+&4B
sed -i 's/CONFIG_PLATFORM_I386_PC = y/CONFIG_PLATFORM_I386_PC = n/g' Makefile
sed -i 's/CONFIG_PLATFORM_ARM64_RPI = n/CONFIG_PLATFORM_ARM64_RPI = y/g' Makefile
```
***

###sudo入れないとややこしい
```
sudo make 
sudo make install
```


###これで8814auチップのWiFiアダプタが動いた！！！


自分が動かしたのは,8814auチップのWiFiアダプタはこちらです。
[I-O DATA WiFi 無線LAN 子機 11ac 1300Mbps USBバスパワー IPv6 土日サポート WN-AC1300UA](https://www.amazon.co.jp/gp/product/B084B8Y4TY/ref=ppx_yo_dt_b_asin_title_o05_s00?ie=UTF8&psc=1)

[WAVLINK WiFi 無線LAN 子機 AC1900 1300+600Mbps デュアルバンド USB3.0 アダプター WPSボタン 吸着機能あるクレードル付き 高速通信4X3dBi Windows7/8/10/Mac OS X 対応 WLAMJP2C-WN693A5](https://www.amazon.co.jp/gp/product/B094DDRNSY/ref=ppx_yo_dt_b_asin_title_o07_s00?ie=UTF8&psc=1)


8812auのWiFiアダプタは[こちらの記事](https://qiita.com/wear_volt/items/4e05a7a9899aacb00e87)で細かく書いてます。

###Raspberry piのWiFiアダプタに、ここまでこだわってる人がなかなかいない気がする......

以前、8812auチップのWiFiアダプタを使ってAP化したRaspberry pi zeroと、
Raspberry Pi３や４を１つのSDカードで共同利用したい！と思ったが

#####8812auのドライバは機種によって違うため、zeroでAP化した場合、ドライバが違う３や４では使えないということだった....

[ここ](http://downloads.fars-robotics.net/wifi-drivers/8812au-drivers/)で見ていくと、機種別でドライバが違う。

| ファイル名 | Raspberry Pi |
|:-:|:-:|
| 無印|  Pi1、PiZero、PiZeroW、CM |
|  v7 | Pi2、Pi3、Pi3+、CM3  |
|  v7l |  Pi4 |

これもまた、このコマンドを買いかぶりすぎたせい....

```
sudo wget http://downloads.fars-robotics.net/wifi-drivers/install-wifi -O /usr/bin/install-wifi
sudo chmod +x /usr/bin/install-wifi
sudo install-wifi
```

AP化しなければ、機種を変えても問題ないんだろうけど、自分はAP化しているので詰まったというお話。
ここ三年、秋になるとラズパイのWiFiアダプタに苦しめられる。

お疲れさまでした。
【GAS初歩】特定の日時まで、定期的に現時点のGoogleフォームの回答数をDiscordに投稿する

イベントの申し込みやアンケートの回答の状況を定期的に把握しておきたい（特にチームでなんか運営していて、集まりが芳しくないときにプッシュせにゃならぬ）ときがある。
総数だけ知りたい。その数。それ。
![setting_trigger_210913_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62270/d0b204f9-805a-4ece-c74b-4bd3e5f25728.png)
…ので、それ用のお手軽コードを書いた。


# 作業すること（全体の流れ）
1. Googleフォームにスクリプトを書く
2. トリガーを登録する
3. Discordに結果が届くのを待つ

# スクリプト抜粋
### 回答数を調べるところ

フォームの回答数は、単純に [Form クラス](https://developers.google.com/apps-script/reference/forms/form)の `getResponses()` の戻り値の数を取得するだけ。

```
FormApp.getActiveForm().getResponses().length
```

### Discord に投稿するところ
Discord の特定のチャンネルへの投稿は [UrlFetchApp](https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app) クラスの `fetch(url, params)` を使う。Webhook URL の取得方法は割愛。

```
const m = `現在の回答数 ${FormApp.getActiveForm().getResponses().length}`; //回答数
const u = '[Webhook url]'; //Discord の Webhook URL を貼付
const o = {'method':'post',
            'contentType':'application/json',
            'payload':JSON.stringify({'content':m})};
try{
  const r = UrlFetchApp.fetch(u, o);
  Logger.log(`code=${r.getResponseCode()}`); //204ならヨシ!!
}catch(e){ Logger.log(e); }
```
### 特定の日時に処理を実行するところ
めんどくさいので今回は `myFunction()` に全てのコードを書いて、それをトリガーに登録するだけにした。1回だけ実行するならこれでOK。
![setting_trigger_210913.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62270/1f94acd4-2196-3d63-fa6b-2284b47bd6cb.png)
日付の書式は `YYYY-MM-DD HH:MM`。

### 特定の日時になるまで毎日特定の時間にチェックするところ
現在の状況をなんとなく毎日知りたいので、先のトリガを「日付ベースのタイマ」に変更して、 `myFunction()` の最後の行に下記3行を追加した。

```
const nd = new Date(); //now date
const cd = new Date('[YYYY-MM-DD HH:mm]'); //for compire
if(nd>=cd)ScriptApp.getProjectTriggers().forEach(i=>ScriptApp.deleteTrigger(i));
```

![setting_trigger_210913_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62270/33c8542e-3655-7857-40bf-dc29bba85f9b.png)

# コード全体
[count_now_formresponses.gs (現在のフォームの回答数を定期的にDiscordに投げ飛ばす)](https://github.com/togazo/samples/blob/master/others/GAS/count_now_formresponses.gs)
Ruby3.x+Rails6+CircleCI+Rspec+Rubocop+MySQL8のプロジェクト作った。(ソースコードあり)

プロジェクトを立てるたびに同じようなプロジェクト作成作業をするのが手間なので、ソースコードを残しておく。
OSSライセンスにしておくので、この環境で使いたい人がいたら、使ってください。

# 環境
Ruby3.x
Rails6
CircleCI
Rspec
Rubocop
MySQL8


# ソースコード

https://github.com/outsource-systems/rails6-sample-app
Unity スクリプトからゲームオブジェクトとクラスの適用

### 1.適当にクラスを用意する。
```C#
public class InpGameObject : MonoBehaviour
{
    public async Task<string> GetKey()
    {
        var ret="";
        while (ret==""){
            ret = Input.inputString;
            await Task.Delay(16);
        }
        return ret;
    }
}//class
```

### 2.外からクラスを割り当てて呼び出す。（MonoBehaviourの無いクラスを想定）
```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class test : MonoBehaviour
{
    // Start is called before the first frame update
    async void Start()
    {
        var o =new GameObject("_inp");//空のゲームオブジェクトを生成
        o.AddComponent<InpGameObject>();//コンポーネントを割り当てる。
        while(!Input.GetKeyDown(KeyCode.Space)){
            var ret=await o.GetComponent<InpGameObject>().GetKey();//call
            Debug.Log(ret);
            await System.Threading.Tasks.Task.Delay(5);
        }
        
    }
}

```
<%= form_with do |f| %> updateやcreateが発火/動作しない問題

#<%= form_with do |f| %> updateやcreateが発火しない問題
コントロールやモデルに問題があるコードがないのに発火/動作しない...
updateやcreateができない原因は使っている<B>タグ</b>、ビューファイル（html.erb）に問題があるかも

```java:タグ
<div></div>
<table></table>
いっぱいあるけど割愛

```


##うまく動作しない集
```java:form
<form>#bootstrapで参考しがちなformタグ..これをform_withと併用するとうまく発火しない原因になる。
<%= form_with model:@user, local:true do |f| %>
<%= f.label :profile_image %>
<%= attachment_image_tag @user, :profile_image, :fill, 30, 30, fallback: "noimage.png"%>
<%= f.submit %>#submitボタンを押して画面がrenderみたいに遷移する
</form>#form_withを消して<div>で囲もう！
```

```java:tabel
<table>#テーブルタグも同様になる可能性がある。あまり使わない方がいい
<%= form_with model:@user, local:true do |f| %>
<%= f.label :profile_image %>
<%= attachment_image_tag @user, :profile_image, :fill, 30, 30, fallback: "noimage.png"%>
<%= f.submit %>
</table>
```

```java:しっかりとタグで囲もう！！


<%= form_with model:@user, local:true do |f| %>
<div>------------------------------------------------------------------------------------
<%= f.label :profile_image %>
<%= attachment_image_tag @user, :profile_image, :fill, 30, 30, fallback: "noimage.png"%>
<%= f.submit %>
</div>-----------------------------------------------------------------------------------
divで変な囲い方をすると発火しない原因になる
```
【Git】変更履歴確認方法


# ファイルの「行単位」の変更コミットIDを確認

```bash
# 行単位のコミットIDを確認可能
$ git blame <ファイル名>
```

# 「コミット単位」の変更履歴を確認


```bash
# 最新のコミットの詳細を表示する
$ git show

# 指定したコミットの詳細を表示する
$ git show <コミットのハッシュ値>
```

---
### 会社紹介

**株式会社 Mosaica**  
最先端テクノロジーで社会課題を解決し、持続可能な未来を創造する IT カンパニー。
AI ソリューション、クラウド統合、DX 推進、経営コンサルティングなど包括的なサービスでビジネス変革を支援しています。  

詳しくは [公式サイト](https://mosaica.co.jp/) までお気軽にご相談ください。
公式サイト： https://mosaica.co.jp/
OpenVPN でハイパフォーマンスを求めるなら lz4-v2 ではなく lzo をつかう

## 背景

Solana validator など通信量とレイテンシが求められるももの UDP proxy として OpenVPN を使っている

Proxy ノード(e.g. VPS) と手元 PC 間は最大 50 M bps くらい.
Proxy ノードの CPU はそんなにつよつよではない.

lz4-v2 は, 一応 OpenVPN マニュアルでも推奨しているっぽいようなので使ってみましたが, なんかおそすぎました.

## 解決

lz4-v2 は, CPU 処理負荷が高いのか, バッファリングのサイズが大きくなるからなのか, lz4-v2 だとレイテンシが遅くなってしまいました.

細かいパケットを扱うような場合は lzo 圧縮を使いましょう. 非圧縮でもいいかもですが, その場合は Proxy <-> 手元 PC の帯域がボトルネックになってしまうかもしれません.


```
compress lzo
```

たとえば OpenVPN クライアント(手元 PC)から `ping www.google.com` では lz4-v2 だと 100 ms くらいでしたが, lzo だと 15 ~ 20 ms くらいでした.
(Proxy ノードから直の ping だと 1.5 ms くらい)



特に OpenVPN は single-thread 実行のため(v 2.x), 圧縮すると CPU 負荷も増えてしまうという問題があります.

## TODO

* [ ] `lz4` だとどうなるか調べる