OmniAICreator/Qiita-1.07M huggingface dataset:
Tkinter 相互関連があるCallbackをテストする2

最近忙しく、Markdownの書き方も少し忘れていたため、思い出す意味も込めて投稿。
下記相互関係のCallbackを使った場合に、複数のオブジェクトを関係を作ると
ソースが雑多となるため、ペアとしてまとめられるようにソース修正。
https://qiita.com/Nomisugi/items/8d11e0419091ac21866d　（修正前のコード)


```Python:MultiBinEditor.py
import tkinter as tk

class HexSpinbox(tk.Spinbox):
    def __init__(self, *args, **kwargs):
        self.var = tk.StringVar()
        self.bytenum = kwargs.pop('bytenum', 1)
        self.add_callback = None
        self.handle_obj = None
        max_val = 0x1<<(self.bytenum*8)
        super().__init__(*args, **kwargs, textvariable=self.var, from_=0,to=max_val,
                         increment=1, command=self.callback )

    def set(self, val):
        s = "0x{:0%dx}" % (self.bytenum*2)
        self.var.set(s.format(int(val)))
        
    def get(self):
        hstr = super().get()
        return int(hstr, 16)

    def callback(self):
        val = super().get()
        self.set(val)
        self.add_callback(val) if self.add_callback != None else None

    def setCallback_pair(self, obj):
        self.pair_obj = obj
        self.add_callback = self.handle

    def handle(self, val):
        self.set(val)
        self.pair_obj.set(val)
        
    def setCallback(self, func):
        self.add_callback = func

class BinEditFrame(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.val = 0x00
        self.bits = []
        self.add_callback = None
        self.pair_obj = None
        for i in range(8):
            btn = tk.Button(self,text=str(i), relief='raised', command=self.callback(i))
            btn.pack(sid='right')
            self.bits.append(btn)

    def callback(self, i):
        def push():
            self.val ^= (1<<i)
            self.redraw()
            self.add_callback(self.val) if self.add_callback != None else None
        return push
    
    def redraw(self):
        #All Button Delete
        for bit in self.bits:
            bit.destroy()
        self.bits.clear()
            
        #All Button ReCreate
        for i in range(8):
            if (self.val & (1<<i) > 0):
                btn = tk.Button(self,text=str(i), relief='sunken',
                                command=self.callback(i) )
            else:
                btn = tk.Button(self,text=str(i), relief='raised',
                                command=self.callback(i) )
            btn.pack(sid='right')
            self.bits.append(btn)
        
        
    def setCallback(self, func):
        self.add_callback = func
        
    def setCallback_pair(self, obj):
        self.pair_obj = obj
        self.add_callback = self.handle

    def handle(self, val):
        self.set(val)
        self.pair_obj.set(val)

    def set(self, val):
        self.val = int(val)
        self.redraw()

if __name__ == "__main__":
    print("BinHexEditor")
    win = tk.Tk()
    hx = HexSpinbox(win)
    hx.pack(side=tk.LEFT)
    be = BinEditFrame(win)
    be.pack(side=tk.LEFT)

    hx.setCallback_pair(be)
    be.setCallback_pair(hx)
        
    win.mainloop()
```

外部にCallback関数を追加せずに、相互の数値を変更できる仕組みができました。
これを使って特殊バイナリエディタを作ってみます。
分散システムと並列分散処理の違い

ポイント: 「並列分散処理」と「分散システム」は，同一コンピュータ内で完結するか

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/56aace04-1c8c-6b1a-1234-e52092fe4abe.png)
>
> 出典: https://www.slideserve.com/Mia_John/css434-parallel-distributed-computing-1181596

| | 並列システム | 分散システム |
| --- | --- | --- |
| メモリ | しっかり結びついた共有メモリ | 分散メモリ |
| 制御 | グローバルクロック制御 | グローバルクロック制御がない |
| プロセッサ間通信 | Tbpsのオーダー | Gbpsのオーダー |
| 主眼 | パフォーマンス(用途:科学技術計算) | パフォーマンス(コストとスケーラビリティ)，信頼性/可用性，情報/リソースの共有 |
【Java】Javaの全体像

#Javaエディション（環境）

* **JavaSE（Java Platform, StandardEdition）**
    * JavaSEはJavaアプリを動作させるための基本的な実行／開発環境を提供
    * 文字列／数値、日付の操作、入出力処理など、汎用的に利用できるライブラリ
    * 基本的にこれしか使わない

* **JavaEE（Java Platform, Enterprise Edition）**
    * JavaEEは、このJavaSEの上で動作するサーバーアプリ開発のためのライブラリ
    * 主に企業向けのシステム開発を想定した機能

* **JavaME（Java Platform, Micro Edition）**
    * リソースの限られた環境への組み込み用(携帯、家電など)
    * 近年のIoTの流れの中で、JavaSEに統合

#Javaの歴史
* Java2 (version1.2)で環境に応じてエディションが整理されたのち、JDKがJ2SE（Java2 Platform, Standard Edition）と呼ばれるようになった
* Ver6では、J2SEという呼称もJavaSEに改められる
* Java8、9でラムダ式、モジュールなどのモダンな機能が追加される
* Java11でOracleJDKが有償化(OpenJDKは無償)
* OpenJDKにはLTS提供なし(Long Term Support：長期サポート)

##環境
* **JDK（Java Development Kit）**
    * JDKは、Javaアプリを開発／実行するために必要なソフトウェア
    * Java仮想マシン、コンパイラー、クラスライブラリ、デバッガーを備えた開発キット
    * OracleJDK、OpenJDK(オープンソース)、AdoptOpenJDK(IBM、マイクロソフトなど)

* **統合開発環境（IDE：Integrated Development Environment）**
    * コーディングを支援する諸機能を取りそろえたソフトウェア
    * コードエディター、デバッガー、プロジェクト管理機能など
    * ボタン1つでコンパイルから実行までを一気に実行
    * Eclipse、NetBeans、IntelliJIDEAなど


##Javaコードの全体像
##Class
* Javaによるプログラムの基本
* クラスは**アプリの中で特定の機能を担うかたまり**
    * String Class:文字列
    * Math Class:数学機能
    * FileReader/FileWriter:テキストファイルの読み書き
* これらのクラスを組み合わせアプリを作る
* Javaでは、ファイルとクラスを対応関係にする
    * ex:HelloクラスはHello.javaというファイルで定義

##メソッド
* class{...}配下に含まれる要素のことをメンバ(フィールド、メソッド、コンストラクターなど)
* メソッドは、**クラスの「機能」を表すためのメンバー、アプリで実行すべき処理を表す**
* Javaではアプリを起動したときに、まずmainメソッドを探して実行：**エントリーポイント**という


##パッケージ
* **クラスを分類するためのいれもの**
* `package com.example.demo.trySpring;`配下にある`HelloController`クラスなど


##名前解決
* クラスは**パッケージ＋クラス名**で識別：**完全修飾名（FQCN：Fully Qualified Class Name）**という
* FQCN：`package com.example.demo.trySpring.HelloController`


##ドキュメンテーションコメント
* あとでドキュメントの生成に利用できるコメントでアスタリスク2個で開始(複数行コメントは*1個)
* クラスやそのメンバーの説明を記述する

```Java
/***Reads text from a character input stream,...  //クラスの概要
*
*@see FileReader //関連項目
*@author MarkReinhold //作者
*@since1.1 //導入されたバージョン
*/

/***Create a buffering character-input stream from…  //コンストラクタの概要
*@param in A Reader //引数
*@param sz Input-buffer size //引数
*@exception //例外
*@retutn //戻り値
*/
```

#デバッグの基本
* **ブレークポイント設置**
    * 実行中のプログラムを一時停止する機能
    * エディターから行番号のひいだりクリック
    * ブレークポイントでプログラムの状態確認する
* **デバッグ実行**
    * ブレークポイントからは文単位でコード実行できる：**ステップ実行**
        * ステップイン:1行実行
        * ステップオーバー:途中メソッド呼び出し実行し次の行へ
        * ステップリターン:現メソッド呼びだし元に戻るまで実行
* **実行再開/終了**
    * 通常実行に戻すときは再開,終了したいときは終了ボタン
Pythonで型を極める？（型チェックをいつするべきか）

