OmniAICreator/Qiita-1.07M huggingface dataset:
PythonとFlaskをインストールする(Windows10)

### 参考サイト
- [Python3.7 windows10環境で『Flask』の最小構成を試す](https://karupoimou.hatenablog.com/entry/2019/05/20/191515)

Python3.7のインストール
https://www.python.org/downloads/release/python-376/

上記からインストーラタイプ(`Windows x86-64 executable installer`)をDL

インストールする(もし、PATHが通っていなかった場合は再実行し
`Modify→add python to environment variablesにチェックを入れ再インストール`

インストールされているか確認

```
python -V

Python 3.7.6
```

Pythonインストール確認後、下記コマンドでFlaskをインストール

```
pip install flask
```

作業ディレクトリにmain.pyを作成し、以下を記述

```python
#coding:utf-8

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return "Hallo World!"

if __name__ == '__main__':
    app.debug = True
    app.run()

#デバッグモードTrueにすると変更が即反映される
#ファイルのエンコードはUTF-8で保存すること
#下記URLをブラウザに打ち込むとページが開く
# http://127.0.0.1:5000/
```

その後、作業ディレクトリで以下のコマンドを実行

```
python main.py
```

アプリが実行されるので、http://127.0.0.1:5000/ へアクセスして確認
GITHUBの日付の表示を相対表示から絶対表示に変換するブックマークレット

GITHUBの日付の表示が`...4days ago`みたいな相対表示なのを、
絶対表示で確認するために設定などを探していた時に見つけたブックマークレット（https://qiita.com/kobake@github/items/06dcc5b6135fd38adeb7）が古くて動かなくなっていたため、新しく作りました。

``` JavaScript
javascript:var%20times%3Ddocument.querySelectorAll('relative-time')%3Bfor(var%20i%3D0%3Bi%20%3C%20times.length%3Bi%2B%2B)%7Bvar%20date%3Dnew%20Date(times%5Bi%5D.getAttribute('datetime'))%3Bvar%20dateString%3D''%3BdateString%20%2B%3Ddate.getFullYear()%2B%20'%2F'%3BdateString%20%2B%3D('0'%20%2B(date.getMonth()%2B%201)).slice(-2)%2B%20'%2F'%3BdateString%20%2B%3D('0'%20%2B%20date.getDate()).slice(-2)%2B%20'%20'%3BdateString%20%2B%3D('0'%20%2B%20date.getHours()).slice(-2)%2B%20'%3A'%3BdateString%20%2B%3D('0'%20%2B%20date.getMinutes()).slice(-2)%2B%20'%3A'%3BdateString%20%2B%3D('0'%20%2B%20date.getSeconds()).slice(-2)%3Btimes%5Bi%5D.innerText%3DdateString%3B%7Dvoid(0);
```

元のスクリプト

``` JavaScript
var times = document.querySelectorAll("relative-time");
for (var i = 0; i < times.length; i++) {
  var date = new Date(times[i].getAttribute("datetime"));
  var dateString = "";
  dateString += date.getFullYear() + "/";
  dateString += ("0" + (date.getMonth() + 1)).slice(-2) + "/";
  dateString += ("0" + date.getDate()).slice(-2) + " ";
  dateString += ("0" + date.getHours()).slice(-2) + ":";
  dateString += ("0" + date.getMinutes()).slice(-2) + ":";
  dateString += ("0" + date.getSeconds()).slice(-2);
  times[i].innerText = dateString;
}
```
Rails 「Markdown記法の導入について」

#はじめに
標題の通り、作成しているアプリにMarkdown記法をできるようにしました。
何とか導入できましたので、復習も兼ねてoutput致します。
もうすでにご存知の方、省略の仕方等ご存知でしたら、ご教授願います。


#開発環境
- ruby 2.6.3
- Rails 5.2.4.1
- macOS Catalina 10.15.3
- VScode 1.42.1

#必要なGem
```
Gemfileに追記

gem 'redcarpet'
```

その後、bundle installです。

#redcarpetの機能を利用するための準備
- app/helpers内に「markdown_helper.rb」ファイルを作成する。
- markdown_helper.rb内に以下を記述する。

```markdown_helper.rb
module MarkdownHelper
  def markdown(text)
    unless @markdown
      options = {
        hard_wrap: true
      }
      extensions = {
        no_intra_emphasis: true,
        tables: true,
        fenced_code_blocks: true,
        autolink: true,
        quote: true
      }
      renderer = Redcarpet::Render::HTML.new(options)
      @markdown = Redcarpet::Markdown.new(renderer, extensions)
    end
    @markdown.render(text).html_safe
  end
end
```
textに反映させるイメージで導入致しました。
htmlから変換できるようになっております。

#適用したいviewsフォルダ内へ追記

＊〜＊間は随時変更してください。

```show.html.erb
 <span><div><%= markdown(@*comment.task.title*) %></div></span>
```

#結果

<img width="653" alt="markdown1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576541/073bfa90-d68e-747b-2be7-d599d9d029bc.png">
<img width="555" alt="markdown2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576541/bc9d7a5f-4a28-9372-fabf-3c10c5034594.png">


##参考記事
勉強になりました。ありがとうございます。
@hkengo 様　https://qiita.com/hkengo/items/978ea1874cf7e07cdbfc
@shimoch 様　https://qiita.com/shimoch/items/466ed5cc5c232e58b34f
redcarpet公式README　https://github.com/vmg/redcarpet


#さいごに
日々勉強中ですので、随時更新します。
皆様の復習にご活用頂けますと幸いです。
スマホの充電をオフグリッドしてみた

#できたもの
![CDF563DB-A98F-4FA9-B9AF-376FF80A8932.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482921/dbdc1103-be2d-bd5e-3ebc-af2922db119e.jpeg)

#きっかけ
電力会社の作る火力発電の電気を使い続けるのに不安を感じたが、いきなり完全にオフグリッドするというのはビビリなわたしには怖かった(？)から。
#やること
ソーラーパネルからモバイルバッテリーに給電して、充電が終わったらスマホに給電する。
#用意するもの
・やる気
Amazonなどでは購入できないっぽい。売ってるところがあったら教えてください。
・モバイルバッテリー
Anker PowerCore 26800 (26800mAh 超大容量 モバイルバッテリー) 
がおすすめ(用意できなかったのでcheero製を使った)(cheeroももちろんいいですよ！)
(Amazonリンク)
https://www.amazon.co.jp/Anker-PowerCore-【デュアル入力ポート-3台同時充電】iPhone-新しいMacBook他各種対応/dp/B01JYL3IF4?ref_=ast_sto_dp&th=1&psc=1
・モバイルバッテリー充電用ケーブル
なんでもいいけどできるだけ高品質なものを(私の場合ソーラーパネルについていた)
・ソーラーパネル
これを使った
(Amazon)
https://www.amazon.co.jp/Anker-PowerPort-ソーラーチャージャー-Android各種他対応-【PowerIQ搭載】/dp/B012VOBXU8/ref=sr_1_2?__mk_ja_JP=カタカナ&crid=1SSP19U2F2CNN&keywords=anker%2Bsolar%2Bcharger&qid=1583199526&sprefix=Anker%2BSolar%2Caps%2C274&sr=8-2&th=1

##あると便利なもの
・USBハブ
モバイルバッテリーに貯めた電気を多くのデバイスに供給するため(使えるかは未確認)

#やり方
と言っても繋げるだけ
Anker製が高品質だからか知らないけど、家の窓ガラスにペタァーでも発電できた(写真非掲載)

#まとめ
案外簡単にオフグリッド(笑)できた。
今後は、USBハブが使えるかの確認と、AC電源への変換(はAnkerがそれっぽいモバイルバッテリー出してたな)などをやっていきたい(Qiitaに書くかはわからない)
(Qiitaへの記事投稿は初めてで、まともなものになってるかは不安ですが、面白いものになっていたら幸いです。)
Go でリフレクションを使って struct をバリデーションする

Go 言語で、テストに必要な Variables　がちゃんとセットされているか確認したいという要望があった。その Variables もいろんなところに分散していたら面倒なので、一か所で書きたかった。つまりこんなイメージ。

```go
type Foo struct {
	Bar string `env:"TF_VAR_hello"`
	Baz string `env:"TF_VAR_world"`
}
```
こんな感じで構造体を書いておくと、自動で、`TF_VAR_hello` と `TF_VAR_world` の環境変数を読み込んで、それをそれぞれのフィールドにセットしてほしい、そしてすべてのフィールドがちゃんとなんかしらの値がセットされていてほしい。

このような要件の時はリフレクションだけど、Goではやったことなかったので調べて試してみた。

# フィールドの読み込み

定義されたすべてのフィールドの読み込みは次のコードで可能になる。ちなみに、`s` は、ポインターでも実体でも良い。

```go
func validate(s interface{}) {
	val := reflect.ValueOf(s).Elem()

	for i := 0; i < val.NumField(); i++ {
		valueField := val.Field(i)
		typeField := val.Type().Field(i)
		tag := typeField.Tag

		fmt.Printf("Field Name: %v, \t Field Value: %s,\t Tag value: %s\n", typeField.Name, valueField, tag)
	}
}
```

Mainから実行してみる。

```go
func main() {
	foo := &Foo{
		Bar: "abc",
		Baz: "def",
	}
	validate(foo)
}
```

## 実行結果

```bash 
Field Name: Bar,         Field Value: abc,       Tag value: env:"TF_VAR_hello"
Field Name: Baz,         Field Value: def,       Tag value: env:"TF_VAR_world"
```

# フィールドへの値のセット

フィールドへの値のセットは次のように行う。`interface{}`なので、型チェックをしてから、`SetString()` などで型を明確にしてとると良い。

```go
	for i := 0; i < val.NumField(); i++ {
		if val.Field(i).Kind() == reflect.String {
			val.Field(i).SetString("overriden")
		}
	}
```

更新した後は、ついでに、Tagの値をとるようにしましょう。とても簡単。

```go

	for i := 0; i < val.NumField(); i++ {
		valueField := val.Field(i)
		typeField := val.Type().Field(i)
		tag := typeField.Tag

		fmt.Printf("Field Name: %v, \t Field Value: %s,\t Tag value: %s\n", typeField.Name, valueField, tag.Get("env"))
	}

```

# 実行結果

```bash
$ go run *.go
Field Name: Bar,         Field Value: abc,       Tag value: env:"TF_VAR_hello"
Field Name: Baz,         Field Value: def,       Tag value: env:"TF_VAR_world"
Field Name: Bar,         Field Value: overriden,         Tag value: TF_VAR_hello
Field Name: Baz,         Field Value: overriden,         Tag value: TF_VAR_world
```

ちなみに、`interface{}` を元の型にキャストしたいときはこんな感じ。TypeValidationが必要です。ちなみに、`DeserializeVariablesStruct` は自分で書いた関数で、Tagを元に環境変数から値をセットして、
Structを戻す関数です。

```
	result := DeserializeVariablesStruct(&Foo{})
	foo := result.(*Foo)
```

思ったよりずっと簡単やった。もっとAPIを掘りたいところやけど、今日はここまで。

# 全ソースコード

```go
package main

import (
	"fmt"
	"reflect"
)

// Foo is a testing struct
type Foo struct {
	Bar string `env:"TF_VAR_hello"`
	Baz string `env:"TF_VAR_world"`
}

func main() {
	foo := &Foo{
		Bar: "abc",
		Baz: "def",
	}
	validate(foo)
}

func validate(s interface{}) {
	val := reflect.ValueOf(s).Elem()

	for i := 0; i < val.NumField(); i++ {
		valueField := val.Field(i)
		typeField := val.Type().Field(i)
		tag := typeField.Tag

		fmt.Printf("Field Name: %v, \t Field Value: %s,\t Tag value: %s\n", typeField.Name, valueField, tag)
	}

	for i := 0; i < val.NumField(); i++ {
		if val.Field(i).Kind() == reflect.String {
			val.Field(i).SetString("overriden")
		}
	}

	for i := 0; i < val.NumField(); i++ {
		valueField := val.Field(i)
		typeField := val.Type().Field(i)
		tag := typeField.Tag

		fmt.Printf("Field Name: %v, \t Field Value: %s,\t Tag value: %s\n", typeField.Name, valueField, tag.Get("env"))
	}

}

```
Gitのconfigの設定、ローカルからリモートへのpush

ローカル環境のコマンドライン上でgitリポジトリを作成した際に
設定し忘れることがあるのでメモっておく。

- Author、Commiterの設定

```
$ git config --local user.name "Name"
$ git config --local user.email "Email"
```
- gitのAuthor、Commiterの変更

```
$ git filter-branch -f --env-filter "GIT_AUTHOR_NAME='Name' GIT_AUTHOR_EMAIL='Name' GIT_COMMITTER_NAME='Name' GIT_COMMITTER_EMAIL='Email'" HEAD
```

- ローカルで作成したリポジトリからリモートへのpush

1. githubでリモートリポジトリを作成する
2. 以下のコマンドでリモートにpushする  

```
$ git remote add origin https://github.com/リモートリポジトリ
$ git push -u origin master
```

`git remote add origin https://github.com/リモートリポジトリ`
このコマンドでローカルとリモートを関連付ける
個人的資格試験計画（適宜更新）

Qiitaで役立ちそうな話題の資格は体験記を書いていこうと思ってますが、
それ以外の資格はまぁいっかって感じです（受かったよーって報告だけ）。

割と資格試験って「肩書き欲しいんじゃないの？」とか「受かっても使えないんじゃ意味ない」
まぁそういう人には言わせておけばいいです。

個人的には資格試験合格がゴールではなくて、必要最低限の知識がついたスタート地点と
考えているので日々努力とかは必要だな～と。

ぶっちゃけ自分にとって資格は努力の可視化としか思ってないので。

そんな感じで僕の試験計画備忘録です。
~~※2021年には転職したいな～と思っているので大幅な予定変更はあるかも。~~
→ なんか会社で新しい部署立ち上げたので手を挙げてみたら選ばれてしまい
　データアナリスト的な立場になれそうなので残ってみた。

※所持資格
・臨床工学技士
・第2種ME技術者
・甲種危険物取扱者（乙種全種所持後に受けた）
・ITパスポート
・QC検定 2級
・統計調査士
・G検定
・Python3 エンジニア認定データ分析試験

# 2020年
・1/26
　甲種危険物取扱者（2/13：合格）

・4/19
　ITパスポート　→　COVID-19により中止

・6/21
　統計検定2級 → COVID-19により中止（CBTで受けるつもり）

・9/6
　QC検定2級　→　不合格

・11月
　統計調査士　→　COVID-19により中止（CBTで受けるつもり）

・12/20
　ITパスポート　→　[合格（試験後の採点で）](https://qiita.com/Under_the_mountain/items/001ebf1df08cf16f593e)

# 2021年
・1/30（土）
　統計検定2級（CBT）→ 不合格

・3/21（日）
　QC検定2級 → 合格（4/28:Web発表）

・6/27（日）
　統計調査士（CBT）→ 合格（即日発表）

※2021年はここで燃え尽きる

# 2022年
・7/4（土）
　G検定 → 合格（7/15：web）
　ぶっちゃけ機械学習の手法・DeepLearningの手法であまり点数取れていないので
　あまり納得がいかない試験でした。
　合格記執筆中

・9/17（土）
　Python3 エンジニア認定データ分析試験 → [合格（即日合否）](https://qiita.com/Under_the_mountain/items/2599ea61213cb988b679)
　925/1000点での合格。思った以上に簡単だったのは、業務でやっていたから？

・12/3（土）
　データサイエンティスト検定™ リテラシーレベル　→　不合格
　データサイエンス力とビジネス力はそれぞれ7割と9割くらい取れてたものの、
　データエンジニアリング力が「え？なんでこんなに取れてないの？」ってほど点数低かったです。
　弱点が分かって良かったということで。

# 2023年
・3/19（日）
　統計検定3級　→　不合格（合格点まであと1問という事実に、放心）

・9/30(土)
　AI実装検定B級　→　合格（得点9割弱）
　さすがに業務でやってることの初歩の初歩を落とすわけにはいかぬ。。。
　A級受験でも良かったけど、合格祝い金がそれなりに高かったので。

・12/2（土）
　統計検定3級　→　合格
　とりあえず、確率が苦手だったので高校数学からやり直して何とか合格。
　データ分析者が確率弱いのはなんとかしたいので、重点的に勉強せねばなと思いました。


# とりたいなーと思っている資格
・E資格（講座代高すぎ問題）
・AI実装検定（S級、A級）
・基本情報技術者試験, 応用情報技術者
・データベーススペシャリスト
・統計検定の各級
・統計検定　専門統計調査士
・QC検定1級
・データサイエンティスト検定™ リテラシーレベル
・日商簿記2級, 3級
C言語　ポインタを使用した配列の初期化方法。ポインタも実は数字。

ポインタをインクリメントさせるところの書き方が初心者には理解しにくいので解説。

```c
#include <stdio.h>

int main(void)
{
    int i;
    unsigned short int num[8];
    unsigned short int *np;
    np = num;

    for(i = 0; i<8; i++){
        *np = 0;
        np++;
    }

    return 0;
}

```

##ポインタは、intではないのになんで「np++」というインクリメントさせるような書き方が可能なのか。
実はポインタも数値だからです。だから下記のような書き方がされています。
メモリには，__場所を表す「アドレス」という連続した通し番号（整数の値）__が振られています。なので、足したり、引いたりすることが可能です。
これは、charが実は文字コードを使って文字として表示されているだけで実は数字であることと同じです。



```c
    for(i = 0; i<8; i++){
        *np = 0;
        np++;
    }
```



##おまけ
上記のコードは下記のように省略して書くことも可能です。

*np(npの通常編集モード）に0を代入した後、ポインタnpのアドレスを1つ進める。という動作を表しています。
演算子の優先順位を利用した書き方です。
先に格納して、次に足し算を行うという仕様を使っています。

```c

    for(i = 0; i<8; i++){
        *np++ = 0;
    }

```



###参考
もう一度基礎からC言語 第24回 データ構造(3)～ポインタの基本 ポインタと配列
https://www.grapecity.com/developer/support/powernews/column/clang/024/page02.htm


第３回　アドレスとポインタ変数
http://www.isc.meiji.ac.jp/~re00079/EX2.2011/20110518.html
gitを使うためのssh keyの登録

[流れ](https://employment.en-japan.com/engineerhub/entry/2017/01/31/110000#GitHub%E3%81%AB%E5%85%AC%E9%96%8B%E9%8D%B5%E3%82%92%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B)
[公開鍵のコピー](https://qiita.com/tmiame/items/45af62872cf43c3b0842)
Home

[Python](https://qiita.com/tominstead000/private/997cbc04cf5ef5cd6e55)

#### その他

**SPA のパフォーマンス測定**
あるボタンを押下してから、次に押す要素が特定の状態(押下可能など)になるまでの時間を測ればよいかも♪
[Seleniumで待機処理するお話](https://qiita.com/uguisuheiankyo/items/cec03891a86dfda12c9a)

「SPA window.performance.timing」で検索↓
[SPA(Single Page Web Application)のパフォーマンスを評価する](https://www.infoq.com/jp/news/2015/12/performance-web-applications/)
[Measuring and Optimizing Performance of Single-Page Applications (SPA) Using RUM](https://engineering.linkedin.com/blog/2017/02/measuring-and-optimizing-performance-of-single-page-applications)

```shell
# ファイル内の文字列を検索（ディレクトリ内を再起的に検索）
$ grep -Iirn hogehoge .
```

```javascript
driver.execute_script('for (var len = 0; len < 2; ) { len = document.getElementsByClassName(\'checkin__radio\').length; console.log(len);}')
driver.execute_script('document.getElementsByClassName(\'checkin__radio\')[1].click();')
```
【JavaScript初心者】getElementsByClassNameを再帰を使って実装してみた

#はじめに
再帰(recursion)は初学者がつまづきやすいポイントとよく言われます。
Javascript初学者がrecursionの実装練習として、DOM操作の基本メソッドである`getElementsByClassName()`を実装してみました。
未対応edge caseも多々あると思いますがご了承ください。


#getElementsByClassNameとは？
DOM操作の基本メソッドです。
document内の任意のClass名の要素を<b>配列として</b>抽出します。
詳しくは[公式ドキュメント](https://developer.mozilla.org/ja/docs/Web/API/Document/getElementsByClassName)をご覧ください。

#実装してみた
本来ならば、`getElementsByClassName`はノードオブジェクトのメソッドであるため、任意のノードオブジェクト`nodeObj`のメソッドとして下記のような使い方をします。

```javascript

const elements = nodeObj.getElementsByClassName(className);
```

今回は簡単のため、下記２つを引数にとる関数として実装してみました。

* `className`
    * 検索するクラス名
* `nodeObj`
    * 検索を実施するノード。指定したクラス名をこのノードおよびこのノードの子ノードのなかから検索する


```javascript:getElementsByClassName

const getElementsByClassName = (className, nodeObj) => {
  const result = [];

  // 任意のnodeの中からクラス名がclassNameに一致する要素をresultにpushする関数を定義します
  const searchInsideNode = (node) =>{

    // nodeのクラス名にclassNameが含まれており、かつnodeがクラスを含んでいない場合を除くとき
    if(node.classList.contains(className) && node.classList !== undefined){
      result.push(node);
    };

    // nodeが子要素を持つときは、各子要素に対して再帰的に同じことをします。
    if(node.childNodes.length > 0){
      for (const element of node.childNodes){
        searchInsideNode(element);
      }
    }
  }

  //任意のnodeオブジェクトnodeObjに対してsearchInsideNodeを実行し、resultを返します。
  searchInsideNode(nodeObj);
  return result;
};
```
C言語　文字列の初期値とコンパイル時の注意点

##初期値を意識しよう。
Cでは、宣言時に値を初期化しない。確保されたメモリにゴミが入っていることもある。

```c
char message[17];
```

##Cはコンパイル時に配列の文字数をチェックしない。

Cではコンパイル時に配列の文字数をチェックしないので、下記のような書き方をしてもコンパイルが通ります。
※警告を出してくれるコンパイラもあるそうです。

なので、プログラマーが要素数を意識して書く必要があります。

```c
char message[7];
// 12文字の「Hello world!」('\0'を加えれば13文字)を格納
strcpy(message, "Hello world!");
```
CORS対応としてAPI側で対応しないといけないことメモ

## 概要

CORS対応としてAPI側で対応しないといけないことのまとめ。

## 対応内容

### OPTIONSメソッド

preflight対応としてOPTIONSメソッドを実装する必要がある。

#### HTTPレスポンスヘッダ

※値は全てAPIが許容するモノのみとする

* `Access-Control-Allow-Headers: Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token`
* `Access-Control-Allow-Methods: DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT`
* `Access-Control-Max-Age: 600` ※任意、例だと10分間
* `Access-Control-Allow-Origin: *` ※クライアント側のFQDN

### GET等各種メソッド

#### HTTPレスポンスヘッダ

※値は全てAPIが許容するモノのみとする

* `Access-Control-Allow-Origin: *` ※クライアント側のFQDN
* `Access-Control-Expose-Headers: *` ※クライアント側がヘッダとして取得可能なものを指定する
* `Access-Control-Allow-Credentials: true` ※クッキーのやり取りが必要な場合

`Access-Control-Allow-Credentials: true`の場合、`Access-Control-Allow-Origin`はワイルドカードではなく`Origin`を指定しなければならないので注意。※[MDNのCORS説明](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS) 参照

#### 実装

* Originが想定と異なる場合、処理を継続しないようにする  
  ※内部的には実際の処理が走ってしまっているとPOSTなどで悪戯可能になるため

## 注意点

シンプルなリクエスト*1 の場合、preflightは行われない為、preflight無しでも成立できるように必要あり。

*1 JavaScript無しで、ブラウザからの操作で可能なリクエストと等価なAPIコール、
※ 例：ただのGETリクエストや、フォーム送信（Content-Typeがapplication/x-www-form-urlencodedなPOST）等）
※ [MDNのCORS説明](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS) の `シンプルな cross-site リクエスト` 参照


## 参考

* [Access-Control-Expose-Headersが未指定時にAxiosが取得可能なヘッダ](https://stackoverflow.com/questions/37897523/axios-get-access-to-response-header-fields/37931084#37931084)
* [MDNのCORS説明](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)
[squidでhttpsプロキシ] dh key too small で発生したエラーの解消

# はじめに
sslインターセプトするhttpsプロキシを運用していて、不具合があった点が解消できましたので、記録します。
利用する環境は、前回構築した以下のものです。
**[squidでActiveDirectory連携とSSLインターセプトするProxyをdockerで手軽につくる](https://qiita.com/bashaway/items/6adc75265973de9b5fcc)**

# なにが起こったのか
以下のサイトに接続しようとすると、エラーが発生。
https://blog.goo.ne.jp/

[![Screenshot from Gyazo](https://gyazo.com/db99bf90582cd12d9fb757fc39958623/raw)](https://gyazo.com/db99bf90582cd12d9fb757fc39958623)

エラーの内容は
(71) Protocol error (TLS code: SQUID_ERR_SSL_HANDSHAKE)
Handshake with SSL server failed: error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small
というものだった。


# 原因調査

`tls_process_ske_dhe:dh key too small` というエラー。
サーバ証明書がsquidが要求するDH鍵長よりも短いため、はじかれているようだ。

CentOS8では `crypto-policies` という仕組みが用意されており、システム全体で暗号化ポリシーを一元的に管理しているようだ。
そのポリシーはプリセットで管理されており、 LEGACY / DEFAULT / FIPS / FUTURE の順で厳しくなっていく。

現在の設定は `update-crypto-policies --show` というコマンドで確認できる。

```
# update-crypto-policies --show
DEFAULT
```

参考にした **[RHEL8のサイト](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/security_hardening/using-the-system-wide-cryptographic-policies_security-hardening)** では、DEFAULTのDH鍵長は最低2048bitとなっている。
これを LEGACY にすれば、DH鍵長が短くても許容できるだろう。

が、システム全体でレベルを下げる、というのはちょっと引っかかる。


# 解決方法

`squid.conf` の tls_outgoing_optionsディレクティブで暗号化セットの指定があったので、これで試してみる。

```:squid.conf
tls_outgoing_options cipher=DEFAULT:@SECLEVEL=1
```

[![Screenshot from Gyazo](https://gyazo.com/9750c590edf8080f93a626f59d69800d/raw)](https://gyazo.com/9750c590edf8080f93a626f59d69800d)


これでOK


# 出典
参考にさせていただきました。
http://www.squid-cache.org/Doc/config/tls_outgoing_options/
https://yoku0825.blogspot.com/2019/12/centos-80url-error141a318assl.html
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/security_hardening/using-the-system-wide-cryptographic-policies_security-hardening
https://stackoverflow.com/questions/53058362/openssl-v1-1-1-ssl-choose-client-version-unsupported-protocol
【R tips】特定の列（変数）について条件を満たす行（観測）を更新する

#1. 目的
 - 特定の列（変数）について条件を満たす行（観測）の更新

#2. コード
##2.1 データフレームdfを生成
 - 行（観測）×列（変数）=4×2のdf

```R
v1 <- c("A", "B", "C", "D")
v2 <- c(0, 0, 1, 1)
df <- data.frame(v1, v2)
df
```
 - 出力：

```
  v1 v2
1  A  0
2  B  0
3  C  1
4  D  1
```
##2-2.dfの更新
 - 更新内容：v2 > 0の行について，v2に-1を加える
 - 方針：
    - 更新した行を抜き出し保存（df_updateとする）
    - 更新しない行を保存（df, df_updateのうちdfにしかない行，dplyr::anti_join()を使う）
    - 更新しない行に更新した行をくっつける（dplyr::bind_rows()を使う）

```R
df_update <- df %>% 
  dplyr::filter(v2>0) %>% 
  dplyr::mutate(v2=v2-1)
df <- df %>% 
  dplyr::anti_join(df_update, by="v1") %>% 
  dplyr::bind_rows(df_update)
df
```
 - 出力：

```
  v1 v2
1  A  0
2  B  0
3  C  0
4  D  0
```

##2.3 応用例
 - 行（観測）×列（変数）=4×3のdfとする．

```
v1 <- c("A", "B", "C", "D")
v2 <- c(0, 0, 1, 5)
v3 <- rep(0,4)
df <- data.frame(v1, v2, v3)
df
```
- 出力：

```
  v1 v2 v3
1  A  0  0
2  B  0  0
3  C  1  0
4  D  5  0
```
 - 更新内容：
    - v2 > 0の行について，v2に-0.1を加える
    - v2の合計値が0を超えている間は，繰り返しv2 > 0の行についてv2に-0.1を加え続ける
    - -0.1を加えた回数をv3に格納
    - （10^-2のオーダーは誤差として丸める）

```R
v2_sum <- sum(unlist(df$v2))
library(dplyr)
while (v2_sum>0) {
  df_update <- df %>% 
    dplyr::filter(v2>0) %>% 
    dplyr::mutate(v2=round(v2-0.1, 2), v3=v3+1)
  df <- df %>% 
    dplyr::anti_join(df_update, by="v1") %>% 
    dplyr::bind_rows(df_update)
  v2_sum <- sum(unlist(df$v2))
}
df
```
- 出力：

```
  v1 v2 v3
1  A  0  0
2  B  0  0
3  C  0 10
4  D  0 50
```
#3. コメント
 - 使いどころ：特定の変数について条件を満たす観測に「複雑な処理」を施し，条件を満たすまで繰り返した結果を格納するときとか
 - いちいちバインドするので遅い

#4. 参考
 - [left_join two data frames and overwrite](https://stackoverflow.com/questions/35637135/left-join-two-data-frames-and-overwrite)
 - [dplyrを使いこなす！JOIN編](https://qiita.com/matsuou1/items/b1bd9778610e3a586e71#anti_join)
Twilio上に溜まった録音データを一括削除

:::note alert
2023年5月1日を持ちまして、株式会社KDDIウェブコミュニケーションズのTwilioリセール事業が終了したため、本記事に記載されている内容は正確ではないことを予めご了承ください。
:::

# はじめに

みなさん、こんにちは。
KDDIウェブコミュニケーションズのTwilio事業部エバンジェリストの高橋です。

今回は、Twilio上に保存されている録音データをプログラムを使って一括削除する方法をご紹介します。なお、削除にあたっては、日付での範囲指定ができるようにしてあります。

## 通話録音ってどんなもの？

Twilioには、通話録音の機能があります。録音データは、mp3もしくはWAV形式でTwilio上に保存されます。
この通話録音は通常の通話料に加えて、以下の追加料金がかかります。

- 録音料金：0.38円/分  
- ストレージ使用料：10,000分まで無料、10,001分からは0.1円/分

録音料金はともかく、ストレージの使用料については、毎月の**平均**保存時間（分）に対して課金されるので、不要な録音データに関しては定期的に削除していくと無駄なコストを押さえられます。


# ハンズオン

以下のGitHubにプログラムを用意しました。
https://github.com/mobilebiz/twilio-remove-recordings

## 使用するライブラリなど

- node 10.8.0 以上
- dotenv 8.2.0
- moment 2.24.0
- twilio 3.39.5

## インストール

```sh
git clone https://github.com/mobilebiz/twilio-remove-recordings.git
cd twilio-remove-recordings
npm install
cp .env.sample .env
```

ここまでできたら、`.env`をエディタで開き、TwilioのAccountSidとAuthTokenを書き込みます。
AccountSidとAuthTokenは [こちら](https://jp.twilio.com/console) で調べられます。
次に、`.env`のSTART_DATEとEND_DATEに削除したい日付を範囲指定します。日付は2015-01-01のように指定してください。
<font color='red'><注意>
日付を指定し間違えると、予期しないデータを削除することになりますので注意してください。</font>

## テスト

`.env`ファイルを編集したら、まずはパラメータをテストしてください。

```sh
npm test
```

## 実行

エラーがなければ実行します。

```sh
npm start
```

## 解説

本プログラムを以下のようになっています。

```javascript
/**
 * Remove recordings with date range.
 *  
 */
'use strict';

require('dotenv').config();
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = require('twilio')(accountSid, authToken);
const moment = require('moment');

const START_DATE = moment(process.env.START_DATE);      // Range start
const END_DATE = moment(process.env.END_DATE);          // Range end

const delLoop = (targetDate => {
    let _targetDate = targetDate || START_DATE;

    // Extract data from one day.
    client.recordings.list({
        dateCreated: _targetDate.toDate()
    })
    .then(recordings => {
        // Remove the retrieved list.
        recordings.forEach(async r => {
            await client.recordings(r.sid).remove();
            console.log(`${r.sid} ${r.dateCreated} deleted.`);
        });

        // If the end date has not been reached, call it recursively.
        if (_targetDate.isBefore(END_DATE)) {
            _targetDate = _targetDate.add(1, 'days');
            delLoop(_targetDate);
        }
    })
    .catch(err => {
        console.log(err);
    })
});

delLoop();
```

START_DATEを起点に、一日づつ録音データをリストアップし、中身を1件ずつ削除しています。`async/await`で非同期対応をしていますが、極稀にTwilio側からAPIコールのエラーが戻ることがあります。
そのようなときには、同じ日付範囲で再度プログラムを実行することで取りこぼしたデータも確実に削除することができます。
# まとめ

一度削除してしまった録音データは復活できません。
日付範囲指定はくれぐれも間違えないようにしましょう。
**また、本プログラムを利用したことによる責任は、当方では負いかねますので予めご了承ください。**

---
### Twilio（トゥイリオ）とは

https://cloudapi.kddi-web.com
Twilioは音声通話、メッセージング（SMS/チャット）、ビデオなどの 様々なコミュニケーション手段をアプリケーションやビジネスへ容易に組み込むことのできるクラウドAPIサービスです。初期費用不要な従量課金制で、各種開発言語に対応しているため、多くのハッカソンイベントやスタートアップなどにも、ご利用いただいております。
【JavaScript初心者】lodashの_.eachを実装してみた

#はじめに
Javascript初学者がlodashのeach関数を作ってみました。
未対応edge caseも多々あると思いますがご了承ください。

#lodashとは？
JavaScriptの便利な関数を提供しているライブラリです。
詳しくは公式ドキュメントをご覧ください。

[公式ドキュメント](https://lodash.com/)


#_.each
配列の組み込みメソッドforEachをオブジェクトに拡張したものです。
以下の２つを引数にとります。

- <b>collection</b>:
対象となる配列またはオブジェクトです。
- <b>iteratee</b>：
collectionの各要素に実行するcallback関数です。
配列の場合、要素(value)・インデックス(index)・配列自身(collection)を引数にとります。
オブジェクトの場合、キー(key)・値(value)・オブジェクト自身(collection)を引数にとります。

```javascript:_each

_.each = (collection, iteratee) => { 
//collectionが配列の場合
    if (Array.isArray(collection)){ 
      for (let index = 0; index < collection.length; index++){
        let value = collection[index];
        iteratee(value,index,collection);
      };
// collectionがオブジェクトの場合
    }else{ 
      for (const key in collection){
        let value = collection[key];
        iteratee(value,key,collection);
      }
    }
  };
```
社会人でも勉強を継続できるコミット会の魅力

#近況報告

エンジニア転職成功しました。YouTubeでエンジニア転職したい方向けに情報発信しています。

https://www.youtube.com/channel/UCcXQG8lu_EdyP2Cbhtz1bcA


- 勉強したいけど目標ないなぁ・・・

学生までは勉強を続けていたのに、社会人になってめっきり勉強しなくなった、なんて事態を避けるために
我々[「技術ブログ東京」](https://tech.cloud-blazer.com/)のメンバーは隔週で
**「コミット会」という成果発表する会**を開いています。

[<img width = 400 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244639/40573a03-fe84-ab64-ea43-ce365825af7d.jpeg">](https://tech.cloud-blazer.com/)


今回は継続的な勉強を促進する「コミット会」の運営方法と、その魅力について語っていきます。

# 運営方法

1. 技術好きなメンバーを集める
2. Slackのワークスペースを作る
3. commitチャンネルを作り、次回までの目標を書く
3. 開催日を決める
4. コワーキングスペース等に集い、各メンバーが成果発表を行う
5. 成果発表は、「発表」と「質問タイム」の2つに分ける
5. 終了後、開催日と次回までの目標を決めて共有する


# コミット会の魅力

## 自己効力感が高まる

コミット会では

- 前回定めた目標をどのように達成したか
- 目標達成までに勉強した内容

この2点を皆の前で発表します。

こうした発表を行うことで、「定めた目標をクリアした」という達成感を重ねていける為「自己効力感」が高まります。

自己効力感とは、自分の存在価値を肯定できるという意味で使われる「自己肯定感」とは違い、
**「ある結果を生み出すために必要な行動をうまく行えるという確信」**のことを指します。

<img width = 800 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244639/9b91bbfa-2405-9827-6dc3-36a9c7387b6e.png">

目標を達成すれば、目標に必要な行動量がわかりますし、必要な行動量がわかれば
「目標達成に必要な行動をこれぐらいはできる」という効力予期を持つことができます。

つまり、目標達成の過程と勉強した内容を共有し、それを積み上げていくことが、自己効力感の向上に繋がります。

## 見識を広げる

<img width = 400 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244639/aa6df446-c8f6-e6c5-3250-c049952ccefd.jpeg">


コミット会の成果発表には「質問タイム」が設けられます。

この質問タイムでは「わからないと思ったことは何でも聞いていい」という方針を取っています。

メンバーが学んでいる分野はインフラ、サーバ、フロント、クラウド、それぞれ異なる為、
自分の専門外の分野では当然わからないことが出てきます。

そういった「わからないことを、わからないままで放置するのは勿体ない」ので、
何でも気軽に聞ける環境を整えています。


**この「何でも聞ける」という環境が、見識を広げることに繋がります。**

皆さんそれぞれ得意分野があると思いますが、**一つの分野のみに突き進んでいくと見識が狭くなりがちです。**

そこで、オーディエンスが「抽象的・個別具体的」な疑問点を挙げ、それにプレゼンターが答えることで、幅広い疑問を解消すると同時に見識を広げます。

## 継続的な勉強を促進する

<img width = 400 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244639/fa8b6142-6446-8f82-cffd-0fbdb96ae7ee.png">


タイトルにも付けていますが、目標を定めることで継続的な勉強を促進します。

これがコミット会最大の魅力です。社会人になると仕事も忙しく、プライベートを削って勉強を継続するのは中々ハードルが高いです。

コミット会では皆の前で目標を宣言しますので、**発言に責任感が生まれ目標達成の為に尽力します。**

勿論、仕事ではないので必ず達成しなければならない、という訳ではありません。
しかし、皆の前で宣言した目標を達成出来ないのはかっこわるいですし、「達成できなかった」という負の感情を持ちたくない為に、なんとか目標に近づこうと努力はするでしょう。

結果、コミット会に参加し続けることで、継続的な勉強を促進します。

#皆もやろう、コミット会

コミット会は特定のテーマを決めない為、エンジニアであれば誰でもメンバーに入れることができます。

**メンバーを集めるハードルは低く、事前準備もないので同僚、知人を誘って気軽に始められます。**

- 自己効力感を高めたい
- 見識を広げたい
- 勉強を継続させたい

上記いずれかに当てはまる方、是非ともコミット会をはじめてみましょう。
autopep8がsys.path.append()行をImportの下に持ってきてしまう問題

#Abstract
`autopep8`でフォーマットしながらPythonコードを書いているとき，オートフォーマットされたくない行の最後に`#nopep`を付ける

# Background
`VSCode`で`autopep8`でフォーマットしながらPythonコードを書いているとき，
`./neko/modules/nekofuguri.py`をインポートしたいがため

```python
import sys
sys.path.append('./neko/modules/')
import nekofuguri 
```
て書いてたのが，

```python
import sys
import nekofuguri
sys.path.append('./neko/modules/')
```

ってセーブするときとかに勝手にされてしまっていた．

# Solution
いかで色々挙げられているが
https://stackoverflow.com/questions/54030320/vscode-autopep8-allow-statements-before-imports

- VSCodeの`settings.json`にて`"python.formatting.autopep8Args": ["--ignore", "E402"]`と設定する
    - 402エラーがimportがファイルのトップレベルに来てないっていうエラーらしいなのでこれを無視するように設定するということらしい
    - 多分ワークスペース毎のsetttings.jsonの方が良い？
- オートフォーマットされたくない行の最後に`#noqa`または`#nopep`を付ける
すなわち

```python
import nekofuguri #nopep
```
みたいな．

いずれかで対応すればよい
なんとなく，sys.path.append行を別のファイルに書いてそれをimportしてもいい気もするが，野暮ったい気がするので試してもない．
slimでkaminari導入

ERBで導入経験はありましたが、slimではなかったので、試しました。

まずはgem追加

```ruby:Gemfile
gem 'kaminari'
```
```ruby:command
bundle
```
コントローラ側とviewを修正していきます。

```ruby:hoges_controller
def index
  @hoges = Hoge.page(params[:page])
end
```

```ruby:hoges/index.html.slim
.mb-3
  = paginate @hoges
```

下記のように表示できれば成功です！

<img width="181" alt="スクリーンショット 2020-03-03 7.54.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381043/541abaee-1f45-3d69-4df1-f016005529a4.png">

デフォルト設定が25レコードなので、それ以上データが無いと表示されませんでした。追加してから動作確認した方が良さそうです。

ちなみに、下記のように.per(8)を追加すれば表示したいレコードを
指定できるので、わざわざ25も登録しなくても確認できます。

```ruby:hoges_controller
def index
  @hoges = Hoge.page(params[:page]).per(8)
end
```

参考

https://github.com/kaminari/kaminari
【競技プログラミング】STL::pair ことはじめ

## ０．はじめに
[AtCoder Programming Guide for beginners (APG4b)]((https://atcoder.jp/contests/apg4b))でSTL::pairを学んだ際、
記述に迷い、エラーを再三出してしまったため、自分用の知識のまとめ、備忘録として記事に残します。
お役に立てれば幸いです。

なお、`STL::pair`の詳細については[APG4bの該当箇所](https://atcoder.jp/contests/apg4b/tasks/APG4b_z)で学習するのがよいと思います。

## １．STL::pairとは
`pair`とは、2個の要素をひとまとめにするクラスです。
例えば科目と点数、氏名と所属などを１つの値として管理できます。
なお、N個の要素をひとまとめにするクラスとして、`tuple`があります。


## ２．ポイント
* 配列と共に使われることが多い。つまり`vector`の型として利用するのが基本です。
* `pair`をソートすると1番目の値で比較され、それが等しい場合は2番目の値で比較されます。
* `pair`, `make_pair`, `tie`の型の並びは統一する必要があります。

## ３．例題
では実際に例題を通してポイントを確認していきます。
似通った問題を並べてみますので、その違いに注目しましょう。

##### 例題A

>全ｎ科目の試験の結果が科目名a, 点数bで与えられる。
点数の低い科目から順番に出力しなさい。

```C++:SampleA
#include <bits/stdc++.h>
using namespace std;

int main() {
	int  n;
  	cin >> n;
  	vector<pair<int, string>> p(n); //点数を比較したいのでintを前に。
  	for(int i = 0; i < n; i++) {
         string a;
      	 cin >> a;
         int b;
         cin >> b;
         p.at(i) = make_pair(b, a); //pairと合わせてint, stringの順に記述します。
    }
  
  	sort(p.begin(), p.end());
  
  	for(int i = 0; i < n; i++){
      string a;
      int b;
      tie(b, a) = p.at(i); //pair, make_pairと合わせてint, stringの順に記述します。
      cout << a << ": " << b << endl; //出力は任意の順番で問題ありません。
    }
}
```

**入力例A**
3
Math 100
English 80
Science 85

**出力例A**
English: 80
Science: 85
Math: 100

##### 例題B

>全ｎ科目の試験の結果が科目名a, 点数bで与えられる。
科目名を辞書順で並び替え、点数と合わせて出力しなさい。

```C++:SampleB
#include <bits/stdc++.h>
using namespace std;

int main() {
	int  n;
  	cin >> n;
  	vector<pair<string, int>> p(n); //辞書順にしたいのでstringを前に。
  	for(int i = 0; i < n; i++) {
         string a;
      	 cin >> a;
         int b;
         cin >> b;
         p.at(i) = make_pair(a, b); //string, intの順となり例題Aとは反転します。
    }
  
  	sort(p.begin(), p.end());
  
  	for(int i = 0; i < n; i++){
      string a;
      int b;
      tie(a, b) = p.at(i); //上のmake_pairと合わせ、string, intの順で記述します。
      cout << a << ": " << b << endl;
    }
}
```
**入力例B**
3
Math 100
English 80
Science 85

**出力例B**
English: 80
Math: 100
Science: 85

## ４．まとめ
pairクラスは1番目の値がソート対象になります。
その都合、値の順番を入れ替えることが多いのですが、
pair, make_pair, tieの組み合わせに齟齬が発生するとエラーが発生したり、誤った値が出力されたりします。
厳格な記述を求めてくる印象ですが、記述量が少なく、要素が少ないケースで適している場合が多そうです。

最後までお付き合い頂き、ありがとうございました。



## 参考文献

[AtCoder Programming Guide for beginners (APG4b)](https://atcoder.jp/contests/apg4b)
[cpprefjp - C++日本語リファレンス](https://cpprefjp.github.io/)
[@e869120](https://qiita.com/e869120): [厳選！C++ アルゴリズム実装に使える 25 の STL 機能【前編】](https://qiita.com/e869120/items/518297c6816adb67f9a5)
[@drken](https://qiita.com/drken):[「記事を書くこと」のススメ 〜 最高の達成感を求めて 〜](https://qiita.com/drken/items/afad07b70695c414fff7)
最近pycファイル見ないなーと思っていたら、python3でpycacheに隔離されていた話

pythonを触ってる中で
「あれ…？pycファイル最近見ないな？」

と気づきました。

そしたら、仕様がしっかりと変わっていた(結構古いですが)ので書いてみました

## pycファイルとは
公式にはこんな説明が書いています。

> CPython compiles its source code into "byte code", and for performance reasons, it caches this byte code on the file system whenever the source file has changes. This makes loading of Python modules much faster because the compilation phase can be bypassed. When your source file is foo.py, CPython caches the byte code in a foo.pyc file right next to the source.

https://www.python.org/dev/peps/pep-3147/

3行でまとめると

- importするソースコードを随時コンパイルしてコンピュータが読みやすいバイナリファイルにするよ！
- バイナリファイルはロードがとっても早くなるよ！
- バイナリファイルは該当ファイルのすぐそばにpycファイルとして作られるよ！

と書いています。(すごい大雑把です)

ですので読み込みを高速化してくれる役割を担ってくれているわけです。

### pycファイルを作ってみよう！

```
　├─ a.py
　├─ b.py
　└─ c.py
```

```a.py
import b
import c

b.hello()
c.goodmorning()
```

```b.py
def hello():
    print("hello")
```

```c.py
def goodmorning():
    print("goodmorning")
```

#### 結果
```
hello
goodmorning

$ ls
a.py		b.py		b.pyc		c.py		c.pyc

```

pycファイルがこんにちはしています。


## pycの行方の真相
しかしいつからか、このpycファイルがすぐそばに作られなくなりました。

てっきり
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367399/594dd37a-3b3f-9969-e89a-52eedefb2cc9.png)

かと思いましたが、そんな事はなく。

python3.2から格納場所が変更になったそうです。

> これらの新しいファイルがソースディレクトリを散らかすのを防ぐために、 pyc ファイルはパッケージディレクトリの下の "__pycache__" ディレクトリに収集するようになりました。

https://docs.python.org/ja/3/whatsnew/3.2.html#pep-3147-pyc-repository-directories

ふむふむ、確かにソースコードを探すのに二重であって見づらかった。

なので管理方法を変えたわけですね。

### 置き場が新しいｐｙｃファイルを確認する

今度は同じファイル構成ですがpython3.2で確認(前述のは2.7で試していました。)

```
　├─ a.py
　├─ b.py
　└─ c.py
```

```a.py
import b
import c

b.hello()
c.goodmorning()
```

```b.py
def hello():
    print("hello")
```

```c.py
def goodmorning():
    print("goodmorning")
```

#### 結果

```
$ ls
__pycache__	a.py		b.py		c.py
$ ls __pycache__/
b.cpython-37.pyc	c.cpython-37.pyc
```

このように__pycache__/配下に.pycが作成されているのが確認できました！
【初心者向け】LambdaとAlexaスキルの連携設定

#LambdaとAlexaスキルの連携設定
前の記事：[LambdaでAlexaカスタムスキルと連携する関数を作成](https://qiita.com/kurisaka/items/00451cb7d5551a79b68d)
###スキルIDの表示
スキルの一覧に戻り該当スキルの「スキルIDの表示」を押下する
![4-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/a0fca7a0-06cb-0557-a79a-3d15788a645c.png)

###スキルIDのコピー
表示されたスキルIDをコピーしておく
![4-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/df876165-d394-b9a1-19f0-269fb1abd735.png)

###Lambdaトリガーの設定
Lambdaに戻り「Designer」を開き「トリガーを追加」を押下
![4-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/75644892-c5dd-4a08-8fd5-f420a68bf5fb.png)

###トリガーの追加
トリガーの設定のプルダウンより「Alexa Skills Kit」を選択
![4-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/77dc35fa-bafa-2a03-5fdc-8991852cd3b2.png)

###スキルIDの登録
トリガーの設定の「スキルID」に先ほど4-2でコピーしたスキルIDを貼り付け「追加」を押下
![4-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/59031f27-eb12-8cfb-3666-a9e0850850f2.png)

###トリガーがの設定完了
トリガーが正常に登録できれば以下画面が表示されます
右上のコピーアイコンをクリックしてARNをコピーしてください
![4-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/d61dc2db-ba60-5792-bf62-1ea258036273.png)

###ARNのコピー
成功メッセージが表示されるとクリップボードにARNがコピーされます
![4-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/c5dffff5-3eae-e878-d940-f03dd3656d7d.png)

###エンドポイントの設定
alexaに戻り左側のメニューより「エンドポイント」を選択
「AWS LambdaのARN」を選択
![4-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/d2c9dee4-1b94-1501-b1d8-f2ad6f5434ea.png)

###エンドポイントの追加
- 「デフォルトの地域」に先ほどコピーしたARNを貼り付け  
- 上部にある「エンドポイントを保存」を押下し、Lambdaとalexaの連携を完了させます
![4-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/b0d33748-23e9-576c-4de4-4bf423eac9f8.png)

###マニュフェストの保存成功メッセージが表示されます
![4-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/a4ad16e5-9cdd-0141-c5b0-53d14b948c7c.png)

###次の記事
* [Cognitoで認証情報を保存するユーザープール作成](https://qiita.com/kurisaka/items/7235d058211367aaa96f)


###関連記事
* [Alexaでカスタムスキルを作成する](https://qiita.com/kurisaka/items/24f5dfe54d718e33c1c2)
* [Alexaカスタムスキルを作成してCognitoのユーザープールとアカウントリンクする手順](https://qiita.com/kurisaka/items/8dda3fef0d1eb2662f05)
* [AlexaとCognitoをアカウントリンクして認証情報をLambda関数で利用できるように修正](https://qiita.com/kurisaka/items/6404f49b4d5134ee8e74)
【初心者向け】Cognitoで認証情報を保存するユーザープール作成

#Cognitoでユーザープールを作成
前の記事：[LambdaとAlexaスキルの連携設定](https://qiita.com/kurisaka/items/e8dcadb94053a7ddc266)
##AWS Cognitoでユーザープールの作成手順

###AWSのサービス一覧から「Cognito」を選択
「Cognito」はセキュリティ、ID、およびコンプライアンスのカテゴリです
![2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/8687f807-b895-f89e-fde8-ec24204b1342.png)

###Cognitoトップ画面より「ユーザープールの管理」を押下
![2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/dc867dc6-3d94-d2a1-079d-6d34d9e3a613.png)

###ユーザープールトップ画面より「ユーザープールを作成する」を押下
![2-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/bd96c85b-d694-c4d9-f06d-f9cbe7b8bac5.png)

###ユーザープールの基本情報を入力する
- 「プール名」を入力　→今回はSamplePoolsと入力しました
- 「デフォルトを確認する」を押下
![2-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/1187ecc3-31be-832c-4cfd-58596c767019.png)

###ユーザープールの情報が表示されたら左側メニューの「属性」を押下
プールの作成はまだ押下しないでください
![2-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/0199a248-e9ca-9fe0-a7b0-d0b58d475066.png)

###属性情報を設定する
- 「Eメールアドレスおよび電話番号」を選択  
    - 「Eメールアドレスを許可」を選択  
- 必要な必須属性を選択  →今回はnameのみ設定しました
- 「次のステップ」を押下
![2-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/cc7fd612-eea5-779e-8fd0-b260373cfc63.png)

###ポリシーの設定  
今回はデフォルトの設定としますので、左側のメニューより「確認」を押下します  
![2-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/f5c3bf6b-29ee-c9ad-7b67-f81d5379b24e.png)

###「プールの作成」を押下
![2-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/c26cd92d-0dfc-03e6-984f-1caae6826069.png)

###プールが作成されたメッセージが表示される
![2-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/a15391fc-b89b-2fb2-61ae-a240b941b2cb.png)

###アプリクライントの設定
左側のメニューより「アプリクライアント」を押下
![2-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/fda71b93-9734-1e16-a952-dd0bfde3567f.png)

###「アプリクライアントの追加」を押下
![2-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/78bac230-6fd2-84dc-b5ed-264b3c259d9d.png)

###アプリクライアントの詳細設定
- 「アプリクライアント名」を入力　→今回は「SampleApp」としました
- 「クライアントシークレットを生成」のチェックは入れておく  
- 「アプリクライアントの作成」を押下
![2-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/5ab44751-2fc5-0740-cdcf-69b761ba837f.png)

###アプリクライントのIDが発行される
「詳細を表示」を押下
![2-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/65183d70-99c9-9ccf-1ea5-236aa8bbb7d9.png)

###アプリクライアントの詳細情報の表示
後ほど利用するため、以下情報をメモ帳などにコピーしておく
- アプリクライアントID
- アプリクライアントのシークレット
![2-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/dffc754d-c70c-3605-67d2-9da9e1c42ee1.png)

###次の記事
* [AlexaカスタムスキルとCognitoをアカウントリンクで連携させる](https://qiita.com/kurisaka/items/6404f49b4d5134ee8e74)

###関連記事
* [Alexaカスタムスキルを作成してCognitoのユーザープールとアカウントリンクする手順](https://qiita.com/kurisaka/items/8dda3fef0d1eb2662f05)
* [Alexaでカスタムスキルを作成する](https://qiita.com/kurisaka/items/24f5dfe54d718e33c1c2)
* [AlexaとCognitoをアカウントリンクして認証情報をLambda関数で利用できるように修正](https://qiita.com/kurisaka/items/6404f49b4d5134ee8e74)
conda を fish で使えるようにする方法

アプリケーション・環境・パッケージのデプロイを管理するツール Conda を fish で使えるようにインストールする方法である。macOS で `conda` （Miniconda） をパス `$HOME/miniconda` に（__fish__ で利用できるように）インストールする __bash__ スクリプトを記す。Anaconda を使いたい場合は Miniconda を Anaconda に置き換えること。`$HOME/tmp` に一時ファイルを生成する。

```bash
#!/usr/bin/env bash
mkdir -p $HOME/tmp
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O ~/tmp/conda_installer.bash
bash $HOME/tmp/conda_installer.bash -b -p $HOME/miniconda
source $HOME/miniconda/bin/activate
conda init fish
# 一時ファイルを消したければ
# rm $HOME/tmp/conda_installer.bash
```

以上である。`wget` はデフォルトの macOS にはないので HomeBrew で `brew install wget` などとして入れておくこと。[アンインストール](https://conda.io/projects/conda/en/latest/user-guide/install/macos.html#uninstalling-anaconda-or-miniconda)するときは、

* ディレクトリ `$HOME/miniconda`
* ファイル `$HOME/.condarc`
* ディレクトリ `$HOME/.conda`
* ディレクトリ `$HOME/.continuum`
* fish の設定ファイル `~/.config/fish/config.fish` に書き加えられた `conda initialize` で囲まれたブロック

を消すこと。
ツイートで身バレするか　〜COTOHA×Nuxt×Firebase×twitterAPIでtwitterユーザ属性判定できるサイトを作ってみた〜

# はじめに
こんにちは。Qiita初投稿です。
もともとNuxt×Firebaseで何かしら作ってみたいと考えていたところに、Qiita x COTOHA APIプレゼント企画の記事を見つけたので、チャレンジすることにしました。

[Qiita x COTOHA APIプレゼント企画](https://zine.qiita.com/event/collaboration-cotoha-api/)

# 作ったもの
NuxtとFirebaseのtwitter認証を使い、自分のツイート30個くらい(RT除く)をCOTOHA APIのユーザ属性推定(β)に投げて結果を表示するサイトです。

ツイートからどこまで身バレするのか楽しみ。

判定結果はFirestoreに保存して、再ログイン時には前回の判定結果を参照できるようにしました。

他人には見られたくないと思い、ログインした本人にだけ見れるようにしています。

[作ったサイトはこちら](https://hiro-it.work/)

<img width="375" alt="IMG_FA7E8CD50D63-1.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294625/8012bf9b-0e9d-ba93-c841-65bded2da668.jpeg">



# 利用したもの
- Nuxt.js v2.11.0
- [Vuetify](https://vuetifyjs.com/ja/)
- Google Firebase v7.9.0
- Google Firestore
- Google Cloud Functions
- Twitter API
- [COTOHA API](https://api.ce-cotoha.com/contents/index.html)

# COTOHAのユーザ属性推定(β)の結果
|属性  |判定結果  |正誤  |
|---|---|---|
|Gender|男性  |○  |
|hobby|ANIMAL  |×  |
|hobby|COLLECTION  |×  |
|hobby|FISHING  |×  |
|hobby|GOURMET  |×  |
|hobby|SPORT  |○  |
|hobby|STUDY  |○  |
|moving|BUS  |△  |
|moving|CAR  |○  |
|moving|CYCLING  |×  |
|moving|RAILWAY  |○  |
|moving|WALKING  |○  |
|occupation|会社員  |○  |

正誤はあるけども、高々３０個くらいのツイートからこれだけ推定してくるとは。

他にも年齢なども推定してくれる時があります。（年収もありましたが、twitterの規約に反するとのことで、表示されないように対応してます）

# 初心者がサイトを作っての所感
- Firebaseのtwitter認証機能がすぐに実装できたことに感激
- FirestoreのWeb画面とDBのリアルタイム同期に感動
- Vuetifyでそれっぽくサイト作りができることに感激
- 参考にできる良質な記事のおかげで、休日主体で実質２週間くらいでできた。感激（間に合った〜）
- 作成優先でコード品質はイマイチ。コードレビューや開発スキルの必要性に気づく
- Firebaseみたいな便利な技術が世の中にたくさんある。これからもアウトプットを大切にしたい

# 超良質記事（参考サイト）
- [Nuxt.js + Vuex + Firebase(Authentication, Cloud Firestore)でTwitterユーザー向けの伝言板を作る](https://qiita.com/ysd_marrrr/items/cf7871e7803d7b4919f1)  
Nuxt×Firebase(Authenticationなど)を使ったサイト作り全般の記載があり、大変お世話になりました。Firebaseのリアルタイム同期の機能にも出会えました。
- [Twitter民の年収が低いことを明らかにしてはいけなかった 【小ネタ】](https://qiita.com/Harusugi/items/22accacd3c8dba66df03)  
twitterの規約の問題等、大変勉強になった記事。今回の取組はこちらの記事の二番煎じでした。。。
【初心者向け】Alexaでカスタムスキルを作成する

#alexa developer consoleでスキルを作成
「alexa developer console」へログインする
https://developer.amazon.com/alexa/console/ask

##カスタムスキルの作成手順

###「スキルの作成」を押下
![3-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/4388dfe2-2518-44b5-d588-2cc4248b05b7.png)

###スキルの基本情報を入力
- 「スキル名」を入力  →今回はサンプルスキルとしました
- 「カスタム」を選択  
- 「ユーザー定義のプロビジョニング」を選択  
- 右上の「スキルを作成」を押下
![3-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/51a7b38f-41ee-03cf-342d-5f9b02ea4b7f.png)

###スキル作成画面
「呼び出し名」を押下
![3-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/b383da9e-0d91-599f-3acf-e572210b1e14.png)

###スキルの基本設定を入力する
- 「呼び出し名」を入力  →今回はサンプルスキルにしました
- 左側メニューのインテントにある「追加」を押下
![3-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/abaa3f92-ff88-8136-6e01-a2c3689d88ea.png)

###「インテントを追加」を押下
![3-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/677614e3-4c7c-d695-3fd3-810a2e40f296.png)

###インテント設定画面
- インテント名を入力　→今回はtestにしました
- 「カスタムインテントを作成」を押下
![3-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/7e6ce696-7639-e773-b735-e04fd0691a0a.png)

###インテント追加画面
サンプル発話に「こんにちは」と入力して「＋」ボタンを押下
![3-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/13406338-8e6d-f8ed-cb33-7a198d981192.png)

###モデルを保存する
サンプル発話が追加されたら「モデルを保存」を押下する
![3-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/f6e773c7-c421-b1af-44f9-82414022f47c.png)

###モデルが保存されたらモデルをビルドする
対話モデルが保存されたら「モデルをビルド」を押下
![3-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/ae91a714-7e13-60c2-9a94-aa4ea793b51b.png)

###ビルド完了
ビルド成功メッセージが出たら基本設定は完了
![3-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163917/5ae6adcb-50ea-d396-1086-634eeed6016f.png)

###次の記事
* [LambdaでAlexaでカスタムスキルと連携する関数を作成](https://qiita.com/kurisaka/items/00451cb7d5551a79b68d)

###関連記事
* [Alexaカスタムスキルを作成してCognitoのユーザープールとアカウントリンクする手順](https://qiita.com/kurisaka/items/8dda3fef0d1eb2662f05)
* [LambdaとAlexaを連携させてカスタムスキルの完成](https://qiita.com/kurisaka/items/e8dcadb94053a7ddc266)
* [Cognitoで認証情報を保存するユーザープール作成](https://qiita.com/kurisaka/items/7235d058211367aaa96f)
* [AlexaとCognitoをアカウントリンクして認証情報をLambda関数で利用できるように修正](https://qiita.com/kurisaka/items/6404f49b4d5134ee8e74)
Misora 次世代構想

# 経緯
[国連 GGIM 防災会議](https://ggim-tokyo-2020.github.io)（延期）のために、これまで[国連ベクトルタイルツールキット](https://github.com/un-vector-tile-toolkit)を Raspberry Pi 上に実装する作業をしていました。国連ベクトルタイルツールキットを用いたウェブ上の地理空間情報共有を、数時間のシナリオベース演習という形で技術移転することを予定したからです。

# Misora の誕生
延期決定直後、数時間のシナリオベース演習を最短30分で実施できるよう、演習のエッセンスを30分程度まで圧縮できるように[三つ折りパンフレット](https://github.com/un-vector-tile-toolkit/misora-leaflet)をまとめ、[UNITAR-UNOSATとの打ち合わせ](https://twitter.com/UNOSAT/status/1232695933265174530?s=20)等に使用しました。この作業の中で「国連ベクトルタイルツールキットをセットした Raspberry Pi」に名前をつける必要を感じ、その仮称を Misora としています。

# 次世代開発
## 変更点
Misora は、令和元年度台風19号の都幾川データを組み込んでいます。この時、オルソ画像を組み込んだのでレポジトリが重くなりました。その他、さまざま改善できるところを見つけたので、次の表のとおり、これから次世代開発を実施していきたいと思っています。

| 要素     | 現世代 kawagoe | 次世代 sonogi | 工夫点 |
|---|---|---|---|
| 構造 | [unvt/v6](https://github.com/un-vector-tile-toolkit/v6) の上に構築する | 直接 alpine から構築する | 部品点数を減らし、確実・簡易に更新・改造ができるようにする |
| 起動 | 起動後、`cd kawagoe` として作業ディレクトリに移動する必要があった | 起動時点で、作業ディレクトリに移動しておくようにする | 学習曲線を少しでもなだらかにする |
| Raspberry Pi 用イメージの作り方 | 手動作業で作る | 素の Rasbian を導入済みの Raspberry Pi に一式を導入するタスクとして `rake world` を新設する | 確実・簡易に更新・加増ができるようにする |
| 同梱ジオデータ | 2019年台風第19号の都幾川データ | 環境省植生調査 ["v67"](http://gis.biodic.go.jp/webgis/sc-025.html?kind=vg67) と農林水産省農地の区画情報（筆ポリゴン）の長崎県データ | ジオデータを軽量化する |

## 共通の工夫
- あえて armv6 用の Docker コンテナイメージから構築を行うことにより、armv7 や Intel でも動くことを期待する。
- Dockerfile と作業用ファイルをあえて一つのレポジトリの中に入れ込んで開発を進める。
金融業務能力検定(CBT方式)合格記

ファイナンシャル・プランニング技能検定を実施している金融財政事情研究会が提供している
金融向けのコンプライアンス系の検定試験を受けてきました。

https://www.kinzai.or.jp/kentei/guide/field.html

いつでも簡単に受験できるので、Fintechで働いている方や個人情報を扱うシステムを開発する方は
受験を検討してみたらいかがでしょうか。

## 受けてきた試験
- AML／CFTスタンダードコース
- マイナンバー保護オフィサー
- 個人情報保護オフィサー・銀行コース

## 試験概要
- 試験時間: 100分
- 問題数: 50問
- 出題形式: 4個から正解を1個選択
- 合格基準: 70点以上

AWS・GCP等のベンダー試験みたいに、HPから自分で試験会場を選択して受験するスタイルです。

## 結果

- 1/12 AML／CFTスタンダードコース(1回目)
    - 62点 不合格
- 1/17 マイナンバー保護オフィサー
    - 76点 合格
- 2/10 個人情報保護オフィサー・銀行コース
    - 88点 合格
- 2/14 AML／CFTスタンダードコース(2回目)
    - 88点 合格

## 勉強法

ひたすら公式の問題集をやりました。
問題集は毎年新しくなるようです。私は2019年版をやりましたが、もう2020年版も出ているようです。

- [2019年度版 AML/CFTスタンダードコース試験問題集](https://www.amazon.co.jp/2019%E5%B9%B4%E5%BA%A6%E7%89%88-AML-CFT%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%80%E3%83%BC%E3%83%89%E3%82%B3%E3%83%BC%E3%82%B9%E8%A9%A6%E9%A8%93%E5%95%8F%E9%A1%8C%E9%9B%86-%E4%B8%80%E8%88%AC%E7%A4%BE%E5%9B%A3%E6%B3%95%E4%BA%BA%E9%87%91%E8%9E%8D%E8%B2%A1%E6%94%BF%E4%BA%8B%E6%83%85%E7%A0%94%E7%A9%B6%E4%BC%9A-%E6%A4%9C%E5%AE%9A%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC/dp/4322136869)
- [2020年度版 マイナンバー保護オフィサー試験問題集](https://www.amazon.co.jp/2020%E5%B9%B4%E5%BA%A6%E7%89%88-%E3%83%9E%E3%82%A4%E3%83%8A%E3%83%B3%E3%83%90%E3%83%BC%E4%BF%9D%E8%AD%B7%E3%82%AA%E3%83%95%E3%82%A3%E3%82%B5%E3%83%BC%E8%A9%A6%E9%A8%93%E5%95%8F%E9%A1%8C%E9%9B%86-%E4%B8%80%E8%88%AC%E7%A4%BE%E5%9B%A3%E6%B3%95%E4%BA%BA%E9%87%91%E8%9E%8D%E8%B2%A1%E6%94%BF%E4%BA%8B%E6%83%85%E7%A0%94%E7%A9%B6%E4%BC%9A-%E6%A4%9C%E5%AE%9A%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC/dp/432213808X)
- [2020年度版 個人情報保護オフィサー・銀行コース・生命保険コース試験問題集](https://www.amazon.co.jp/2020%E5%B9%B4%E5%BA%A6%E7%89%88-%E5%80%8B%E4%BA%BA%E6%83%85%E5%A0%B1%E4%BF%9D%E8%AD%B7%E3%82%AA%E3%83%95%E3%82%A3%E3%82%B5%E3%83%BC%E3%83%BB%E9%8A%80%E8%A1%8C%E3%82%B3%E3%83%BC%E3%82%B9%E3%83%BB%E7%94%9F%E5%91%BD%E4%BF%9D%E9%99%BA%E3%82%B3%E3%83%BC%E3%82%B9%E8%A9%A6%E9%A8%93%E5%95%8F%E9%A1%8C%E9%9B%86-%E4%B8%80%E8%88%AC%E7%A4%BE%E5%9B%A3%E6%B3%95%E4%BA%BA%E9%87%91%E8%9E%8D%E8%B2%A1%E6%94%BF%E4%BA%8B%E6%83%85%E7%A0%94%E7%A9%B6%E4%BC%9A-%E6%A4%9C%E5%AE%9A%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC/dp/4322138071)

問題集を3〜5周すれば大丈夫だと思います。
1回目AML／CFT不合格になった敗因は、問題集を1.5周くらいしかやらなかったからだと自己分析してます。

## 難易度

1回不合格になって言うものなんですが、どれも難しくはありません。
強いて順位付けするなら以下のような感じです。

　マイナンバー保護オフィサー << 個人情報保護オフィサー・銀行コース < AML／CFTスタンダードコース

## 雑感

- 他ベンダー試験(AWS/Azure/GCP)に比べ試験のWEBアプリの出来がよくストレスなく受験できました。
- 試験に合格したからといって何か認定されるわけではありません。