OmniAICreator/Qiita-1.07M huggingface dataset:
local環境のNode-REDにngrokが頼もしすぎる

## 概要
[Node-RED](https://nodered.org/)の動作環境は[IBM Cloud](https://cloud.ibm.com/login)が有名ですが、もちろんローカルPCでも使用することが出来ます。しかし、その場合localhostで動作する為、LANの外からアクセスをすることが出来ず、Webhookなどが使用できません。

今回は、この悩みを解消してくれた『ngrok』というツールがとても良かったのでご紹介したいと思います。
### 動作環境
| システム | バージョン |
|:-----------|------------:|
| macOS Catalina | 10.15.6 |
| node-red | 1.1.2 |
| ngrok | 2.3.35 |


Node-REDをローカル環境で動作させる場合、いくつかの選択肢があります。([公式を参照](https://nodered.jp/docs/getting-started/local))
今回はnpmを用いて、Node-REDをインストールした環境と仮定します。

### ngrok
ngrokとは、localhostのサーバーに対して、外部からもアクセスすることのできるパブリックURLを、ngrok起動ごとに割り当てることができます。これによって、デプロイせずにWebサイトのデモを行うことや、開発環境下でWebhookを使用することができるようになります。


##使用方法
### 事前準備
①[公式サイト](https://ngrok.com/)より、アカウントを作成します。
現在はGoogleとGithubでのシングルサインオンに対応しているので、そちらのアカウントからでもログインすることが出来ます。

②ログイン後、ngrokをダウンロードし、zipファイルを解凍。
※実行ファイルをホームディレクトリに移動させておきます。

③公式サイトの「Setup&Installation」> 「2. Connect your account」にある以下のようなコマンドを打つことで、新たに隠しフォルダとymlファイルが生成され、作成したアカウント情報との紐付けが行われます。

```terminal
./ngrok authtoken  { 認証トークン }
```
※`./ngrok`  の部分は実行ファイルが存在しているパスを示しているので、ホームディレクトリ直下に置かない場合は任意のパスを記述します。

### 実行
npmでNode-REDをインストールした場合、デフォルトで使用しているポート番号は1880なので以下のようなコマンドで起動することが出来ます。

```terminal
./ngrok http 1880
```

ターミナルに表示される部分を一部抜粋、、

```terminal
Forwarding           http://〇〇〇〇.ngrok.io -> http://localhost:1880
Forwarding           https://〇〇〇〇.ngrok.io -> http://localhost:1880
```

ブラウザから[http://〇〇〇〇.ngrok.io]()にアクセスすると、Node-REDエディタに移ることが出来ます。
以降は[http://〇〇〇〇.ngrok.io]()をエンドポイントとして、Webhookなどを使用することができます。
Windowsで快適なPython 3 (Anaconda)開発環境を作る

# 入れるもの
Anaconda(Python 3)をインストールします。

# anacondaのインストール手順

## ダウンロード
[公式のサイトへアクセスします。](https://www.anaconda.com/products/individual)
アクセスした後、下の図のところまでスクロールしてください。そのあと、黄色で塗った"64-Bit Graphical Installer "[^4]をクリック[^5]してください。
![1a.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206651/47ff1f24-aa0e-2721-34c1-d375659ab117.png)
これでダウンロードは完了です。

## インストール
**"Anaconda3-ほにゃらら-Windows-x86_64"** をクリックしてください。
![2a.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206651/ecfaa375-4aa6-a758-4841-6a90fe6a9df9.png)
ダブルクリックするとこのような画面が出てきます。
![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206651/3af21616-0483-9675-2b09-a3c10a178926.png)

クリックすると、ソフトウェア利用許諾契約[^6]が出てきます。良く読みましょう。
**進む場合は"I Agree"を押してください。**
![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206651/a3902eb4-2ddf-07fd-6391-6327b1347ca6.png)

**"Next >"を押してください。**
![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206651/6ce3aca8-219c-cc2a-7851-56efe07f519e.png)

後、容量が結構必要なので注意が必要です。
**"Next >"を押してください。**
![6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206651/7ecdcacd-bed6-1d2b-d906-2b53ab03c37a.png)

**"Add Anaconda3 to my PATH environment variable"は非推奨ですが、初めての人はこちらをチェックすることをおすすめします。**[^8]
"Register Anaconda3 as my default Python 3.8"はそのままで大丈夫だと思います。
**"Next >"を押してください。**
私の環境ではインストールに5分くらい時間がかかりました。
![8.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206651/3f83e531-6691-a803-0ddb-f9305e62c062.png)


こちらの画面がでればインストール完了です。
**"Next >"を押してください。**
![9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206651/3b5eadc3-544b-8369-cb2f-f3b0f73474ae.png)


二つのものはチェックを入れていると閉じたときブラウザでWEBページが開きます。面倒なら外してもらって構いません。
**"Finish"を押してください。**
![10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206651/96eb774c-30d2-2c99-c29e-87d9f2feb5fb.png)


# PATHを通す

さて、Anacondaのインストールは完了しました。
早速、コマンドプロンプト![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206651/1e2f3943-6523-2548-dad0-cc25c3b6bb31.png)を起動させて、

```
python --version
```

と入力してみます。
上手くいった場合、

```
Python 3.8.3
```

と出力されます。
失敗した場合、

```
'python' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
```

とでるか、Microsoft Storeのページが出てきてPythonのインストールをお勧めされてしまいます。
これの場合、PATHが通っていないかインストールに失敗している可能性があります。
"Add Anaconda3 to my PATH environment variable"にチェックを入れてAnacondaを再インストールしてみてください。

# 終わりに

お疲れ様でした。



[^1]: 正確には言語処理系と言いますが、とりあえず気にしないください。
[^2]: 逆に効率的な行列計算や科学計算やニューラルネットワークを自分で実装できる人はこの記事読む必要ありません。
[^3]: 同じバージョンでも複数用意できますのでご安心ください。
[^4]: 古いパソコンだと32bit版しか動かない場合がありますが、現在のパソコンなら原則大丈夫だと思います。個人的には32bitのパソコンは性能的にPython使うのは厳しいと思いますが、下の"32-Bit Graphical Installer "をクリックすると32bit版をダウンロードできます。
[^5]: ファイルサイズはバージョンアップによって変更されている場合がありますが、気にしなくて結構です。テザリング中などの場合は通信量を気をつけてください。
[^6]: この名称であっているか不安です。詳しい方是非、コメント欄でお教えください。
[^7]: BSD Licenseなようなので日本語記事の二次情報を見ても良いかもしれません。ただ、BSD Licenseにもいくつか種類があるのと、二次情報は信憑性が疑わしい場合があります。
[^8]: このオプションを選ぶと事前に入れた今回インストールしないAnaconda以外のPythonが壊れてしまったり、今後にインストールするPythonが上手くいかなかったりする可能性があるようです。**ですが、チェックを入れないと自力でAnacondaのPATHを追加しなければならず大変だと思います。**
MongoDB インストール (Ubuntu 18 LTS)

##　今回やったこと
- MongoDB（NoSQL）をインストール。
MongoDB CommunityのURLに従う[「Install MongoDB Community Edition on Ubuntu」](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/)を参照。

- Pythonからの実行 pymongo
Anaconda環境下JupyterNotebookでの実行
## 環境

- OS Ubuntu 18.04.01 LTS
- MongoDB 4.4 (2020/9月現在最新）
- Anaconda Navigator 19.1.2
- Jupyter Notebook 6.0.3
- python 3.7

## 手順

1.公開キーのインポート

```
wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -
```
ここでエラーになる場合は__gnupg__をインストールするように。とのこと。

2.リストファイルの作成

```
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list
```

3. ローカルパッケージのアップデート

```
sudo apt-get update
```
4.MongoDBのインストール

```
sudo apt-get install -y mongodb-org
```
defaultの備考
データディレクトリ  /var/lib/mongodb
ログディレクトリ　  /var/log/mongodb
コンフィグファイル  /etc/mongod.conf

5. Init systemの確認
Linuxによってsystemdを使うか、system V initを使っているかで以下の作業が変わる。自分の設定を確認する。

```
ps --no-headers -o comm 1

> systemd 私の場合の結果
```
## MongoDBを開始する
```
sudo systemctl start mongod
```
#### チェック１　作動したかLogファイルを確認する
```
sudo cat /var/log/mongodb/mongod.log
```
#### チェック２　もしくはステータスの確認
```
sudo systemctl status mongod
```
## PyMongo インストール
Anaconda上のでterminalを開く

```
conda install pymongo  
# pip installがドキュメントには書かれているが、condaにて mongo-3.11.0をインストールした
```
ちょっと自分のメモ書き

## AWS
基本的にLinuxコマンド

## sudo vim とは
super user do
つまり管理者権限を持った人間がやりますよ
という意味のLinuxコマンド

vimはvimEditor
使い方はLinuxとはまた別

## 環境変数
.zshrc 内に記述してconfig/secrets.ymlで呼び出す。
それによって公開を防ぐ。

※ただしrailsの5.2以降はcredentials.ymlを使用する。

## rails でキャッシュのクリア
ブラウザでクリア
spring stopでクリア
webpackerでクリア
railsの再起動でクリア
vs-codeの再起動でクリア

※Spring は Railsの preloaderGEM
※webpackerはjavascript環境
機械学習のEDAで使ったもの

*これは自分用メモです

今までに使用したコードのメモ書きです
##intersection

```python:intersection
a=['A','B','c']
b=['B']
c=a.intersection(b)
```

配列aと配列bの積集合を出力する関数
ジャッカード係数の計算などで使いました。


##stopword

```python:stopword
from nltk.corpus import stopwords
stop_words = stopwords.words('english')
print(stop_words)
```

英語のstopwordを取得します。
Tweetの感情予測で使用しました。
**stopwordとは**
自然言語処理で除外される一般的な単語

---
treemap

```python:treemap
from ploty import graph_objs as go
import plotly.express as px

fig=px.treemap(list,value='common',title='Tree of XXX')
```

面積グラフです。
データビジュアライズで色々使えそうです。

---
# 自然言語処理

トークン化
通常のテキスト文字列を欲しい単語のリストに変換するプロセス
単語を見つけやすくなる

---
ステム処理
[run][running][ran]
など同じ意味の単語を[run]などの一般系に戻す処理

---
ストップワードの除去

***
今後も勉強する中で調べたものをメモ書きしていきます
Python組み込み関数〜divmod~ 割り算の商と余りを同時に取得しよう

#はじめに
今回の記事では、Pythonの「divmod関数」について取り上げます。
「divmod関数」は、割り算した時の商と余りを一気に取得できる便利なものです。
「divmod」関数を使えるようになって、Pythonの知識を深めていきましょう。

#通常の割り算での商と余り
Pythonで通常の割り算では、商を求めるときは「/」、余りを求めるときは「%」を使用します。

```python
#商
12 / 4
>>>3.0
```

```python
#商
12 / 5
>>>2.4
```

```python
#小数点を切り捨て
12 // 5
>>>2
```

```python
#余り
12 % 4
>>> 0
```

```python
#余り
12 % 5
>>> 2
```


#divmod関数
では早速「divmod関数」を使用していきます。
まずはコードを見て確認していきましょう。

```python
quotient, remainder = divmod(12, 5)
print(quotient)   #2
print(remainder)  #2
```
見てわかるように、変数を２つ用意し、１つ目の変数には商が、２つ目の変数には余りが入ります 
そしてポイントとなるのが、１つ目の変数には、「小数点を切り捨てにした状態の商」が入ります。
つまり、「//」を使用した時と同じということです。  

次に変数１つで受け取るとどのようになるのか確認しましょう。

```python
tuple = divmod(12, 5)
print(tuple)   #(2, 2)
```
このようにタプルとして受け取れます。
取り出したいときは、

```python
print(tuple[0], tuple[1])
#2 2
```
とすれば取り出せます。
#比較
最後に普通に商と余りを出すときと、「divmod関数」を使った時とを比較してみましょう。

```python
#普通
quotient = 12 / 5
remainder = 12 % 5
print(quotient)   #2.4
print(remainder)  #2
```

```python
#divmod関数
quotient, remainder = divmod(12 / 5)
print(quotient)   #2
print(remainder)  #2
```
たった１行ですが短くなっているのがわかります。
たった１行でも短くなるなら使わない手はないので、積極的に使っていきましょう。

#最後に
今回の記事では、Pythonの「divmod関数」について取り上げました。
今後も役立つモジュールや組み込み関数なども記事にしていくので、よかったらみて行ってください。
Versioning した GCS でアクティブ&非アクティブ両方に condition による action をかける方法

## 方法

```
gsutil versioning get gs://【EXAMPLE】/
gsutil versioning set on gs://【EXAMPLE】/
gsutil lifecycle get gs://【EXAMPLE】
```

```
vim life.json
{
  "rule":
  [
    {
      "action": {"type": "Delete"},
      "condition": {"age": 1}
    }
  ]
}
```

```
gsutil lifecycle set ./life.json gs://【EXAMPLE】
```

```
gsutil ls -a gs://【EXAMPLE】/
```

## 解説

| isLive の値 | 挙動 |
| --- | --- |
| true | 現行バージョンが対象 |
| false | 非現行バージョンが対象 |
| 無し | 全てのオブジェクトが対象 |

## Appendix1
https://cloud.google.com/storage/docs/lifecycle#islive

## Appendix2

ちなみにこれでも OK

```
{
  "rule": [
    {
      "action": {
        "type": "Delete"
      },
      "condition": {
        "age": 1,
        "isLive": false
      }
    },
    {
      "action": {
        "type": "Delete"
      },
      "condition": {
        "age": 1,
        "isLive": true
      }
    }
  ]
}
```
WEBカメラ取り込みVer3

前回作成した物。
[WEBカメラ取り込みVer2](https://qiita.com/bobrock/items/50a1f0b8324b43c30614)

前回はGPIOを使用したプログラム。

今回は撮影枚数を指定しての撮影プログラム。

基本構成は前回と変わらず。

##ライブラリ
```python:cap_save_prg.py
import cv2
import os,os.path
from pathlib import Path
import sys
from datetime import datetime
import time
```
基本構成に`pathlib`を追加したくらい。

この辺りは色々と調べながらなので、結構適当です。

##保存先とファイル名の定義
```python:cap_save_prg.py
save_dir_path = '保存先'
filename = 'ファイル名'
```
お好みの場所で構いません。
最近はデスクトップ上にフォルダを作成してその中でプログラム保存や
撮影画像の保存を行う様にしています。

##ディレクトリの作成
```python:cap_save_prg.py
os.makedirs(save_dir_path,exist_ok=True)
base_path = os.path.join(save_dir_path,filename)
datename = datetime.now().strftime('%m%d%H%M')
```
いつも通りとなっています。

##使用デバイスの定義
```python:cap_save_prg.py
device_id = 0
width = 640
height = 480
fps = 30

cap = cv2.VideoCapture(device_id)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
cap.set(cv2.CAP_PROP_FPS, fps)
```
今回は調べている中でOpencvの機能を設定が出来る下りの記述を見つけたので
試しに使ってみようと思い、盛った記述になっています。

まぁ撮影するだけなら`cv2.VideoCapture()`で問題ないです。

##画像撮影
```python:cap_save_prg.py
n = 0
while True:
    ret,frame = cap.read()
    cv2.imshow(filename,frame)
    key = cv2.waitKey(1) & 0xFF 

    cv2.imwrite((base_path + datename +'_'+ str(n) + ".png"),frame)
    pathl,dirsl,filesl = next(os.walk(save_dir_path))
    file_count = len(filesl)
    print(file_count)
    time.sleep(0.2)
    cap.release
    n += 1

    if file_count == 100:
        break
```
今回はプログラムスタートと同時に撮影がスタート
保存先のディレクトリ内ファイル数をカウントする様にしています。

設定値に到達でプログラムストップとなります。

本当なら`cv2.imwrite`の前に`if key == ord('s'):`を入れてキーボードを押したら
撮影スタートにしたかったんですが
`NameError:name　'file_count' is not defined`が発生。

色々と調べたけど、解消出来なかったので一旦ヨシとしました。

##まとめ
一つのプログラムであれもこれもしようとしてしまうので私の頭脳では対処しきれず知恵熱発生…
作った物を１つずつ改良していくしかないなぁ~と思い
まぁショボい物をアップして悶えながらやってます。

以上です。
メモ: Jupyter Lab に gspreadとoauth2clientを入れる方法

![jupyter.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/61996d4f-2b8d-df94-b8cb-c1128f0a5274.png)

```Dockerfile:Dockerfile
FROM ubuntu:20.04

RUN apt update \
 && apt install -y sudo wget vim curl gawk make gcc \
 && apt clean

RUN wget -q "https://repo.continuum.io/archive/Anaconda3-2019.03-Linux-x86_64.sh" \
  && sh ./Anaconda3-2019.03-Linux-x86_64.sh -b \
  && rm -f Anaconda3-2019.03-Linux-x86_64.sh \
  && curl -sL "https://deb.nodesource.com/setup_10.x" | bash -
RUN apt install -y nodejs \
  && apt clean

ENV PATH=$PATH:/root/anaconda3/bin

RUN pip install gspread \
 && pip install oauth2client

WORKDIR /workspace
VOLUME /workspace
EXPOSE 8888

CMD ["jupyter-lab", "--ip=0.0.0.0","--port=8888" ,"--no-browser", "--allow-root", "--LabApp.token=''"]
```

```sh:ビルド
docker build . -t jupyter
```

```sh:起動
docker run -it --rm -p 8888:8888 -v $(pwd):/workspace jupyter
```

* http://localhost:8888

にアクセス
ASP.NET Core の IHttpClientFactory を使ったときに直接 HttpClient を DI したら何が渡されてくるのか

[IHttpClientFactory のドキュメント](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1)を見ると IHttpClientFactory を受け取って CreateClient をするか、型指定されたクライアント機能を使って HttpClient を受け取るかという方法が書いてあるのですが、型指定されていない普通のクラスで HttpClient を DI してもらったらどうなるのか？というのが明示的に書いてないようなので調べてみました。（書いてあったらごめんなさい）

答えは以下のコードにありました。

https://github.com/dotnet/runtime/blob/254ef0f7f7f429ec238735fe6132805e3c38a19f/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs#L59

IServiceCollection に対して AddHttpClient をすると、内部で HttpClient も登録されていて IHttpClientFactory の CreateClient(string.Empty) をした結果のインスタンスがわたってくるみたいです。

```csharp:HttpClientFactoryServiceCollectionExtensions.cs
// Register default client as HttpClient
services.TryAddTransient(s =>
{
    return s.GetRequiredService<IHttpClientFactory>().CreateClient(string.Empty);
});
```

なので IHttpClientFactory を受け取って CreateClient するだけなら直接 HttpClient を受け取るようにしてしまってもよさそうですね。

ふぅ、すっきり。
[Android]Retrofit + OkHttp + MoshiでGithub APIを使う

AndroidでAPIを実装する時の手法をまとめました。

## ざっくり説明

- アーキテクチャはシンプルなAndroid MVVM
- API実装には`Retrofit` `OkHttp` `Moshi`を使用
- 言語はKotlin
- Github Search APIでリポジトリを検索

## ソースコード 
こちらに置きました。
https://github.com/usk-lab/AndroidGithubApiSample

## 実装画面

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297014/23768f2c-89a7-0bfe-1dfe-04f7d60c0c58.png"/>
![Screenshot_20200908-144710.png]()

単純に検索文字を打ち込み、検索結果を表示します。

## API部分の実装

- GithubInterface：APIの定義
- GithubRepository：API処理の実行
- GithubRetrofitProvider：Github用にRetrofitを初期化しGithubRepositoryに提供する
- SearchResponse：レスポンスの定義

### APIの定義

```GithubInterface.kt
interface GithubInterface {

    @GET("/search/repositories")
    fun getSearchRepositories(@Query("q") query: String) : Call<SearchResponse>

}
```

### 検索結果の処理

```MyViewModel.kt
    //検索結果
    private var _searchResult: MutableLiveData<Result<SearchResponse>> = MutableLiveData()
    val searchResult: LiveData<Result<SearchResponse>> get() = _searchResult
    ....
    //リポジトリを検索
    fun searchRepository(query: String) {
        repository.searchRepository(query).also { response ->
            if (response.isSuccessful) {
                this._searchResult.postValue(Result.success(response.body()!!))
            } else {
                this._searchResult.postValue(Result.failure(Throwable(response.errorBody()!!.toString())))
            }
        }
    }
```

GithubRepositoryで返却される型は`Response<***>`ですが、扱いやすく`Result<***>`に変換しています。
また、`LiveData`を使い、情報更新を通知しています。

### 検索結果の表示

```MainActivity.kt
    private lateinit var viewModel: MyViewModel
    private lateinit var adapter: ArrayAdapter<String>

    ....

        viewModel.searchResult.observeForever { result ->
            result.onSuccess { response ->
                this.adapter.clear()
                this.adapter.addAll(response.items.map { it.fullName })
                this.adapter.notifyDataSetChanged()
            }
            result.onFailure {
                Timber.e(it.toString())
            }
        }
```

検索結果を`observeForever`で受け取っています。
onSuccessの場合は、adapterを更新します。

## 参考

- [MVVM](https://developer.android.com/jetpack/docs/guide?hl=ja)
- https://qiita.com/yoppie_x/items/bbc0ca7a4c8a4b29e141
- https://qiita.com/kuluna/items/59fbc84dd1e33c6d8d1b
ロードバランサ配下のサーバにhttpsリダイレクトするとループする問題を解決

通常、http→httpsのリダイレクトはhtaccessなりapacheのconfなりでこう書く。

```apache
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
```

しかしLB配下にサーバが居ると無限ループが発生する。
こんな感じだろうか（ちょっと自信ないけど）

LB(http)→サーバ(httpなのでリダイレクト→LBへ)→LB(http)→サーバ(httpなのでry


```apache
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteCond %{HTTP:X-Forwarded-Proto} !=https #←こいつ追記
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
```

これで解決。
**おわり。**
WordPress 決済プラグイン導入

WordPressでクラウドファンディングサービスを構築し、決済プラグインを導入しました。
その試行錯誤です。

「物語を共有するクラウドファンディング」[mamenoki](https://www.chuo-system.co.jp/mamenoki/ "mamenoki")

##まず、WP Attractive Donations Systemを導入（購入）しました。
カッコイイのですが、
https://codecanyon.net/item/wp-attractive-donations-system-easy-stripe-paypal-donations/16982796
ドルなら良いかもしれないけど、これを１円単位で合わせるのは、現実的ではありません。
それに、違うプラグインですが、
https://liapoc.com/stripe-100.html
と同じ現象が起きました。
Stripeに送信すると、￥1 ⇒ ￥100になる、ドル使用が前提だから？ 
/wp-content/plugins/WP_AttractiveDonationsSystem/includes/ads-core.php
`$amount *= 100;` ⇒ `$amount *= 1;`で解決しましたが、

* Steps of the progress bar :の下限額を99円以下にすると機能しない
* ドル単位にすると、逆に1/100になる

これは厳しい…
（Stripeのアカウントを作って、会社の口座をリンクして、テストまで出来た、のみが成果）

##なので、WP Full Stripe (Premium)を導入（購入）しました。
https://paymentsplugin.com/
これは完全に年単位のサブスクなので、注意しないと、永遠に使用料を引き落とされます（たぶん）。

https://yuyauver98.me/wpfullstripe-translation/
を参考に日本語化も行いました。


**物語を共有するクラウドファンディング**
<a href="https://www.chuo-system.co.jp/mamenoki/"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458322/831e74df-187b-7e31-daf9-f5e99c733a6b.png" width=50%></a>
No suitable application records were foundの解決策


## はじめに

AppStoreへipaファイルをアップロードする際に普段はエクスポートして、
AppStoreConnectの申請ページでアップしていましたが、

今回はXcodeのOrganizerでそのままUploadすることにしました。

![20200814171835.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701264/f651d7df-8e9f-bb63-60dd-5c43f614c7b8.png)



## しかしエラーが...

しかし以下のようなエラーが出ました。

> No suitable application records were found. Verify your bundle identifier ‘xxxx’ is correct. 


そんなこんなで調べると解決策の載ったページがありました。

## 原因と解決策

原因はAppStoreConnectでの登録が必要だから。
基本的にはAppStoreConnectで登録をしてからXcodeでArchive→Validateするようにした方が良いようです。

ということで、AppStoreConnectで新規アプリを作成し、該当のバンドルIDを設定して保存すれば、再度Validateすることで通りました。

![20200814172215.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701264/c72b7ea0-419b-d330-086b-7595aabb65d1.png)




参考サイト:
[https://unity-yuji.xyz/no-suitable-application-records-were-found-verify-your-bundle-identifier-is-correct/]
ロジスティック回帰を用いた予測

###　JGSSデータを使って機械学習の勉強をしました。
(大学で課題として出したものを少し書き換えました。)

データ：[JGSS](http://jgss.daishodai.ac.jp/data/dat_top.html)
＊学術利用のみが可能らしいです

---
###テーマ
大きなテーマとして結婚生活にフォーカスを当てました
[先行研究](https://nfrj.org/nfrjs01-2005_pdf/nfrjs01-2005kato1.pdf)として挙げられていた離婚の要因とされているものを変数としてロジスティック回帰を行いました。
以下がコードです


```python:title
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

y=data['domarry']
features=['ageb','sexa','szttlsta','incsp','incself','incpar','chiled','op5schpf','agegrd',]
X=data[features]
X_train, X_test, Y_train, Y_test = train_test_split(X, y, test_size = 0.2, random_state = 0) 

lr = LogisticRegression() 
lr.fit(X_train, Y_train)
```

いくつかの変数は連続値であったためワンホットエンコーディングや離散値に直しています。
上記のコードでは精度が80％であり、そこそこの精度でした。
普段はKaggleできれいで要素も少ないデータで勉強していましたが、今回JGSSのデータはとても要素が多く、要素選びが大変でした。。。

---

##補足
この回帰の前にいろいろ処理やカイ2乗検定などをしているので
今後追記していきたいと思います。
kabuステーション®APIのWebsocketをPythonで受ける

- '20.10.14 ライブラリをアップデートし、より簡易な方法で受けられるようになった。
 
→ [kabuステーション®API - PUSH API用にPythonラッパーをアップデートした](https://qiita.com/shirasublue/items/f51986f39dd8a3bf8310)

# 概要

[前回](https://qiita.com/shirasublue/items/914e1d62d8308623b56b)に引き続き、auカブコム証券が個人に提供するkabuステーションAPIをPythonから利用する。
今回は、銘柄のWebsocketによる配信をPythonで受ける。また同時に、銘柄の登録、登録解除、登録全解除のコードも紹介する。

# 環境

- Windows 10
- Python 3.8.5 ( Microsoft Store からインストール )

# 追加パッケージ

- websockets
- requests
- pyyaml

# コード

### 銘柄登録

```python
import json
import requests
import yaml

# ---

def get_token():
    with open('auth.yaml', 'r') as yml:
        auth = yaml.safe_load(yml)

    url = 'http://localhost:18080/kabusapi/token'
    headers = {'content-type': 'application/json'}
    payload = json.dumps(
        {'APIPassword': auth['PASS'],}
        ).encode('utf8')

    response = requests.post(url, data=payload, headers=headers)

    return json.loads(response.text)['Token']

# ---

token = get_token()

EXCHANGES = {
    1: '東証',
    3: '名証',
    5: '福証',
    6: '札証',
}

payload = json.dumps({
    'Symbols': [
        {'Symbol': 8306 ,'Exchange': 1},  # MUFG
        {'Symbol': 9433 ,'Exchange': 1},  # KDDI
        # ... 50件まで登録可
    ],}).encode('utf8')

url = 'http://localhost:18080/kabusapi/register'
headers = {'Content-Type': 'application/json', 'X-API-KEY': token,}
response = requests.put(url, payload, headers=headers)

regist_list = json.loads(response.text)

print('配信登録銘柄')
for regist in regist_list['RegistList']:
    print("{} {}".format(
        regist['Symbol'],
        EXCHANGES[regist['Exchange']]))

```

### 銘柄登録解除

URLの変更のみで対応する。表示部は流用可能である。

```python
url = 'http://localhost:18080/kabusapi/unregister'
```

### 全登録銘柄解除

`payload` が不要となる。

```python
url = 'http://localhost:18080/kabusapi/unregister/all'
headers = {'Content-Type': 'application/json', 'X-API-KEY': token,}
response = requests.put(url, headers=headers)
```

### 配信表示

登録した銘柄の配信を受け続ける。Ctrl+Cで終了する。
`json.loads` する `response` に `.text` がつかないので注意のこと。

```python
import asyncio
import json
import websockets

# ---

async def stream():
    uri = 'ws://localhost:18080/kabusapi/websocket'

    async with websockets.connect(uri, ping_timeout=None) as ws:
        while not ws.closed:
            response = await ws.recv()
            board = json.loads(response)
            print("{} {} {}".format(
                board['Symbol'],
                board['SymbolName'],
                board['CurrentPrice'],
            ))

loop = asyncio.get_event_loop()
loop.create_task(stream())
try:
    loop.run_forever()
except KeyboardInterrupt:
    exit()
```

なお、サーバ側がハートビート未実装のため `websockets.connect` に `ping_timeout=None` の引数が必要である。

【要望】WebSocket のping/pong対応
　　Issue#8 https://github.com/kabucom/kabusapi/issues/8

# 関連記事

次回：[kabuステーション®API - REST API用のPythonラッパーをつくってみた](https://qiita.com/shirasublue/items/16ff9d1fea54b0ef648e)
前回：[kabuステーション®APIをPythonから使う](https://qiita.com/shirasublue/items/914e1d62d8308623b56b)
番外編：[localhostのみアクセスできるサービスをnginxで中継する](https://qiita.com/shirasublue/items/6dbb1ddb1c516c5f4636)
HTML-PHP-post

<h2>同一ページ内で2つ以上の送信ボタンの区別<h/2>
<h6>自身の振り返りようです。</h6>

```html
<!-- html -->
<form method="post">
    <label>苗字：<input type="text" size="10" name="fname"></label>
    <input type="submit" value="送信">
</form>

<form method="post">
    <label>名前：<input type="text" size="10" name="name"></label>
    <input type="submit" value="送信">
</form>
```
```php
<?php
if($_SERVER['REQUEST_METHOD'] === 'POST'){ 
        if(isset($_POST['fname']) === TRUE){
            $btn=($_POST['fname']);
        }
        if(isset($_POST['name']) === TRUE){
            $btn=($_POST['name']);
        }
}
?>
```
何らかの関係で送信ボタンを分けて送りたい場合、このままだとどちらかのボタンを押しても同時に両方の内容が送信されてしまう。
それぞれ個別で送信できるようにするためには<br>

```html
<!-- html -->
<form method="post">
    <label>苗字：<input type="text" size="10" name="fname"></label>
    <button type="submit" name="btn" value="insert">送信</button>
</form>

<form method="post">
    <label>名前：<input type="text" size="10" name="name"></label>
    <button type="submit" name="btn" value="updata">送信</button>
</form>
```

```php
<?php
if(isset($_POST['btn']) === TRUE){
            $btn=($_POST['btn']);
        }
        if($btn === 'insert'){
            if(isset($_POST['fname']) === TRUE){
                $fname=($_POST['fname']);
            }
        if($btn === 'updata'){
            if(isset($_POST['name']) === TRUE){
                $name=($_POST['name']);
            }
?>
```
WebRTC の end to end の暗号化について調べてみた

# 概要

WebRTC についてググると、簡単な tutorial や NAT を越える仕組みについての簡単な説明などは沢山出てくるのですが、セキュリティについての話はそんなには出てきません。
End to end で暗号化されているの？　暗号化の仕組みは？　どうやって相手を認証するの？　というような基本的なことの説明もすぐには発見できませんでした。

なので、調べたことをちょろっとまとめておくことにしました。

ちなみに、identity providers (IdP) による認証の話は扱いません。

# End to end での暗号化と認証

結論から言うと、WebRTC では end to end で暗号化されています。TURN server を経由する場合でも同様です。

暗号化の仕組みですが、WebRTC の通信を始める際、各 peer は self-signed certificate を作成します。
参考: certificate を作成するタイミングは、[RTCPeerConnection が作成される時](https://www.w3.org/TR/webrtc/#constructor)です。
<details><summary>self-signed certificate（自己証明書）とは</summary>「信頼できる認証局からの認証がない、公開鍵認証用の証明書」です。認証局から認証されていなくても、暗号化通信はできます。認証局は「その証明書を持っているのが誰か」ということを保証してくれます。認証されていないということは、「相手と暗号化通信をしているけれども、相手が誰なのか（自分の意図している相手なのか）は分からない、ひょっとして悪い人かもしれない」ということです。</details>

この certificate を使用して、end to end の暗号化通信(DTLS)を行います。やったね！
・・・とはいかず、これだけだと、暗号化通信はできているけれど、「通信相手が自分の意図した相手か」が分かりません。

これは、peer to peer の通信を始める前の、signaling 段階に仕込みを入れることで解決されます。

WebRTC の簡単な構成図を示します。

![simpleArchitecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108071/021d9e78-5632-e7ec-3339-617dadb1cebd.png)

WebRTC において、signaling server はとても重要です。Peer to peer の通信を始めたいと思っても、通常、そもそも相手の IP アドレスすら分かりませんので、何かしら仲介する仕組みが必要になります。

例として、あなたが SNS を運用しているとして、そのサイトは signaling server の機能を持っているとしましょう。
あなたのサイトは Alice と Bob を id/pass などで認証しているとします。
今、Alice と Bob は互いに通信したいと考えたとします。Alice と Bob は、signaling server を通じて互いの情報(SDP) - 自分への接続先 IP アドレス（ICE）や使用可能 codec など - をやり取りします。その際に、先ほど作成した self-signed certificate の fingerprint もやり取りします。これにより、peer to peer の通信をする際に相手が提示してきた certificate と、signaling server 経由で受けとった certificate の fingerprint を突合することができます。つまり、Singling server が「今回の通信で Bob が使用する certificate はこれです」と教えてくれるので、その後に Bob（と思われる相手）と peer to peer の通信をする際、相手の提示してきた certificate が正しいかを確認することで、相手が Bob かどうかを判別することができます。
＃これまでの説明の通り、相手を認証するのには「Signaling server が信頼できる」ということが大前提になります。なので Signaling server は重要です。


参考: https://tools.ietf.org/html/rfc5763
> The media is transported over a mutually authenticated DTLS session
   where both sides have certificates.  It is very important to note
   that certificates are being used purely as a carrier for the public
   keys of the peers.  This is required because DTLS does not have a
   mode for carrying bare keys, but it is purely an issue of formatting.
   The certificates can be self-signed and completely self-generated.
   All major TLS stacks have the capability to generate such
   certificates on demand.  However, third-party certificates MAY also
   be used if the peers have them (thus reducing the need to trust
   intermediaries).  The certificate fingerprints are sent in SDP over
   SIP as part of the offer/answer exchange.

>   The fingerprint mechanism allows one side of the connection to verify
   that the certificate presented in the DTLS handshake matches the
   certificate used by the party in the signaling.
UIPageViewControllerのUIPageControlのサイズを変更する

UIPageViewControllerのデフォルトでくっついてるUIPageControlのサイズを変更するときのTipsです。

## UIPageControl自体のサイズを変更する方法
```swift
override open func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    for subV in self.view.subviews {
        if type(of: subV).description() == "UIPageControl" {
            subV.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)// ここに指定する
        }
    }
}
```
## UIPageControlのドットのサイズを変更する方法
```swift
override open func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    for subV in self.view.subviews {
        if type(of: subV).description() == "UIPageControl" {
            subV.subviews.forEach {
                $0.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
            }
        }
    }
}
```
停電しても自動復帰! VMware ESXiでの自動起動の設定

物理ノードのBIOSに入り，電源復帰時の動作を設定します．

![IMG_3155.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/262af50c-0a5c-7509-3097-b96f9871131b.png)

ESXiのWeb UIにログインして，ホストマシンの自動起動を有効に変更します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/ccc1b26c-0c11-7caf-7631-a9cee9a2aed1.png)

仮想マシンを選択して，個別の仮想マシンごとの自動起動を有効に設定します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/f67dbd1e-435a-f639-e41c-20f8741b0383.png)

ESXiノードを再起動して，仮想マシンが起動するかを確認します．
Swift5でメインスレッドかどうか確認する


SwiftではUIの更新はMain threadで実行しなければならないというルールがあります。
そのため非同期的にMain threadで処理する場合は `DispatchQueue.main.async` を使用しますが、非同期処理をする必要のない箇所で無闇に使用してしまうと処理フローの制御がしづらくなるなどの問題が起きてしまうため、サブスレッドのタスク内でのUIの更新などに限定する必要があります。

## メインスレッドで実行されているかどうか確認する方法

``` swift
print(Thread.current.isMainThread)
```

スレッドへの理解が浅いままasyncを使用していてUI更新が重くなり挙動がおかしくなっていたので、上記で確認しつつ不要な場合は同期処理で行うように修正しました。

## 参考
[DispatchQueueによる非同期処理を見直す](https://scior.hatenablog.com/entry/2018/12/29/100000#%E6%9C%AC%E5%BD%93%E3%81%ABasync%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%8B%E8%80%83%E3%81%88%E3%82%8B)
[Swift4でDispatchQueueを使う](https://qiita.com/lumbermill/items/7553a6ace26019f08bc6)
LaravelでFirebase Admin SDK for PHPを利用する(トークン再取得編)

# Firebase Admin SDK for PHPでは、自動でトークン取得はできないっぽい

例えば、Javascriptなら以下のように`currentUser.getIdToken()`で取得できる。
期限切れ前に自動で更新してくれるので便利。

```js
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
  // Send token to your backend via HTTPS
  // ...
}).catch(function(error) {
  // Handle error
});

```

Firebase Admin SDK for PHPには似たような機能はなかった。
トークンが切れるたびにいちいちログインし直すのもなんだか嫌。

## 解決方法

```php
    // ログインしていない場合
    if(!Session::get('token')){
      $signInResult = $this->auth->signInAnonymously();
      Session::put('token', $signInResult->idToken());
      Session::put('refresh_token', $signInResult->refreshToken());
    }

    // トークン認証
    try {
      $auth->verifyIdToken(Session::get('token'));
    } catch (\Exception $e) { // ここはExpiredTokenとかに絞った方が良い
      // 期限切れなら更新トークンを使って再取得
      $refresh_token = Session::get('refresh_token');
      $signInResult = $auth->signInWithRefreshToken($refresh_token);
      Session::put('token', $signInResult->idToken());
    }
```

流れは以下のような感じ。
1)ログイン時の結果に`refresh_token`があるので、セッションか何かに取っておく。
2)トークンが期限切れになったら`verifyIdToken()`で例外が発生するので、`signInWithRefreshToken()`で再取得

[リフレッシュトークンが変更されるタイミング](https://firebase.google.com/docs/auth/admin/manage-sessions?hl=ja)はそんなにないので、とりあえず使いたい場合は上記で間に合うと思う。
viewportでレスポンシブしている時にPC版表示をする

環境
初書：2020/09/08

タイトルの付け方が適当な気がしてならないが、いいのが思いつかなかった

# 前提

```html
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0">
```
`viewport`で`device-width`を使用していて、cssで`@media screen and (max-width: 600px)`のような感じでレスポンシブウェブデザインに対応させている場合

# javascriptで動的変更する
…ことが出来る。しかも一行で

```js
document.getElementsByName("viewport")[0].setAttribute('content','width=1080, initial-scale=1.0,minimum-scale=1.0');
```
`document.getElementsByName("viewport")`で、metaタグを取得する事が可能なので`setAttribute`で`content`箇所を書き換える。
（`[0]`なのは、viewportという名前はおそらくこれしかないだろうという観点から。もし他の要素にviewportという名前を付ける場合は、単純に[0]にするとバグが生じるかもしれない）

# 注意点
viewportを書き換える形の場合、スマホの横幅に合わせてサイズが細かくなるわけではなく、
画面外に伸びてサイズが変更されるので（下の図の感じ）、cssで`vw`を使ってサイズを指定している箇所はレイアウトが崩れる。

```text
 |---------------------------------------------| //width=1080に設定した時
 |------------------| // スマホ画面（400くらい？左右にスクロールが出来るようになる）
```

# 参考
[もう逃げない。HTMLのviewportをちゃんと理解する](https://qiita.com/ryounagaoka/items/045b2808a5ed43f96607)
CircleCI でプライベートイメージを使用する際に必要なポリシー

プライベートイメージを利用する際の設定方法は以下。
https://circleci.com/docs/2.0/private-images/


### すべてのリソースに対して
* `ecr:GetAuthorizationToken`


### 対象のECRに対して
* `ecr:GetDownloadUrlForLayer`
* `ecr:BatchGetImage`


## Terraform
```
data "aws_iam_policy_document" "circle_ci_policy_full_resource" {
  statement {
    actions = [
      "ecr:GetAuthorizationToken",
    ]

    resources = ["*"]

    effect = "Allow"
  }
}

data "aws_iam_policy_document" "circle_ci_policy_ecr" {
  statement {
    actions = [
      "ecr:BatchGetImage",
      "ecr:GetDownloadUrlForLayer",
    ]

    resources = [
      "{対象のECR ARN}",
    ]

    effect = "Allow"
  }
}

resource "aws_iam_user" "circle_ci" {
  name = "circle_ci"
}

resource "aws_iam_user_policy" "circle_ci_full_resource" {
  user   = aws_iam_user.circle_ci.name
  policy = data.aws_iam_policy_document.circle_ci_policy_full_resource.json
}

resource "aws_iam_user_policy" "circle_ci_ecr" {
  user   = aws_iam_user.circle_ci.name
  policy = data.aws_iam_policy_document.circle_ci_policy_ecr.json
}
```
[Ubuntu 18.04]カーネルがapt updateで更新されないようにする

- ```apt-mark hold```コマンドを用いる。以下のパッケージをホールド状態にする。
    - linux-generic-hwe-18.04				hold
    - linux-headers-5.4.0-42-generic			hold
    - linux-headers-generic-hwe-18.04			hold
    - linux-hwe-5.4-headers-5.4.0-42			hold
    - linux-image-5.4.0-42-generic			hold
    - linux-image-generic-hwe-18.04			hold
    - linux-modules-5.4.0-42-generic			hold
    - linux-modules-extra-5.4.0-42-generic		hold

```shell
$ sudo apt-mark hold linux-generic-hwe-18.04 linux-headers-5.4.0-42-generic linux-headers-generic-hwe-18.04 linux-hwe-5.4-headers-5.4.0-42 linux-image-5.4.0-42-generic linux-image-generic-hwe-18.04 linux-modules-5.4.0-42-generic linux-modules-extra-5.4.0-42-generic
```

- 確認

```shell
$ dpkg --get-selections | grep hold
```
- ホールド解除は、```apt-mark unhold```コマンドで行う。

```shell
$ sudo apt-mark unhold linux-generic-hwe-18.04 linux-headers-5.4.0-42-generic linux-headers-generic-hwe-18.04 linux-hwe-5.4-headers-5.4.0-42 linux-image-5.4.0-42-generic linux-image-generic-hwe-18.04 linux-modules-5.4.0-42-generic linux-modules-extra-5.4.0-42-generic
```
Rustのインストールがどうにもうまくいかない。

#rustを入れようとしたけど、エラーが出る

macユーザでrustのインストールでエラーが出る。
rustのインストールの時にコマンド上で、

```terminal
error: could not amend shell profile: '/Users/jin237/.bash_profile'
error: caused by: could not write rcfile file: '/Users/jin237/.bash_profile'
error: caused by: Permission denied (os error 13)
```

と出てしまう。。。

入力コマンドが
デフォルトで

```terminal
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
または

```terminal
curl https://sh.rustup.rs -sSf | sh
```

を入れてるところを、
下のように変えるとインストールできる。

```terminal
$ curl https://sh.rustup.rs -sSf | bash -s -- -y --no-modify-path

$ rustup default stable
```

中身の説明は省略。
BigQuery 101

## Features

fully managed, petabyte scale, low cost analytics data warehouse (cloud database). 

NoOps—there is no infrastructure to manage and you don't need a database administrator. 

(So you can focus on analyzing data to find meaningful insights, use familiar SQL, and take advantage of our pay-as-you-go model.)

## What Problem can BigQuery Solve

Storing and querying massive datasets can be time consuming and expensive without the right hardware and infrastructure. Following action takes time in traditional SQL and Hadoop mapreduce:

- determine right index and build it
- how much space it take in the DB
- how to choose network, amount of RAM, CPU cores

Google BigQuery is an [enterprise data warehouse](https://cloud.google.com/solutions/bigquery-data-warehouse) that solves this problem **by enabling super-fast SQL queries using the processing power of Google's infrastructure**.

## Access of BigQuery

- GCP Console
- classic web UI,
- command-line tool
- by making calls to the BigQuery REST API using a variety of client libraries such as Java, .NET, or Python
- 3rd party tools

## What product you can connect BigQuery

programming framework and analysis tools thanks to it is a RESTful API

G product, App Engine, App Scripts, G Analytics

Open Source Community: R

send your logs to to be queried to analyze 

## How to Start

you don't need to deploy any resources, such as disks and virtual machines

Just get started by running a web query or using the command-line tool.

The only thing you need to know to use BigQuery is SQL query.

## What's in BigQuery

public dataset shared in BQ, u'll get a free one month quota.

## What BQ Bill for

- data storage
- amount of data each query processes

so what you need to know are things to use BQ,

- what's my data
- what are my queries

## Usecase

The following is a common architecture of applying BigQuery

![Screen Shot 2020-09-08 at 12.16.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544279/9c963edc-af32-c4e2-362b-58ca273dc55d.png)
Cloud FirestoreでUniqueを実現する2手法とその使い分け

Cloud FirestoreでUniqueを実現する方法は2種類あるように思います。

# ユーザ権限

これはクライアント側、つまりWebやアプリのユーザ側に公開されている権限で処理を行う場合です。
この場合はDocument IDを、Unique Keyにするしか無いでしょう。
ドキュメントを読んでもフィールドを基準にUniqueにする方法は用意されていないように思います。

Firestoreのruleでcreateのみを許可するようにしておけばUniqueとなります。
UniqueKeyとした同じDocumentIDで書き込みを行った場合にupdateとなりFirestore Ruleに違反するので上書きが行われなくなりUniqueであることを担保できます。

ただし、updateが起きた際にエラーになってしまうので
後述するTransactionを使った手法を使ってエラーが出ないようにすることを推奨します。

# サービスアカウント権限

Admin SDKを使う場合の手法です。
Admin SDKは、Firebase Ruleを無視してしまうので前述のcreateのみを許可する方法は使えません。

こちらの場合は、単純にTransactionを使うと良さそうです。
（実際にUniqueが担保されるかは、この記事を書いてる時点では筆者は未検証です）
https://cloud.google.com/firestore/docs/manage-data/transactions?hl=ja

# 2手法の比較

ユーザ権限でもTransactionだけを使えば良さそうですが、問題があります。

ユーザ側の権限での実行については、自由に処理を作ることが出来るので、updateやdeleteを行われる可能性があるのでcreateのみを許可しておくと良さそうです。

ネットワークに接続されたシステムでは、このようなケースもカバーしておくことが求められます。

対して、サービスアカウント権限はこのような悪さをしない事が分かっているので、Transactionだけで対応する事ができています。
[ WordPress ] リンクなしでカテゴリを出力する

WordPressの投稿記事に紐づいたカテゴリを出力するには、通常 <?php the_category(); ?> を使いますが、その場合リンクもつきます。

このリンクをなくしたいと思いました。実装方法は、<?php get_the_category(); ?> を用いて一旦配列に格納して、ループで表示させました。また、複数のカテゴリを表示させる際セパレート（,）をつけて見やすくしましたが、最後のカテゴリが出力された際セパレータがつかないよう条件分岐もさせています。

```php:loop.php
<?php
  $categories = get_the_category();
  $length = count($categories);
  $i = 0;

  foreach($categories as $cat){
    $i++;
    if($length == $i){
      echo $cat->cat_name;
    }else{
      echo $cat->cat_name . ', ';
    }
  }
?>
```

## implode を使う
上記を投稿したところ、下記のように implode を使えばシンプルに実装できるとコメントを頂戴しました。

[technote-space](https://qiita.com/technote-space)様、ありがとうございました！

```php:loop.php
<?php
 $categories = get_the_category();
 echo implode(', ', array_map(function($cat) { return $cat->cat_name; }, $categories));
?>
```

## 参考URL
* [テンプレートタグ/get the category - WordPress Codex 日本語版](https://wpdocs.osdn.jp/%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%BF%E3%82%B0/get_the_category)
* [【PHP】foreach文で最初と最後の処理を変えたい場合  |  Web Stock](https://webstock-blog.com/programming-foreach/)
* [PHP: implode - Manual](https://www.php.net/manual/ja/function.implode.php)
Flutterのテンプレートをスニペット・LiveTemplateに設定しよう

#プロジェクトを立ち上げていちいちコードを書くのがめんどくさい
最近会社の方針でFlutterの学習を始めたのですが、勉強の際何度も新規プロジェクトを立ち上げます。

その度「class！」「extends！」「StatelessWidget！」と書くのがめんどくさいし時間の無駄なので、テンプレートをここに記載しておきます。

これをAndroidStudioのLiveTemplateに設定しておけばコードを爆速で書けるようになります！

```dart

import 'package:flutter/material.dart';
void main() {
  runApp($CLASS$());
}
class $CLASS$ extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: "$TITLE$",
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: $STATE$(),
    );
  }
}

class $STATE$ extends StatefulWidget {
  @override
  _$STATE$State createState() => _$STATE$State();
}

class _$STATE$State extends State<$STATE$> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text($TITLE$),
      ),
      body: PageView(),
    );
  }
}

```

自分は「start」と打ち込むとこのコードが出るよう設定しました。

開発の速度が爆上がりしたらいいなあ…。

AndroidStudioのPreference→Live TemplatesのFlutterの中に追加して、追加したものを右クリック→Change ContextでDartにチェックを入れてあげれば使えるようになるはず！

VSCodeの場合はdart.jsonにこれを書き込んでください！

```
"Start":{
		"prefix":"start",
		"body":[
			"import 'package:flutter/material.dart';"

			"void main() {"
				"\trunApp(MyApp());"
			"}"

			"class MyApp extends StatelessWidget {"
				"\t@override"
				"\tWidget build(BuildContext context) {"
					"\t\treturn MaterialApp("
						"\t\t\tdebugShowCheckedModeBanner: false,"
						"\t\t\ttitle: '$2',"
						"\t\t\ttheme: ThemeData("
						"\t\t\t\tprimarySwatch: Colors.blue,"
						"\t\t\t),"
						"\t\t\thome: $1(),"
					"\t\t);"
				"\t}"
			"}"

			"class $1 extends StatefulWidget {"
				"\t@override"
				"\t_$1State createState() => _$1State();"
			"}"

			"class _$1State extends State<$1> {"
				"\t@override"
				"\tWidget build(BuildContext context) {"
					"\t\treturn Scaffold("
						"\t\t\tappBar: AppBar("
							"\t\t\t\ttitle: Text("
							"\t\t\t\t\t'$2'"
							"\t\t\t\t),"
						"\t\t\t),"
						"\t\t\tbody: PageView(),"
					"\t\t);"
				"\t}"
			"}"
		],
	"description": "最初に使うといい"
	}
```

他にも役に立ちそうなスニペットを書いておきます！

```
"Class":{
		"prefix":"class",
		"body":[
			"import 'package:flutter/material.dart';"
			""
			"class $1 extends $2 {"
			"}"
		],
	"description": "クラス"
	}

	"Icons":{
		"prefix":"icons",
		"body":[
			"Icon(Icons.$1)"
		],
	"description": "アイコンを出す"
	}

	"Text":{
		"prefix":"text",
		"body":[
			"Text('$1')"
		],
	"description": "文字を打つ"
	}

	"Navigate":{
		"prefix":"navigate",
		"body":[
			"Navigator.of(context).push("
				"MaterialPageRoute(builder: (context) {"
					"return $1();"
				"}),"
			");"
		],
	"description": "画面遷移"
	}

	"Back":{
		"prefix":"back",
		"body":[
			"Navigator.of(context).pop();"
		],
	"description": "前の画面に戻る"
	}
```

#情報求む！
実はまだFlutterを勉強して1週間も経っていないど素人です。

素人目線で早く書けるよう工夫しただけですので、詳しい方がいたらもっと良いスニペットの書き方を教えてください！
heroku run rails db:migrate ができないエラーの解消方法

【概要】
----------------------------------------
<b>1.結論</b>

<b>2.なぜ起きるのか</b>

<b>3.どのように解決するのか</b>

<b>4.ここから学んだこと</b>



1.結論
----------------------------------------
<b>migrateファイルを整理</b>する！
<br>

2.なぜ起きるのか
----------------------------------------
migrateファイルが噛み合っていなかったことが原因でした。実は、% rails db:rollbackをする前に、
upしているファイルのカラム名を変更してしまいました。


![スクリーンショット 2020-09-08 11.20.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686400/0d3488b0-41b2-933b-6435-abf2cdf4f467.png)

上記の画像では全て"up"になっていますが、この状態でカラム名を変更するための操作をしてしまいました。
具体的には % rails generate migration rename_”変更前カラム名”_column_to_”モデル名” です。AddやDropもしておりました。


```terminal:ターミナル
% heroku run rails db:migrate 
```
上を実行した際に文字や数字の中にとある一文がありまして”migrateファイルのorders(私が作ったmigrateファイル名です）がないよ”とも言われましたし、

```terminal:ターミナル
% rails db:migrate
```
上を実行した際にもordersに＋αで”このカラム名がないよ”ということを言われました。


<br>
3.どのように解決するのか
----------------------------------------
ただやることは明確で、migrateファイルの食違いをなくすために整理しました。

今回はとにかく早くエラーを解消したかったために、画像を用意し忘れました。

この時は必ず削除が発生する (=migrateファイルの削除ですが結果的にはDBをいじることになる）ので% rails db:rollback を必ず行いました。
（rollbackするとDBのテーブルの中身は消えますが開発段階では特に問題はないと思います。）

% rails db:migrate:statusでも"down"してることを確認しました。
自分は該当テーブルのカラム名のRenameやAdd、テーブルのDropを行っていたので順を追って何が必要で何が消しても問題ないかを慎重に行いながら整理しました。
% rails db:migrate　を行うとうまく機能したのでherokuでも試してみるとうまく行きました。
<br>


<br>
4.ここから学んだこと（エラーの時に使用）
----------------------------------------
今思い返してみるとrollbackせずに、勝手にDB上でテーブルを削除したり、ロールバックしているけど違うファイルでカラム名を追加したりいろんなことたくさんやっていました。その時にmigrateしてもなぜかエラーが出るので勝手に削除等を行ってうまくいってしまってたので、ツケが回って1日も費やす形になってしまいました。

実は自分がこの記事を書いたエラー(<a href="https://qiita.com/taka_no_okapi/items/0444afde4817920d0671">git push heroku masterする際のエラー解消方法</a>)の前に起きたことだったので、migrateファイルを改善したのになぜherokuのmasterにpushできないのかと焦っていました。migrateファイルやDB関係は特に注意して扱わないと修正が本当に大変になることを実感しました。またrollbackする際は% rails db:rollback STEP="数字"をすることでupの箇所から上方向”数字”番目までロールバックしてくれます。手間とミスを省ける記述です。<br>
Githubのwikiをローカルに取り込んでメモをしたい

## 目的
自分のためだけ用にローカルでwikiを編集して残しておきたい

## 方法
これだけ
`git clone レポジトリ名.wiki`

## 例
TypeScriptのwikiをローカルにクローンしたい。
`git clone https://github.com/microsoft/TypeScript.wiki`

wikiのmdファイルがクローンされる
![Screen Shot 2020-09-08 at 11.11.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/312001/c2358c2d-8fbb-f772-4fc4-41cef5e71e7a.png)

## まとめ
これで勉強しほうだい
Personal access tokenを発行して、Resource not accessible by integrationエラーを解消する

### 前提
Qiita記事
[「10分で自分のGitHubプロフィールをカッコ良くする」](https://qiita.com/Hassan/items/134009209f5709f892b1)
このQiita記事に則って**Error: Resource not accessible by integration**というエラーにハマったらご参照下さい。

このエラーは「統合ではリソースにアクセスできません」と直訳で言っていますが、つまりは**リポジトリへのアクセス権が無い**ことが問題になっています。

### 解決に当たって必要になるもの
- Personal access tokenの発行と記述

上記のQiita記事内で.github/workflows/profile-summary-cards.ymlファイルを作成していきますが、ファイル内は通常はこのように記述します。

```.github/workflows/profile-summray-cards.yml(修正前)
name: GitHub-Profile-Summary-Cards

on:
  schedule: # execute every 24 hours
    - cron: '* */24 * * *'
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    name: generate

    steps:
      - uses: actions/checkout@v2
      - uses: vn7n24fzkq/github-profile-summary-cards@release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          USERNAME: ${{ github.repository_owner }}
```

しかし、これだと上手くいかないことがあり、タイトル通りのエラーが発生してしまいます。

その為、ファイル内の書き換えが必要ですが、
先にPersonal access tokenの発行が必要です。

### Personal access tokenの発行
1.自身のGitHubの一番右上のアイコンを押下してメニュー内のSettingsを押下する。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638561/8e9f8093-c0a3-49a4-038c-fbb761b6e24c.png)
2.画面が遷移したら、Developer settingsを押下
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638561/4c548e65-8971-fe51-f93e-2fce8febfa9e.png)
3.Personal access tokensを押下し、Generate new tokenに入る。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638561/6b5e2362-20f2-8494-ef0d-bc91e0f0f654.png)
4.番号が発行されるので、コピペしてReadmeのリポジトリへ移動。
リポジトリ内のSettingsを押下。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638561/0f10aa1e-d113-45f6-8d87-e2676c7243d3.png)
5.メニュー内のSecretsを押下し、New secretでファイルを作成する。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638561/5380efac-bbd6-8934-1cc3-3ff735871ad3.png)
6.ファイル名を設定し、Value欄に上記でコピペした番号を貼り付ける。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638561/56df3bd7-e95f-96f3-5084-602e944aded2.png)
7.　.github/workflows/profile-summray-cards.ymlファイル内のsecrets.GITHUB_TOKENをsecrets.PERSONAL_ACCESS_TOKENへ書き換えて保存する。


```.github/workflows/profile-summray-cards.yml(修正後)
name: GitHub-Profile-Summary-Cards

on:
  schedule: # execute every 24 hours
    - cron: "* */24 * * *"
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    name: generate

    steps:
      - uses: actions/checkout@v2
      - uses: vn7n24fzkq/github-profile-summary-cards@release
        env:                         (↓ここを書き換える)
          GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
        with:
          USERNAME: ${{ github.repository_owner }}
```

コミットしてファイルを更新することでResource not accessible by integrationエラーが解消されます。

改めて[「10分で自分のGitHubプロフィールをカッコ良くする」](https://qiita.com/Hassan/items/134009209f5709f892b1)の記述に従って作業が完了できます。

それでもエラーが解消できなければ作成したファイル名や、記述ミスを疑ってみてください。

以上です。
GooglePlayConsoleで課金テストをする時にテスターに登録したのにも関わらず「お支払い方法の追加」が表示されてしまう時

####経緯
調べても投稿が無く、解決に時間がかかってしまいました。
同じ轍を踏む人が出ないようにここに記しておきます。

####注意
ここで言うGooglePlayの公式ドキュメントのURLはこちら　「Google Play 請求サービスをテストする」https://developer.android.com/google/play/billing/billing_testing?hl=ja
この記事は「GooglePlayConsoleにテスト用アプリを登録して内部テストまで行ったけど課金処理をテストしたらGooglePlay公式のドキュメントで出ている"常に承認/常に不承認"カードの選択ではなく「お支払方法の追加」が表示されてしまう人」向けに書いた記事です。そこまで行く手順は他の記事を参照してください。
GooglePlayConsoleの画面構成はたまに変わるようなので、もしかしたら同じ手順で上手く行かないかもしれません。
設定を変更しても反映するのに5分程度掛かりました
情報は2020.9.8現在の物です。

###結論
__GooglePlayConsoleのトップ→設定→ライセンステスト</color>__ にテスターに登録したいアカウントのメールアドレスを登録し、変更を保存する必要がありました。

###まとめ
テスターの登録には「アプリをダウンロードする事を許可する登録」と「課金テスト時にテスト購入を許可する登録」の２つが必要なようです。
「課金テスト時にテスト購入を許可する登録」はデベロッパー単位なので、そこに登録されたアカウントはそのデベロッパーから出している全てのテストアプリでのテスト購入が可能になるっぽいです。（実際には試していませんがそんな感じの警告が出ます）
時間が掛かってしまった原因は、課金テストを許可するアカウントもアプリ単位で登録する物だとばかり思ってトップメニューを見なかった事ですかね…
あとGooglePlayConsoleのレイアウトが公式のドキュメントと少し異なる所も混乱の原因でした（人のせいにしてはいけませんよ）
以上です。精進します。
Rubyの古いgemで自動ファイルアップロード Watirでの対処法


## 本稿について
WatirでWebサイトに対してファイルアップロードするスクリプトを書いていましたが、
古い環境で情報が見つけづらく困ったところ解決したので備忘録です。


## 環境
　CentOS Linux 7
　Ruby 2.0.0p648
　仕様gemはWatir
　ブラウザはFirefoxを使っていますが、Chromeなど、別のブラウザでも

## やりたいこと
あるWebサイトに対して、Watirをつかって自動スクリプト起動でファイルアップロードさせたい。
アップロード画面ではSelect file というボタンを押して、ファイル選択画面が出た際にそこからファイルを選んでアップロードさせる仕様

## 躓いたこと
アップロード画面からファイル選択をする挙動ができておりません。
OS標準のファイル選択画面が開いた時点で、ブラウザ外の動作になってしまうのかスクリプトの操作が及びません。


## 試したこと

1. watir内部でjavascriptを実行できるので、
クリップボードなどを使ってコピペができないか　など試しましたがそもそも画面の仕様がスクリプトでのクリップボード経由の
ペーストを受け付けていないでいるらしく、ペーストがエラーも吐かずに静かに何も起こらず終了してしまいます。
2. 強引にキーイベントをjavascriptから発動させる。
下記のようなコマンドを実行して強制的にEngerキーやTabキーなど打つことできないか試しましたが、
ブラウザ自体にフォーカスがあたってしまっている？ようで、ファイル選択画面がキーコマンドを受け付けないでいます。

```ruby
    browser.execute_script("
                document.dispatchEvent( new KeyboardEvent( 'keydown', { keyCode: 86 , ctrlKey: true , key: 'V' }) );
    ")
```

（参考：https://ameblo.jp/personwritep/entry-12456996738.html）
などなど試しましたが、対象のファイルを読みに行くなどの動作は行ってくれません。


## Webサイトの仕様・画面イメージ
ファイルアップロード用の画面が下記で、`Select file`ボタン押す事ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540634/90461761-e23e-6f6d-8154-c1752465bdc2.png)

すると下記のようなOS標準のファイル選択画面が出て、そこからファイルをアップロードするような作りになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540634/6e3a070c-7f3d-e776-451d-93b7a5ecfce7.png)

人の手で操作する際は`Select file`ボタンを押してからファイルを選択するか、ドラッグ＆ドロップでファイルアップロードすることも可能です。

## 出来た
結果、これでできてしまいました。

```ruby
$browser.file_field(:id, //).set("filepath\/...\/file.png")
```

## 参考にした記事
https://stackoverflow.com/questions/15163816/automating-a-file-upload-with-watir-in-chrome-on-osx
https://www.rubydoc.info/gems/watir/1.8.1/Watir%2FContainer:file_field


## 最後に一言
いやWatirて。