もともと以下の記事のコメントに書いていたのですが、コメントに書くには攻撃的すぎる内容だと思ったので、ここに移しました。
[Pythonで型を極める【Python 3.9対応】](https://qiita.com/papi_tokei/items/bf652696d6b98f23565a)

宗教論争を引き起こすだけ、であろうことは承知の上での記事です。

最近、静的型付けの利点（というか、動的型付けの欠点？）がよく語られるようになってきて、TypeScript が隆盛したり、Pythonでも静的な型チェックができるようになっています。
ただ、個人的に、（とくに動的型付け言語に、後から追加された静的型チェック機能において）、「不要な型付け」（場合によっては、むしろ「有害にすら思える型付け」）をしているコードが増えているような気がしています。

[Pythonで型を極める【Python 3.9対応】](https://qiita.com/papi_tokei/items/bf652696d6b98f23565a)
の記事で、

```Python
def add(a, b):
    """引数を足した結果を返す"""
    return a + b
```
に型を付けて

```Python
def add_type(a: int, b: int) -> int:
    """引数を足した結果を返す"""
    return a + b
```
とする、という例が登場します。

しかしながら、この例では、型は***書くべきではない***と思います。
不必要に型を特定するのは良くないです。
この場合、`a+b`という演算に意味があるような型であればよいのであって、intに特定するのは「悪い」プログラミングスタイルだと思います。
もちろん、上記は、単なる例として出しているだけ、というのは理解していますが、それでも、この例は「例として不適切」だと考えます。

>intに特定するとどういったケースで不都合があるのでしょうか？

現実は理想論だけではすまない、というのをわかった上で、理想論として語れば、

***具象型に対してではなくて、インタフェースに対してプログラミングするべき***

だからです。

この例で言えば、`add`関数は、「`+`演算子で加算できる」という性質（インタフェース）を備えた任意のオブジェクトに対して適用可能です。もちろん、個々の具体的な型によって、`+`演算子が実行する具体的な処理内容は異なりますが（ポリモーフィズム）、`add`関数は、`+`演算子という「インタフェース」に対してプログラミングしているわけで、`+`演算子の具体的な処理内容は関知していない（というか、`+`演算子の具体的な処理内容に依存しては***いけない***）わけです。

この例で、具象型である`int`に縛るべきではないです。そうしてしまうと、それこそ、後から、`int`ではなく`float`に変えたくなったら、プログラム上の`int`というキーワードを全て`float`に置換しないといけない、みたいな作業が発生することになります。

もっと言えば、`add`関数の引数を数値に絞る必然性もないと思います。`add`関数の引数は、`+`演算子というインタフェースが定義されていればよいわけで、`add`関数に、`str`や`list`、さらには、`__add__`特殊メソッドが定義された独自クラスを入力することは何の問題もないです。もっと正確に言えば、そもそも、`add`関数は`+`演算子を備える任意のオブジェクトに対してキチンと動作するように書かれている***べき***です。

実は、最近、静的型付け言語の世界(とくにC++やRustなんかでは顕著ですが)では、可能な限り型指定はしない（コンパイラに自動で型推論させる）、あえて型指定する場合でも最大限Genericな型にする、というプログラミングスタイルが広がっています。

一方で、最近、Pythonで型指定をしているコードをちょくちょく見かけるようになったのですが、なぜこんな「不要な型指定」をするのか、と疑問に思うコードが多かったりします。
正直に言うと、「３０年前のC++のコード」を見ているような気分になります。Pythonのプログラマーは、静的型付け言語の世界でのこの３０年の試行錯誤（とその結果起ったパラダイムシフト）を、またゼロからやり直すつもりなのか？と思ったり。

これを書くと宗教戦争を引き起こす可能性がかなりありますが、私の「偏見」では、Pythonで型指定したがるのは、Pythonが初めての言語の人たち（あるいは20〜30年前のC++やJavaの知識で止まっている人たち）であって、むしろ、最近、静的型付け言語からPythonに移ってきた人たちは、Pythonで型指定したがらない、という印象があります。
ワイ「TypeScriptなんも分からん」

## TypeScriptなんも分からんワイ

ワイ「なぁ、ハスケル子ちゃん」

ハスケル子「はい」

ワイ「最近、**TypeScript**っていうのが流行ってるみたいやけど」
ワイ「何がええの？」
ワイ「普通のJavaScriptじゃアカンの？」

ハスケル子「うーん」
ハスケル子「じゃあ、VSCodeでコードを書きながら説明しますね」
ハスケル子「例えば・・・」

```javascript:sample.js
const titles = ['記事タイトル1', '記事タイトル2', '記事タイトル3']

const newestTitle = titles.pop()

console.log(newestTitle)
```

ハスケル子「↑このコードは正しく動くと思いますか？」

ワイ「ええと」
ワイ「まずは`titles`という変数に、記事タイトルが3つ入った**配列**を格納するんやな」
ワイ「そんで、配列が持ってる`pop()`メソッドを実行して」
ワイ「一番最後の要素を取得しとるわけか」
ワイ「ほな、`newestTitle`という変数には`'記事タイトル3'`が格納されるな」
ワイ「せやから、コンソールには`'記事タイトル3`と表示されるはずや」
ワイ「問題ないな」
ワイ「これは、正しく動くコードやで！」

ハスケル子「そうですよね」
ハスケル子「じゃあ次は・・・」

```javascript:sample.js
const titles = '記事タイトル1'

const newestTitle = titles.pop()

console.log(newestTitle)
```

ハスケル子「↑このコードはどうですか？」
ハスケル子「正しく動きますか？」

ワイ「ええと、`titles`という変数に`'記事タイトル1'`という**文字列**を格納して」
ワイ「そのあと`titles.pop()`しとるわけか」
ワイ「あれ、**文字列**は`pop()`なんてメソッドを持ってたっけ？」
ワイ「たぶんエラーになるやろ」

ハスケル子「そうですね」
ハスケル子「実際にブラウザ上でこのコードを実行してみると、こんなエラーが出ます」

> titles.pop is not a function
> （titles.popは関数とちゃうで！）

ワイ「せやな」
ワイ「文字列は`pop()`なんていうメソッドを持ってへんからな」
ワイ「`titles.pop`は未定義、つまり`undefined`扱いや」
ワイ「変数でも関数でもあらへん」
ワイ「せやから」

> titles.popは関数とちゃうで！

ワイ「って怒られてまうんやな」

ハスケル子「はい」
ハスケル子「要するに」

> 文字列を、間違えて配列として扱おうとするとバグっちゃうよ

ハスケル子「って話ですよね」

ワイ「せやね」

ハスケル子「実際のWebサイトでこういうバグを起こすと、マズいですよね」

ワイ「まあ、クライアントさんから怒られてまうな」

ハスケル子「そこで**TypeScript**です」

ワイ「ふーん」

## あり得ないことをしていたら教えてくれる

ハスケル子「さっきの**間違ったコード**を、TypeScriptを使って書いてみましょう」
ハスケル子「やめ太郎さん、やってみてください」
ハスケル子「拡張子は`.ts`でお願いします」

ワイ「はいよ」
ワイ「TypeScriptでは`.js`やなくて`.ts`なんやね」
ワイ「はい、書きましたやで」


![スクリーンショット 2020-10-28 10.31.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/0ee12e44-5fba-d639-d513-1294220e935a.png)


ワイ「おお、`pop`の部分に赤い波線が出とるな」

ハスケル子「文字列は`pop()`メソッドを持っていないので」
ハスケル子「そういう**あり得ないこと**をしようとすると」
ハスケル子「エディタが教えてくれるんです」

ワイ「なるほどな」
ワイ「ブラウザ上でポチポチ動作テストせんくても」
ワイ「**コードを書いとる段階で気づける**わけやね」

ハスケル子「はい」
ハスケル子「あとですね、赤い波線が出ている`pop`の部分に」
ハスケル子「マウスをホバーさせてみてください」

![スクリーンショット 2020-10-28 10.11.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/392d8043-b982-2423-2779-0de1a24457ad.png)

ワイ「おお、詳細なエラーメッセージが表示されたで」
ワイ「なんや、TypeScriptって親切なやつなんやな」

ハスケル子「そうなんですよ」
ハスケル子「あり得ないことをして`undefined`エラーが出るのを、事前に防いでくれるわけです」

ワイ「なるほどな」
ワイ「小さめのサイトなら、気をつけてコーディングすれば」
ワイ「バグは出ないかもしれんけど」
ワイ「大規模なサイトだと、どっかでミスは起きるから」
ワイ「TypeScript君に見つけてもらえると」
ワイ「だいぶバグを減らせそうやな」

ハスケル子「はい」
ハスケル子「ほかにもVSCodeくんから受けられる恩恵が**だいぶ増す**ので」
ハスケル子「かなりメリット大きいです」

ワイ「ハスケル子ちゃん、ありがとうやで」
ワイ「ワイもTypeScript勉強してみるわ！」

ハスケル子「TypeScriptは、JavaScriptに変換しないとブラウザ上で動かないので」
ハスケル子「変換するための環境構築とかも勉強してくださいね！」

ワイ「おう！」

## 続編もよろしくやで！

[**ワイ「TypeScriptのエラーが読まれへん」**](https://qiita.com/Yametaro/items/bc592ed712edd329f364)

## 勉強におすすめのサイト
[**TypeScript Deep Dive 日本語版**](https://typescript-jp.gitbook.io/deep-dive/getting-started)

## とりあえず触ってみたい人におすすめのサイト

[**TS Playground**](https://www.typescriptlang.org/play/)
ブラウザ上でTypeScriptを書いてみられるサイト

[**セットアップ | Nuxt TypeScript**](https://typescript.nuxtjs.org/ja/guide/setup.html)
Nuxt.js（Vue）で使ってみたい人はこちら

[**TypeScript Next.js example**](https://github.com/vercel/next.js/tree/canary/examples/with-typescript)
Next.js（React）で使ってみたい人はこちら
React + Amplify環境構築手順

# React + Amplify環境構築手順

ReactでCognito認証を作成したため、本記事にまとめました。

Amplifyは、AWSが提供するWebアプリの開発を支援するためのフレームワークで、Cognito認証などがAPIとして提供されているもので、
他にもホスティングの機能などもありますが、今回は使用しないため、Cognito認証に特化して手順を説明します。

WebアプリのフレームワークはReact(Typescript)とする。

[前提条件]
create-react-appでReact実行環境は作成済みの状態とする。

### 1. Amplifyのインストール

```
$ npm install aws-amplify aws-amplify-react @aws-amplify/ui-react
```



### 2. index.tsxにAmplifyの認証情報追加

```
import Amplify from 'aws-amplify';

Amplify.configure({
  Auth: {
      region: 'ap-northeast-1',
      userPoolId: 'ユーザープールID',
      userPoolWebClientId: 'アプリクライアントID'
  }
});
```

ユーザプールIDとアプリクライアントIDは、AWSコンソールのCognitoの画面から取得できる。

AWSのサービスを直接Webアプリから制御する場合は、IDプールの設定も必要だが、API Gatewayに対するREST APIでのみ制御するので、一旦IDプールの指定は不要とする。



### 3. 認証

aws-amplifyのAuthオブジェクトの各関数をコールすることで、サインインやサインアウトはできた。

```
import { Auth } from 'aws-amplify';

//サインイン
Auth.signIn(userSigninInfo.name, userSigninInfo.password)

//サインアウト
Auth.signOut()

```




### 4.トークン取得

AuthでcurrentSessionで取得できた。

```
import { Auth } from 'aws-amplify';

    useEffect(() => {
        Auth.currentSession()
            .then((data: any) => {
                setIdToken(data.getIdToken().getJwtToken());
            }).finally(() => {
                setLoading(true);
            });
    }, []);
```



上記取得したトークンをAPI GatewayのREST APIコール時にヘッダに付与すると、API GatewayでCognitoで認可していた場合、正常に動作する。



[参考URL]

・Amplify使い方1
https://qiita.com/herohit-tool/items/7a7e7bf3cbfa5b7ddff6

・Amplify使い方2
https://qiita.com/Engineer_Grotle/items/fa37a3924d1e66082889

・トークン取得
https://dev.classmethod.jp/articles/swagger-ui-with-amplify-react/

・Amplify公式
https://docs.amplify.aws/ui/auth/authenticator/q/framework/react#custom-form-fields

・AmplifyをHook化
https://qiita.com/G-awa/items/99cb84c62fcd113943a6
AWS Cognito 構築手順

# AWS Cognito 構築手順
世にたくさん出回っていますが、整理した手順です。

## ユーザプールの作成

### 1. AWSサービスからCognitoを選択



### 2. ユーザプールを作成する。を選択



### 3. プール名を任意で決めて、「ステップに従って設定する」を指定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696083/59867033-f1fc-1db3-2783-22015b6316c5.png)

### 4. 属性の設定

本設定は後から変更できないとのこと。

今回の設定では、下記とした。(用途によって適宜設定する)

- 認証時のユーザ名は「ユーザ名」(他にも任意のメールアドレスや電話番号が選択できるが、メールアドレスの場合、重複登録ができず動作確認しにくいため、今回はユーザ名にしておく)
- サインアップ時の入力必須項目は無しにしておく。(住所、電話番号、名前、誕生日や性別など指定できる)

### 5. ポリシーの設定

- パスワードの強度は、最小８文字、数字、特殊文字、大文字、小文字を必要とする。(デフォルト)

- 管理者のみサインアップ許可(管理者以外のユーザにもサインアップの許可を与えることができる)

- 一時パスワードの有効期限7日間(デフォルト)

### 6. MFAの設定

- MFA無効

- アカウント回復の方法は、なし(他にも「Eメール」や「電話」が選択できる)

- Cognitoに対するSMSメッセージの送信を許可するロールは作成しない(作成するとMFAを有効にする必要がある)



### 5. メッセージのカスタマイズ

SMSで送信するメッセージ内容のカスタマイズ。

今回は、デフォルトのまま。



### 6. タグ

現状、必要かわからず、必要あれば別途追加できそうなので、とりあえず未設定のまま。



### 7. デバイス設定

クライアントのデバイス記録の機能を使用するか選択します。 

今回は”いいえ”を選択します。 機能を使用する場合はMFAの設定が必要になるようです。



### 8.アプリクライアントを指定

クライアント名の入力と「クライアントシークレットの生成」のチェックを外すす(※1)。

※1:クライアントシークレットの生成は、JavascriptのSDKが対応していないとのことでJavascriptでアプリを作るのであれば、必須

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696083/6759f50f-8b45-03f9-71c7-d38f45bb3d4f.png)


<備考>
「トークンの有効期限」のトークンとは更新トークンのことで、認証後、アクセストークンを背面で更新してくれる期間のこと。
「アクセストークン」はリソースへの更新権限を許可するためのトークン
「IDトークン」はその人がだれかを確認するためのトークン

### 9. トリガ

認証時前や後に起動するLambdaが設定できる。
今のところ使用しないので設定しない。

### 10. ユーザ登録

現時点では、ユーザ登録をWebアプリからしないので、AWSコンソールから手動でユーザ登録した。

[参考URL]

1. jsでCognitoと対応したWebアプリ作成する手順
https://docs.amplify.aws/lib/client-configuration/configuring-amplify-categories/q/platform/js#general-configuration

2. トークンの説明
https://yyh-gl.github.io/tech-blog/blog/id_token_and_access_token/

3. Cognitoユーザプール作成
https://www.tdi.co.jp/miso/amazon-cognito-sign-up
乳幼児の予防接種管理ツールを作った。

乳幼児の予防接種スケジュール管理ツールを作りました！
初めてオリジナル企画で作ったサイトです。
カレンダーから日付を入力して、そこから計算した指定の日付を表示させるだけなので、開発と呼ぶにはおこがましい程のレベルのものですが、まぁ作ったよね。ww
jQueryとMoment.jsを使用。この時初めて、静的なサイトであれば、S3にアップロードするだけでサーバが要らないという事実を知りました！(\*'ω'\*)

↓↓ こんなツールです。お子さんのお誕生日を入力すると、いつ頃予防接種に行けばいいのかを自動表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/f4709b33-2d0d-d832-8918-3b2ee023a709.png)

<a href="https://baby-vaccine.s3-ap-northeast-1.amazonaws.com/index.html">予防接種スケジューラー</a>　← こっからサイトに飛んでください～。

私自身、1歳10ヶ月と8ヶ月の息子が2人いるのですが、予防接種の種類や回数が多くて、ちゃんと管理できるか不安だったんですね。そんな時に長男を産んだ産院で、今回作ったツールのような管理表をもらいまして、それがすっごい便利～！と思ったのでWebバージョンを作ろうと思ったわけです。
ただ、色々と調べたのですが、各市区町村によって定期接種対象のワクチン等が微妙に違う（！？）みたいで、埼玉県の予防接種情報を元に作っています。ご了承ください。(m´・ω・｀)m ｺﾞﾒﾝ…  （でも、あまり大きな違いはなかったので、埼玉県外の方も十分使っていただけると思います！）

小さいお子さんを持つ方はぜひ使ってみてください！
また、お知り合いでいらっしゃる方はぜひ紹介してみてください～。宜しくです。( ｀・∀・´)ﾉﾖﾛｼｸ
WebアプリからAWSユーザ認証する方法について

# AWSユーザ認証の方法

## 概要

まず、Webアプリを作成する方法として、大きくは下記2種類ありますが、今回はS3にホスティングする方法でのユーザ認証の方法について、まとめます。

- EC2を使用する方法
- S3にホスティングする方法

S3にWebアプリをホスティングし、AWSに対してリクエストする構成としては、下図の通り。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696083/b8972305-e1a3-beb4-396b-f98ee1f7d332.png)

## ユーザ認証の方法

下記の３種類があるが、Cognitoを使用した認証が一般的に思う。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696083/d1161bf6-6e1d-768e-208e-36800d3c49f9.png)



下記個別のメリット・デメリット

### 1. AWS Cognitoを使用する方法

AWSのサービスでユーザ名、パスワードを用いたユーザ管理をすることができる。

Googleアカウント、Facebookアカウントなどでの認証もできる。

#### [メリット]

- 独自のユーザ認証の仕組みを作成する必要がない。
- ユーザ名、メールアドレスなどで認証する仕組みを作れる
- 一時的なセキュリティ情報として認証できる(有効期限を設けることができる)ため、安全

#### [デメリット]

- 有料

  →ただし、50,000ユーザ(月間アクティブユーザ)まで無料



### 2. AWS IAMを使用する方法

IAMと対応するアクセスキーとシークレットキーを発行してアクセスする方法。

#### [メリット]

- 独自のユーザ認証の仕組みを作成する必要がない。

#### [デメリット]

- AWSがランダムで発行するアクセスキーとシークレットキーを使用する必要がある。

- 基本的に一般ユーザに配布して使用するものではなく、サーバサイドでの制御に使用するもの。

- 一時的なセキュリティ情報とならないため、危険。

  

### 3. Lambdaを使用する方法

独自のユーザ管理、認証の方法を構築する必要がある。

#### [メリット]

- 自由に作ることができる。

#### [デメリット]

- 認証の仕組みをすべて作成する必要がある。



## Amazon Cognitoについて

### 概要

Amazon Cognito は、ウェブアプリケーションやモバイルアプリケーションの認証、許可、ユーザー管理をサポートするサービス。

Amazon Cognito の主な 2 つのコンポーネントは、ユーザープールと ID プールです。



### 1. ユーザプール

ログインを提供する機能。

- ユーザパスワード、メールアドレス、電話番号、カスタム属性などを格納可能　ユーザにまつわるデータベースのようなもの。
- 上記を利用して認証し、API Gatewayにアクセス可能なトークンを取得することができる。



### 2. IDプール

ユーザープールからユーザ認証成功時に発行されるトークンを使って、AWSのサービスに対するアクセス権を得ることができる機能のこと。

AWSのS3やDynamoDBなどのサービスに直接アクセスするときに使用する機能。

今のところ私の用途ではAPI Gateway経由でのアクセスを想定しており、今回は説明しない。



### 3. アクセスの流れ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696083/d854d5a0-4b3e-14eb-1153-9c185ba09106.png)

1. S3からWebページを取得する。
2. Cognitoを使用してユーザ認証を行う。
3. 認証成功時に取得したトークンを使用してAPI GatewayへRequestし、情報を取得する。



### 4. 認証したユーザをAWS内で特定する方法について

Cognitoで認証時に取得できるトークンをBase64でデコードすると、ユーザ名などの情報を取得する事ができる。

API GatewayのREST APIコール時、上記トークンを使用するため、Lambdaでユーザ名を取得することができ、ユーザ名などのユーザ管理情報をDBなどに保持しておけば、ユーザ情報を特定することができると考える。


[参考URL]

・Cognitoについての概要
https://qiita.com/fjisdahgaiuerua/items/d420a2137e8d67e0a190

・CognitoとIAMでの認証の違い
https://qiita.com/katekichi/items/dbf279077db6a7b597fc
https://www.skyarch.net/blog/?p=16856
https://dev.classmethod.jp/articles/lex_access_by_unauth_user_using_cognito/

・Cognito QA
https://aws.amazon.com/jp/cognito/faqs/

・参考動画
https://www.youtube.com/watch?v=wnB6Fq7-tHs
3分アジャイル スプリントレビュー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/6751e4ab-e9b5-3f65-7c6c-5dee9fc0f2de.png)
[^1]

[^1]: Kenneth S. Rubin. エッセンシャル スクラム (Japanese Edition) (Kindle Location 1462). Kindle Edition. 

--- 

## スプリントレビュー
- スプリントで実装できたこと（インクリメント）を共有
- デモ会
- 招待: PO、ステークホルダー、外部の人を招待

---

## 何をするか
- フロント: モックの確認
- サーバ: エンドポイントの動作？

どこかで軽いミーティングをさせてください。

---

## 先日のレトロスペクティブについて
- 今回のスプリントでまずKPTはどうでしょう？
- 他に案があれば是非そちらを。
- KPTやってみて他の方法でも


---

## デイリー
- 昨日やったこと
- 今日やること
- 自分やチームが困っていること


---

スプリントレビューとは、スプリントの終了時にインクリメントの検査と、必要であればプロダクトバックログの適応を行うものである。スプリントレビューでは、スクラムチームとステークホルダーがスプリントの成果をレビューする。スプリントの成果とプロダクトバックログの変更を参考にして、価値を最適化するために次に何ができるかを参加者全員で話し合う。これはステータスミーティングではなく、略式のミーティングである。インクリメントを提示することで、フィードバックや協力を引き出すことを目的とする。


スプリントが 1 か月の場合、スプリントレビューは最大 4 時間である。スプリントの期間が短ければ、スプリントレビューの時間も短くすることが多い。スクラムマスターはスプリントレビューが確実に開催されるようにして、参加者には目的を理解してもらうようにする。スクラムマスターは関係者全員にタイムボックスを守るように伝える。

スプリントレビューには、以下の要素が含まれる。

• 参加者は、スクラムチームと、プロダクトオーナーが招待した重要なステークホルダーである。
• プロダクトオーナーは、プロダクトバックログアイテムの「完成」したものと「完成」していないも
のについて説明する。
• 開発チームは、スプリントでうまくいったこと、直面した問題点、それをどのように解決したかを
議論する。
• 開発チームは、「完成」したものをデモして、インクリメントに対する質問に答える。「完成」の定
義にプロダクト機能のリリースが含まれていれば、それらを表示してレビューしてもらう。
• プロダクトオーナーは、現在のプロダクトバックログの状況を説明する。（必要であれば）現在
の進捗から、可能性のある目標とデリバリーの日程を予測する。
• グループ全体で次に何をするべきかを議論し、次のスプリントプランニングに価値のあるイン
プットを提供できるようにする。
• 市場やプロダクトの利用状況によって、次に行うべき最も価値の高いことが変更される可能性
をレビューする。
• 次にリリースするプロダクトの機能や性能のスケジュール・予算・可能性・市場をレビューする。

スプリントレビューの成果は、次のスプリントで使用するプロダクトバックログアイテムが含まれた改
訂版のプロダクトバックログである。新たな機会に見合うように、プロダクトバックログを全体的に調整することもある。[^guide]

[^guide]: https://www.scrumguides.org/docs/scrumguide/v2017/2017-Scrum-Guide-Japanese.pdf
Pythonで算出するVIFとExcelで算出するVIFが違う..??

# PythonでVIF確認出来て超便利！
PythonでVIF(Variance Inflation Factor)を調べることができ、この結果を見ながら説明変数間の多重共線性を確認することができます。
一般的にVIF>10の場合は多重共線性が強いと判断できるとの事。

```python
from statsmodels.stats.outliers_influence import variance_inflation_factor

df_all = pd.read_excel('train.xlsx',sheet_name="Sheet1")

cols = df_all.select_dtypes(include=[np.number]).columns
cols_x = cols[1:]
data_x = df_all[cols_x]
#vifを計算する
vif = pd.DataFrame()
vif["VIF Factor"] = [variance_inflation_factor(data_x.values, i) for i in range(data_x.shape[1])]
#vif["features"] = data_x.columns 
 
#vifを計算結果を出力する
print(vif)
 
#vifをグラフ化する
plt.plot(vif["VIF Factor"])

```

こんな感じで結果が出ます。便利ですよね！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635959/71be02a4-ed1e-6c13-9f3a-dbae4606bab2.png)

#ところが、、Excelで算出したVIFと比較すると..
VIFが異なる結果で出てくることが発覚しました('Д')..!!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635959/75a9c319-a791-9d49-7065-a5d3e72f95c4.png)

そもそもVIFは以下の式で求められます。

```
VIF = 1/(1-R2) # R2：決定係数
```
説明変数の１つを目的変数と見立てたときに、残りの説明変数で重回帰分析した際に得られる決定係数R2を使用します。
感覚的に言えば、「残りの説明変数である１つの変数を上手に表現できるなら、その変数はいらなくない？」って事だと理解しています。
VIFが違うという事は、PythonとExcelでこのR2が異なるということになるので、一瞬パニックになりました。

#違いの原因は、切片を含むか否か..でした。
何故異なるか、その原因は説明変数に切片を含めるか否か、という事が判明しました。

Python側では、切片=0として処理
Excelで検討した際は、切片を特に指定しませんでした。

Excelでも切片=0とするように設定したところVIFが一致することを確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635959/d0b01825-0d22-7cf1-b2bd-f797857d2436.png)
↑ここにチェックを入れるかどうか

# 皆さんに聞きたい..結局どっちが正しいのでしょうか？
- Pythonのstatsmodel使っておけば問題ないのでは？
- 切片は特に指定するべきではない?
- とにかくR2が最大になる組み合わせでVIFを評価するべきで、切片が0か否かは重要ではない?
- VIFはあくまで目安なので、特に気にする必要はない?

上記のようなことを考えているのですが、皆さんいかがでしょうか？
そもそもstatsmodelのVIF算出アルゴリズムがどうなっているのかも気になります..。

### ご意見やアドバイスがあれば是非、よろしくお願いします！！
flexの使い方

#flex
![スクリーンショット 2020-10-26 9.02.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633943/cf998b73-4b6b-117b-6327-6ab43874a45e.png)

```html:index.html
<div class="feature-item">
          <div class="feature-img-wrapper">
            <a href="https://www.yahoo.co.jp" target="_blank">
            <img src="img/feature/feature.jpg" alt="">
            </a>
          </div>
          <div class="feature-body">
            <p><span class="text-bold">サイト名：</span>
              <br>サイト名が入る<br>
              <a href="#" target="_blank">https://●●●.com</a>
            </p>
          </div><!-- ./feature-body -->
</div><!-- ./feature-item -->
```

```css:style.css
.feature-item{
  display: flex;
  margin-bottom: 80px;
}
.feature-img-wrapper{
  flex-basis: 45%;
  margin-right: 40px;
}
.feature-body{
  flex: 1;
}
```

##参考
[ポートフォリオHTMLテンプレート（ベーシック）](https://webdesigner-go.com/template/portfolio-02/#comment-799)

この間書いた「float」を使ったボックスの配置から「flex」でやってみました。
[この間書いた「float」の記事](https://qiita.com/kyototea/items/db9f8d7ffe6e3c0c3fed)
手動で@ConfigurationProperties相当の処理をする

Spring Bootの```@ConfigurationProperties```はプロパティファイルの設定値を自動的に読み込み仕組みだが、それと似たような処理を手動で記述したい。

たとえば、いま下記のような```kafka.properties```があり、これを```org.springframework.boot.autoconfigure.kafka.KafkaProperties```に読み込みたい、とする。

```yaml:kafka.properties
spring.kafka.bootstrap-servers=localhost:32770
spring.kafka.consumer.group-id=java-consumer-group
```

```java:KafkaProperties
@ConfigurationProperties(prefix = "spring.kafka")
public class KafkaProperties {
  ...
```

これをするには、```Map```を設定値のソースとする```MapConfigurationPropertySource```を使用する（```Properties```は```Hashtable```を継承している）。

```java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Properties;

import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;

public class HogeMain {
	public static void main(String[] args) throws IOException {
		Properties properties = new Properties();
		properties.load(Files.newInputStream(Paths.get("kafka.properties")));

		ConfigurationPropertySource source= new MapConfigurationPropertySource(properties);
		Binder binder = new Binder(source);

		KafkaProperties kafkaProperties = binder.bind("spring.kafka", KafkaProperties.class).get();
	}
}

```

yamlの場合、```YamlPropertiesFactoryBean```から```Properties```が得られるので、これを経由させる。

```java
YamlPropertiesFactoryBean y = new YamlPropertiesFactoryBean();
y.setResources(new ClassPathResource("hoge.yml"));
Properties object = y.getObject();
```

# 参考
* https://stackoverflow.com/questions/26940583/can-i-manually-load-configurationproperties-without-the-spring-appcontext/39774535
設計ナイト2020感想

[吉祥寺.pm](https://kichijojipm.connpass.com)様主催の[設計ナイト2020](https://kichijojipm.connpass.com/event/191220/)に参加してきました。
ついていけてない部分もあって全部覚えきれていませんが、これ以上忘れる前に書き留めておきます。

# CQRS+Event Sourcing

最初は[かとじゅん](https://twitter.com/j5ik2o)さんによる発表でCQRSとEvent Sourcingについての説明でした。資料は以下のリンクです。
https://speakerdeck.com/j5ik2o/event-sourcingwojie-shuo-suru
まとめると以下のような内容でした。

- CQRSは境界を引いてCとQを完全に分断しなければならないので、コストがかかる。
- Event Sourcing無しでCQRSは難しい。
- コストをペイできるほどの大規模なものや、耐障害性を求めないならやらないほうがいい。

かとじゅんさんが提示されていた現実解は私もよくやっていました。WEBサービスをベースに考えますが、そもそもクエリパラメーターによって条件を変化させたり、ページネーションのような取得件数の上限を設けたりしなければいけないGETリクエストと、ドメインロジックによるほぼ固定された条件によるデータ取得しかしないその他で同じモジュール使ってデータ取得すると、どっちかに負債ができるので、最初から別々のモジュール使ったほうがいいと思ってます。ただ、かとじゅんさんが提示されていた現実解ではクエリでドメイン側のVO使うとされてましたが、私は全て禁止してました。基本的にはデータ設計はイミュータブルデータモデル([入門編](https://www.slideshare.net/kawasima/ss-40471672),[世代辺](https://www.slideshare.net/kawasima/ss-44958468))をベースにしてるのですが、クエリ用に非正規化されたテーブル用意したりもしますし、クエリ側にコマンドのVOのロジックが影響を及ぼすのは嫌だったので。DRYではないのでは？と思うこともありましたが、そこは許容範囲だと思ってます。
イベントストアについては、チャット欄含めていくつかおすすめされてました。

- HBase
- Kafka
- Datomic

今後Event Souringやることになったら参考にしてみようと思います。

# GraphQL

[qsona](https://twitter.com/qsona)さんの発表はGraphQLについてでした。資料は以下のリンクです。
https://hackmd.io/@jnl1y8gDTkq7ywsLXpa6GQ/HkDGObSOP
GraphQLについてはクライアントサイドもサーバーサイドも扱ったことがないので、あまりついていけてませんでした。
ただ、具体的な実装についても資料で提示されているので、今度自分で作ってみてもいいなと思いました。
BFFでGraphQLを使うという意見もありましたが、こちらについては「BFF自体がフロントエンドの特定のユースケースを満たすという目的で作られるものなので、あらゆるクライアントサイドで好きにやらせる目的で作るGraphQLとはニーズが合わないのではないか」という意見があり、これには納得しました。

# まとめ

こういう設計の話は大好きなので、こういうイベントもっと参加したいのですが、中々ないのですよね。(探し方が悪いだけかもしれませんが)
もっと話ついていけるように、プログラミング言語だけでなくストレージとかキューとかの技術をもう少し触っていこうかなと思いました。
【Node+Vue】ストア+APIを経由してサーバで作ったバイナリファイル受け取りダウンロードさせる

リアクティブでSPAでなければ、サーバサイドにPOSTしてファイルをダウンロードさせれば簡単だけど
v-router とか使うと簡単には行かず、困ったのだけれど、
以下の方法で受け渡しできたので備忘録として記載しておく。

【仕様】
・ダウンロードボタンを押すと、サーバ側で作成されたファイルをダウンロードする。

【前提】
・vue から直接サーバ側へはPOSTできない。(ルーターが邪魔する。)
・ストア＋API経由でサーバ側とのデータのやり取りはできる。

【サーバ側実装】
今回は、API経由でデータが渡されると、サーバ側でファイルを作成し、base64エンコードした内容を
json形式で { DATA: xxxx } として返すようにした。

【クライアント側実装】
こんな感じ
今回の肝は以下の2箇所。
・base64 をデコードする部分
・blobファイルをダウンロードさせる部分。

```
methods: {
  /**
   * ダウンロード
   */
  async download() {
    let info = { // api に渡す引数があれば、こんな感じで受け渡す。
      name: "download.csv"
    };
    let data = await this.$store.dispatch("download", { info });

    // base64をデコードする。
    let base64 = data["DATA"];
    let bin = atob(base64.replace(/^.*,/, ''));
    let buffer = new Uint8Array(bin.length);
    for (var i = 0; i < bin.length; i++) {
      buffer[i] = bin.charCodeAt(i);
    }

    // 以下のコードが実行されると、勝手にファイルがダウンロードされる。
    const blob = new Blob([buffer.buffer], { type: 'application/csv'});
    let link = document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    link.download = 'download.csv';
    link.click();
  }
},
```

download() を呼び出すボタンはこんな感じ。

```
<v-btn text @click="download" v-bind="attrs" v-on="on">
<v-icon>mdi-download</v-icon>
</v-btn>
```

直接、サーバサイドにPOSTできれば簡単だったけれど、そうすると他とセオリーが異なってしまう。
ボタンが押されると、すぐ遷移してそちらで処理されるのとは異なり、
ボタンが押されると非同期で axios 通信が行われ、データを受け取った後にダウンロードされることになる。
inputタグを選択時に出てくる青線を消す方法

## ■ はじめに

inputタグをクリックすると出てくる青線を消す方法について記事にしました。

■ この記事で出てくるCSSプロパティやクラス
・outlineプロパティ
アウトラインのスタイル・太さ・色をまとめて指定する。borderと異なり、上下左右の概念がない

・focus
擬似クラスで、ユーザーの操作によりフォーカスされた際にスタイルを適用する
例えば、フォームの入力欄にカーソルを合わせてテキストを入力できる様になった状態など

## ■ 例
検索窓をクリックしたら出てくる青い枠なんですが、inputタグに`border-radius`を指定していて
青い枠がinputタグからはみ出てしまいカッコ悪くなっています

![スクリーンショット 2020-10-28 10.02.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772631/15f78c4b-7a4f-5d57-d3f7-f7d16bf41537.png)

## ■ 手順
① `outline: none;`を指定して、選択した時の青い線を消して
<font color="red">20/11/21(土)追記：</font>元々表示されている枠線を消す時は`border: none;`

![スクリーンショット 2020-10-28 10.07.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772631/2e2cd096-8136-cfc1-38d4-49a85311991c.png)

② 上の画像の様に、テキストカーソルが左に寄りすぎていたら、`padding`で調整します

![スクリーンショット 2020-10-28 10.10.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772631/e9d32e99-4b1e-223a-0f7a-b69bdd452017.png)

③ 上の状態からクリックして色をつけたい時は、擬似要素`:focus`を使って色を指定します
  
![スクリーンショット 2020-10-28 11.01.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772631/c1e7c3df-fc45-4d36-46a2-b117dbd9be4c.png)
競プロのライブラリ整理~最小全域木~

長らく逃げ続けていた最小全域木のライブラリの作成でしたが、昨日解いた[Shichikuji and Power Grid](https://codeforces.com/contest/1245/problem/D)において必要であったので作成しました。今のところは実装の容易な**クラスカル法しかありませんが**、気が向いたらプリム法のライブラリも作成したいと思います。

また、クラスカル法を書くにあたり、コードは[こちらの記事](https://algo-logic.info/kruskal-mst/)のものを参考にさせていただいたのと、この記事ではクラスカル法の中身については触れないので他の記事を読んでください。

#クラスカル法とは？

重み付き連結グラフの最小全域木を求めるアルゴリズム

全域木…**グラフが連結のまま辺を消去して得られる木のこと**
最小全域木…辺の重さの総和が最小となる全域木のこと

#計算量

頂点数$n$,辺数$m$のときの計算量は

辺のコストの昇順でのソートで$O(m \log{n})$、UnionFind木へのuniteで$O(m \alpha{(n)})$なので、$O(m \log{n})$となります。

#自分のコードの説明

以下のコードはUnionFindのライブラリのせいで長く見えますが、重要なのはKruskalという関数のみです。

この関数内で必要な辺を順に追加しており、最終的に**最小全域木のコストを返り値として返します**。もちろん、最小全域木に含まれる辺のみを抜き出すことも可能です。

#問題例

①[ABC065-D Built?](https://atcoder.jp/contests/abc065/tasks/arc076_b)

基本問題です。

②[Codeforces Round #597(Div.2) Shichikuji and Power Grid](https://codeforces.com/contest/1245/problem/D)

**超頂点を導入する**ことでスムーズに解くことができます。
[この記事](https://qiita.com/DaikiSuyama/items/3fbab8b47df1325cc600)に解法を書きました。

#コード

```C++:Kruslal.cc
//以下、素集合と木は同じものを表す
class UnionFind{
public:
    vector<ll> parent; //parent[i]はiの親
    vector<ll> siz; //素集合のサイズを表す配列(1で初期化)
    map<ll,vector<ll>> group; //集合ごとに管理する(key:集合の代表元、value:集合の要素の配列)
    ll n; //要素数

    //コンストラクタ
    UnionFind(ll n_):n(n_),parent(n_),siz(n_,1){ 
        //全ての要素の根が自身であるとして初期化
        for(ll i=0;i<n;i++){parent[i]=i;}
    }

    //データxの属する木の根を取得(経路圧縮も行う)
    ll root(ll x){
        if(parent[x]==x) return x;
        return parent[x]=root(parent[x]);//代入式の値は代入した変数の値なので、経路圧縮できる
    }

    //xとyの木を併合
    void unite(ll x,ll y){
        ll rx=root(x);//xの根
        ll ry=root(y);//yの根
        if(rx==ry) return;//同じ木にある時
        //小さい集合を大きい集合へと併合(ry→rxへ併合)
        if(siz[rx]<siz[ry]) swap(rx,ry);
        siz[rx]+=siz[ry];
        parent[ry]=rx;//xとyが同じ木にない時はyの根ryをxの根rxにつける
    }

    //xとyが属する木が同じかを判定
    bool same(ll x,ll y){
        ll rx=root(x);
        ll ry=root(y);
        return rx==ry;
    }

    //xの素集合のサイズを取得
    ll size(ll x){
        return siz[root(x)];
    }

    //素集合をそれぞれグループ化
    void grouping(){
        //経路圧縮を先に行う
        REP(i,n)root(i);
        //mapで管理する(デフォルト構築を利用)
        REP(i,n)group[parent[i]].PB(i);
    }

    //素集合系を削除して初期化
    void clear(){
        REP(i,n){parent[i]=i;}
        siz=vector<ll>(n,1);
        group.clear();
    }
};

//辺の構造体
struct Edge{
    ll u,v,cost;
    //後ろにconstつける！
    bool operator<(const Edge& e) const {return this->cost<e.cost;}
};

//クラスカル法
//ret:=最小全域木の重みの総和
//n:=頂点の総数
//計算量:=O(m log{n})
ll Kruskal(vector<Edge> &edges,ll n){
    sort(ALL(edges));//辺の重みの昇順
    UnionFind uf(n);
    ll ret=0;
    FORA(e,edges){
        //その辺を加える必要があるか
        if (!uf.same(e.u,e.v)){
            uf.unite(e.u,e.v);
            ret+=e.cost;
        }
    }
    return ret;
}
```
Databricks Community Edition ~クラスタ立ち上げ~




以前、Databricks Community Editionをサインアップ方法について、記載させていただきました。

今回はサインアップしてから、プラットフォームを動かすまでに必要なSparkクラスタの立ち上げについて、記載していきます。



Databricks Community Editionにサインアップしてから、MLflowを動かすまでにはクラスタの立ち上げが必要になります。

そこで、今回はクラスタの立ち上げについて、記載します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817530/d3d27e03-2df6-1bfc-bde4-92f94a8c5682.png)



こちらがホーム画面です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817530/9ec1246e-8f95-22af-9239-60451542983c.png)


ホーム画面上にあるNew Clusterをクリック（もしくは、左側に表示されているClustersのタブをクリック）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817530/df4540c8-c894-ae48-f5c9-236617f1890d.png)

New Clusterを押下すると、上記の画面に遷移します。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817530/bf3193d7-37fe-7191-0228-5e426bfcce6c.png)


Clustersのタブボタンを押下すると、Cluster一覧の上記画面に遷移します。

※Create Clusterボタンを押すと、New Cluster画面に遷移していきます。



ちなみに、少し余談になりますが、左隅上にあるボタンをクリックすると下記のWelcome画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817530/09753cd9-3d22-65e7-1a25-135b5cef1213.png)






![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817530/8c6d569b-8c2e-c4d2-a451-b029abcf58c7.png)


上記の画面で任意のクラスタ名を入力し、Databricks Runtime Versionを設定します。Runtime Versionの設定は任意で大丈夫です。

Runtime Versionの中で、MLとかBetaとかの記載があります。MLは（Machine Learning ）の略で機械学習ライブラリが含まれています。Betaはベータ版のことです。やりたいことに合ったクラスタの作成をしていただければと思います。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817530/e614ca54-8343-b1e6-058f-fbabeb0d0969.png)


必要項目を設定したら、Create Clusterボタンを押下すれば、クラスタが作成され、自動的に立ち上がってくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817530/fecfa886-952a-5710-6406-9fc22f218b2b.png)


立ち上がったあと、クラスタ名のところに、緑色でくるくるまわってるのが緑丸になれば、クラスタの立ち上げに成功しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817530/259981dc-7a8e-e2f3-210e-7dc8689b917a.png)



以上がクラスタの作成から立ち上げになります。

Databricks Community Editionでは、立ち上げられるクラスタは1つとなっています。
また、2時間動作がないと、自動的に終了して、再設定する必要があります。


株式会社メソドロジック

川名智士
SQLServerのオブジェクトの付与権限の確認方法


```
--指定したオブジェクトの権限一覧を表示する
SELECT
OBJECT_NAME(major_id) AS オブジェクト
,USER_NAME(grantee_principal_id) AS ユーザー
,permission_name as 権限名
,state_desc as 権限の状態
FROM sys.database_permissions
WHERE major_id = OBJECT_ID('オブジェクトの名前')
```


```
--指定したユーザー（ロール）の権限一覧を表示する
SELECT
USER_NAME(grantee_principal_id) AS ユーザー
,OBJECT_NAME(major_id) AS オブジェクト
,permission_name as 権限名
,state_desc as 権限の状態
FROM sys.database_permissions
WHERE grantee_principal_id = USER_ID('ユーザーの名前かロールの名前')
WindowsのNode.jsのバージョンマネージャー

メモ。

Nodistでやってみたが、JetBrains製品で上手く認識されなかった。
nvm-windowsというのがあり、Googleも推奨してるらしいので、それを入れたら上手く行った。

https://github.com/coreybutler/nvm-windows

### インストール
https://github.com/coreybutler/nvm-windows/releases
ここから、nvm-setup.zipなやつを落としてくる

あとはウィザードに従ってインストール。

### 動作確認
バージョンの確認

```bat
nvm version
```

インストール済みのバージョンの確認、初期では当然ない。

```bat
nvm list
```

インストール出来るバージョンの確認

```bat
nvm list available
```

### nodeのインストール
コマンドプロンプトとかは管理者権限で立ち上げるみたい。

14.15.0のインストール

```bat
nvm install 14.15.0
```

14.15.0を使用する。これをやるとC:\Program Filesにリンクを作ってくれるので、nodeが利用できるようになるみたい。ちなみにインストール時にどこにこれを作るのか聞かれたので、別の場所を指定したらそこになるんだろう。

```bat
nvm use 14.15.0

node -v
```

12.19.0を使用してみる

```bat
nvm install 12.19.0
nvm use 12.19.0
node -v
```
MacデフォルトのカラーピッカーDigital Color Meterの使い方

## 使い方

Spotlightで「digital color meter」を検索して起動。

Digital Color Meterメニューの表示→値を表示→16進にチェック。

色空間で`sRGB`を選択。

マウスポインタを移動し、目的のピクセルを拡大した状態で`Cmd+Shift+C`を押すと`#54C400`という形式でクリップボードにコピーされる。


## 注意事項

`sRGB`を選択しても必ずしも正確な元の値が得られるとは限りません。これは、元のsRGBからディスプレイのカラープロファイルに二重に変換してから、sRGBに戻すためです。丸めエラーが発生する場合があり、わずかにずれます。

詳細は下記ページの「非常に重要な注意事項」の部分を参照:
[ピクセルのRGB値を識別するためのツールは何ですか？](https://qastack.jp/apple/25421/what-tool-exists-to-identify-the-rgb-value-of-a-pixel)


## 色空間

- ネイティブの値: [現在のディスプレイのカラープロファイルに変換された後の値を意味します。](https://qastack.jp/apple/25421/what-tool-exists-to-identify-the-rgb-value-of-a-pixel)
- P3: Appleが開発した色空間
- sRGB: ディスプレイやデジカメで一般的な色空間
- 汎用のRGB: 不明
- Adobe RGB: sRGBよりも緑方向の解像度が高く、緑色の表現力が豊か
- L*a*b*: [L*a*b*色空間では、明度をL*、色相と彩度を示す色度をa*、b*で表します。図6は、L*a*b*色空間色度図です。図からわかるように、a*、b*は、色の方向を示しており、a*は赤方向、-a*は緑方向、そしてb*は黄方向、-b*は青方向を示しています。数値が大きくなるに従って色あざやかになり、中心になるに従ってくすんだ色になります。](https://www.konicaminolta.jp/instruments/knowledge/color/section2/02.html)
openapi-generator で生成された Kotlinコードの Enumでコンパイルエラーが発生したとき

## 概要
openapi-generator でデフォルトの設定のままKotlinコードを生成すると、
生成されたコードでコンパイルエラーが発生する場合があります。

そのようなときは、`enumPropertyNaming` プロパティの設定を変更するというのが解決策のひとつです。

## 詳細
### デフォルトの設定だとコンパイルエラーになる文字列がある

以下のようなスキーマを考えます。
role というフィールドを `User` `Operator` `Admin` の3つのEnumで定義しています。
のちに、この `Operator` が悪さをします。

```yaml
  role:
    type: string
    enum:
      - User
      - Operator
      - Admin
```

上記のスキーマから openapi-generator を使って Kotlin のコードに変換すると、以下のコードが生成されます。
しかし、operator は Kotlin の予約語のため、このコードはコンパイルエラーになってしまいます。

```kotlin
    enum class Role(val value: kotlin.String) {
    
        @JsonProperty("User") user("User"),
    
        @JsonProperty("Operator") operator("Operator"), // ← operator は予約語
    
        @JsonProperty("Admin") admin("Admin");
    
    }
```

## どう対応するか?
対応の1つのアイディアとして、Enumが小文字で `operator` と出力されてしまうのがいけないという考えのもと、
大文字で `OPERATOR` と出力するように openapi-generator の `enumPropertyNaming` プロパティを変えることが挙げられます。

`enumPropertyNaming` に設定できる値は以下のいずれかです。[^1]

- camelCase (default)
- PascalCase
- snake_case
- UPPERCASE
- original

Kotlinの公式ドキュメント[^2]を見ると、Enumは upper case で書かれているため、
自分のケースでは、 `enumPropertyNaming=UPPERCASE` で対応しました。

[^1]: https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/kotlin.md
[^2]: https://kotlinlang.org/docs/reference/enum-classes.html

そうすると以下のようなコードが生成されます。コンパイルエラーは出ません。

```kotlin
    enum class Role(val value: kotlin.String) {
    
        @JsonProperty("User") USER("User"),
    
        @JsonProperty("Operator") OPERATOR("Operator"),
    
        @JsonProperty("Admin") ADMIN("Admin");
    
    }
```

## 深入り希望者へのリンク

事態を詳しく調べたい方に役に立ちそうなリンクを貼っておきます。

- [Kotlin の予約語一覧](https://kotlinlang.org/docs/reference/keyword-reference.html)
- [openapi-generator (Kotlin) で予約語が定義されているファイル](https://github.com/javils/openapi-generator/blob/master/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java#L94)
- [openapi-generator (Kotlin) の予約語を更新したPR](https://github.com/OpenAPITools/openapi-generator/pull/4793)
Jetbot & PyTorch CNN（８）プログラムの実行

#衝突回避プログラムの実行
では実際に各プログラムを使ってJetbotを走らせます。
![data collection.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617683/0348e663-0079-6a14-1286-439be72c2507.png)
「データ収集」、「学習」、「デモ」の順に進めます。
この画面で"add free"または"add blocked"をクリック。それぞれ200枚以上撮影しました。
ではデモの映像をご覧ください。
https://www.youtube.com/watch?v=YzSbHhW5_FM
![CA.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617683/4d6dbd47-cc2a-e166-790f-bc28a871e6d2.png)

#ライントレース プログラムの実行
![data.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617683/a17165ca-f473-cf89-85a0-abfc9cbb399f.png)
こちらも同様に「データ収集」、「学習」、「デモ」の順に進めます。
コントローラからアクセル、ブレーキを操作するより、スライダーの方が作業性がいいので変更、撮影のみコントローラの♯5ボタンで実施。
映像はこちら。
https://www.youtube.com/watch?v=ElMq5QPielI
![RF.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617683/113f57fa-b82b-30cf-e3ef-a6b8e15d824b.png)
スピードUPだ！
https://www.youtube.com/watch?v=eNPJpWeKMG4
![WOT.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617683/ee697bd7-bff4-fe91-4a29-5a5655fc20f5.png)



#ライントレース＋衝突回避プログラムの実行
衝突回避とライントレースのPTHファイルをフォルダにコピーしデモ実行。
映像をどうぞ。
https://www.youtube.com/watch?v=YUo0yv_c1c4
![RF_CA.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617683/387baf18-e0f7-c5e4-ad10-90d10a99acdc.png)

＜おまけ＞
衝突回避動作を停止から左回転に変更。左折やUターンができます。
https://www.youtube.com/watch?v=l2AGvR_SBhQ
![youtube.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617683/9483d039-e3d1-b0ba-154a-939a199547ba.png)
【Oracle】ユーザ作ろうとしたら、ORA-65096: invalid common user or role name って怒られたときの解決法

# 解決法
> 99.9% of the time the error ORA-65096: invalid common user or role name means you are logged into the CDB when you should be logged into a PDB

[stack overflow](https://stackoverflow.com/questions/33330968/error-ora-65096-invalid-common-user-or-role-name-in-oracle)の回答によると、ORA-65096のエラーが出る原因の99.9%がCDBに接続しているかららしい:innocent:
ということで、CDBじゃなくて、PDBに接続してユーザを作る:muscle:

```console:OK
# 今接続しているコンテナ名を確認する(CDBに接続してる状態)
SQL> show con_name;

CON_NAME
------------------------------
CDB$ROOT

# PDB名を調べる
SQL> select pdb_name from cdb_pdbs;

PDB_NAME
--------------------------------------------------------------------------------------------------------------------------------
ORCLPDB1
PDB$SEED

# PDBに接続する
SQL> alter session set container = ORCLPDB1;

Session altered.

# ユーザを作成する。
SQL> create user qiita identified by password default tablespace USERS temporary tablespace TEMP;

User created.

```

```console:NG
# 今接続しているコンテナ名を確認する(CDBに接続してる状態)
SQL> show con_name;

CON_NAME
------------------------------
CDB$ROOT

# CDBに接続してるからユーザ作成しようとすると怒られる。
SQL> create user qiita identified by password default tablespace USERS temporary tablespace TEMP;
create user qiita identified by password default tablespace USERS temporary tablespace TEMP
            *
ERROR at line 1:
ORA-65096: invalid common user or role name
```

# バージョン情報
- Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production Version 19.3.0.0.0

# 参考

- [error: ORA-65096: invalid common user or role name in oracle - Stack Overflow](https://stackoverflow.com/questions/33330968/error-ora-65096-invalid-common-user-or-role-name-in-oracle)
- [スキーマ（ユーザ）作成時に「ORA-65096」～Oracle 12cのアーキテクチャはここが違う～:DBMoto - データベース アクセス ブログ](https://www.climb.co.jp/blog_dbmoto/archives/1272)
- [CDB/PDBへの接続 - 
DBひとりでできるもん](https://xn--w8j8bac3czf5bl7e.com/2018/06/14/cdbpdb%E3%81%B8%E3%81%AE%E6%8E%A5%E7%B6%9A/)
Ruby の Gem で ウエブフレームワーク を検索してみた

# はじめに
気が向いたので、やってみた
#　検索結果
|gem|last|
|:--:|:--:|
|Roda|3.37.0 - October 16, 2020|
|Ruby on Rails|6.0.3.4 - October 07, 2020|
|Scorched|1.0.1 - August 28, 2020|
|Cuba|3.9.3 - August 11, 2020|
|Sinatra|2.1.0 - September 04, 2020|
|Pakyow|1.0.6 - September 03, 2020|
|Rack::App|2.2.3 - June 15, 2020 |
|Padrino|0.15.0 - May 15, 2020 |
|Syro|3.2.0 - February 28, 2020|
|Hanami|2.0.0.alpha1 - January 30, 2019|
|Hobbit|0.6.1 - February 20, 2016|
|Camping|2.1.532 - March 21, 2013|
|Ramaze|2012.12.08 - December 08, 2012|
|Hyperstack|-|

# まとめ
+ いろいろあります

参照したサイト
*[RubyGems.](https://rubygems.org/)*
*[Awesome Ruby : 素晴しい Ruby のライブラリ・ツール・フレームワーク・ソフトウェアの数々](https://qiita.com/hatai/items/62766145f2e24fa1c246#%E3%82%A6%E3%82%A7%E3%83%96%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF)*
cscの作法 その42 dllinject

#概要

cscの作法、調べてみた。
dllinjectやってみた。
pidを指定するタイプやってみた。

#サンプルコード


```
using System;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;

class Test {
	[Flags]
	enum AllocationType {
		MEM_COMMIT = 0x1000,
		MEM_RESERVE = 0x2000,
	}
	[Flags]
	enum MemoryProtection {
		PAGE_EXECUTE_READWRITE = 0x40,
	}
	[Flags]
	enum FreeType {
		MEM_RELEASE = 0x8000,
	}
	[Flags]
	enum DesiredAccess {
		PROCESS_ALL_ACCESS = 0x1fffff,
		PROCESS_QUERY_INFORMATION = 0x400,
		PROCESS_CREATE_THREAD = 0x2,
		PROCESS_VM_OPERATION = 0x8,
		PROCESS_VM_WRITE = 0x20,
	}
	[DllImport("Kernel32.dll")]
	extern static IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
	[DllImport("Kernel32.dll")]
	extern static bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, FreeType dwFreeType);
	[DllImport("Kernel32.dll")]
	extern static IntPtr OpenProcess(DesiredAccess dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
	[DllImport("Kernel32.dll")]
	extern static bool CloseHandle(IntPtr handle);
	[DllImport("kernel32.dll")]
	extern static bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, String lpBuffer, uint nSize, IntPtr lpNumberOfBytesWritten);
	[DllImport("kernel32.dll")]
	extern static IntPtr LoadLibrary(String lpFileName);
	[DllImport("kernel32.dll")]
	extern static IntPtr GetProcAddress(IntPtr hModule, String lpProcName);
	[DllImport("kernel32.dll")]
	extern static IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
	static void Main(string[] args) {
		IntPtr tp,
			kh,
			dr,
			la,
			retval;
		int pid = Convert.ToInt32(args[0]);
		String dllpath = "c:\\ore\\c\\spy.dll";
		uint dllpathLength = (uint) Encoding.GetEncoding("UTF-8").GetByteCount(dllpath);
		tp = OpenProcess(DesiredAccess.PROCESS_ALL_ACCESS, false, (uint) pid);
		dr = VirtualAllocEx(tp, (IntPtr) null, dllpathLength + 1, AllocationType.MEM_COMMIT, MemoryProtection.PAGE_EXECUTE_READWRITE);
		WriteProcessMemory(tp, dr, dllpath, dllpathLength + 1, (IntPtr) null);
		kh = LoadLibrary("kernel32.dll");
		la = GetProcAddress(kh, "LoadLibraryA");
		retval = CreateRemoteThread(tp, (IntPtr) null, 0, la, dr, 0, (IntPtr) null);
		VirtualFreeEx(tp, dr, (uint) (dllpath.Length + 1), FreeType.MEM_RELEASE);
		CloseHandle(tp);
	}
}





```

以上。
githubでブログっぽいものgist

githubにあるgistというサービスに勉強の進捗を書こうと考えています。

<a href="https://qiita.com/hkusu/items/18cbe582abb9d3172019">他の方のgistの記事<a>

ファイル名を .md　にするだけで、似たようなことができたので、


キータで書いているのも悪くないのですが、
正直、「マークダウン」でかつ「シンタックスハイライトがある」かつ
「インターネットに残るもの」ということで、
<a href="https://gist.github.com/yottodest021">gist</a>に移転しようと思います。

見出しが右に表示されなくなるのは面倒くさいですが、リンクつければいいだけなので、大丈夫。

キータでは、
「詰まった際のノウハウ」、「お役立ちを発信する」、「作品の発表をする」
などといった質の高い情報発信をする際に使い分けができればいいなと思います。

そのうち時間があったら、gist使い方をかければいいなと思います。

今日の書きかけの記事を書き終わったら、gistに書きます。
音声合成で しゃべらせる VBS

とりあえず しゃべらせる。
以下のファイルをダブルクリックで実行。
(Windows10, Window7 等)

talk.vbs

```visualbasic
Dim tts
Set tts=CreateObject("SAPI.spVoice")
'tts.Rate = 2
'tts.Volume = 100
tts.Speak "生麦　生米 生卵"
```

しゃべらない？　なら、
マイクロソフトスピーチプラットフォームをインストール。

http://www.microsoft.com/en-us/download/details.aspx?id=27225

　x86_SpeechPlatformRuntime￥SpeechPlatformRuntime.msi
　　または
　x64_SpeechPlatformRuntime￥SpeechPlatformRuntime.msi

日本語を追加

http://www.microsoft.com/en-us/download/details.aspx?id=27224

　MSSpeech_SR_ja-JP_TELE.msi
　MSSpeech_TTS_ja-JP_Haruka.msi
音声合成で しゃべらせる JavaScript

とりあえず しゃべらせる。
以下のファイルをダブルクリックで実行。
(Windows10, Window7 等)

talk.js

```javascript
var tts = WScript.CreateObject("SAPI.spVoice");
tts.Speak("生麦　生米　生卵");
```

しゃべらない？　なら、
マイクロソフトスピーチプラットフォームをインストール。

http://www.microsoft.com/en-us/download/details.aspx?id=27225 

　x86_SpeechPlatformRuntime￥SpeechPlatformRuntime.msi
　　または
　x64_SpeechPlatformRuntime￥SpeechPlatformRuntime.msi


日本語を追加

http://www.microsoft.com/en-us/download/details.aspx?id=27224

　MSSpeech_SR_ja-JP_TELE.msi
　MSSpeech_TTS_ja-JP_Haruka.msi
Botpressで作るチャットボットにAWSインフラエンジニアの仕事をさせよう

忙しい日々が続いていて、自分の部下が欲しいーー！でも、教えるのは面倒。。。それ以前に人がいない。。。そう感じた時に自分の仕事をボットにやらせればいいんじゃないか？！と思いつき、開発？育成？することにしました。

# 完成イメージ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115627/5244e06f-e32b-229b-95f9-69560bc78089.gif"  width="600">
ボットに処理を依頼するとボットがansibleでsarコマンドなどを対象サーバー上で実行し、その実行結果をチャットに表示します

# 前回書いた記事
https://qiita.com/drafts/e87634e7bef42ed2dfe1/

# 環境
EC2(AmazonLinux2)
ALB
Nginx
Botpress

# 参考リンク
https://botpress.io/

# Botpressインストール

```
mkdir botpress
wget https://s3.amazonaws.com/botpress-binaries/botpress-v12_10_7-linux-x64.zip
unzip botpress-v12_10_7-linux-x64.zip
./bp
```

■エラーになる時
※AmazonLinux2で動作しなかったので以下対応

```
Error starting botpress
Error: Could not require NativeExtension "fasttext.node" for OS "linux raspbian". Tried the following paths: [ /mnt/xxxxx/xxxxxxx/botpress/bindings/linux/default/fasttext.node ]
```
↑のエラーが出る場合、bindings/linux/にバイナリコンパイル済のファイルがあるのでそれをraspbianのところと合わせる
cp -a bindings/linux/centos_7_5 bindings/linux/raspbian

fasttextは別のオープンソースのようで別途コンパイルが必要みたい

# Botpress設定
■Botpressをバックグラウンド実行する

・pm2インストール
npm install pm2 -g

・バックグラウンド実行
pm2 start './bp start -p'

■自分のWebサイトにbotpressチャットを表示させる
ヘッド部に↓

```
<script src="/assets/modules/channel-web/object_assign.js"></script>
<script src="/assets/modules/channel-web/inject.js"></script>
```

ボディ部に↓

```
<script>
      let lastConfig = {
      host: 'https://xxx.com/',
        botId: 'test1'
      }
      window.botpressWebChat.init(lastConfig)
</script>
```

# フロー図の作成
・CHOICEノード
↓この選択肢が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115627/701ed448-d58d-545f-2869-ed9baae1d557.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115627/d3405e3d-aa1b-8863-e4d7-75de2533d9a6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115627/bcb0affb-82a6-6296-6efc-afc99543b1cb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115627/cee5cc08-f50e-385f-4198-f7f019826d84.png)
選択した値によって分岐させる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115627/25b13cb1-f84e-ec09-9536-79c2d88a0dfd.png)

# FAQ
■Code-Actionsで登録したjsファイルがNodeから呼び出せない、または呼び出していたものが呼び出せなくなっている場合
どうもこのあたりにバグがある模様
~~一度、エクスポートして再度、ボットをインポート作成しなおす~~
bpを再起動（オススメ）