OmniAICreator/Qiita-1.07M huggingface dataset:
COTOHA APIを使って俳句を詠む!

[【Qiita x COTOHA APIプレゼント企画】COTOHA APIで、テキスト解析をしてみよう！](https://zine.qiita.com/event/collaboration-cotoha-api/?utm_source=qiita&utm_medium=top_banner)の企画を見て俳句詠むツール作ってみました！

**文章から俳句を詠むツールを作りました。**
[COTOHA API](https://api.ce-cotoha.com/)を利用しています



## やり方
[構文解析API](https://api.ce-cotoha.com/contents/reference/apireference.html#parsing)を利用します。

利用したのはform, kana, posです。

**kana**で文字列の長さを判定しています。
俳句は音で５・７・５を数えるので、単純に文字列の長さで作ることはできません。例えば、ジショは文字列としては3文字ですが、読みとしては2音です。小文字を無視するコードを書いてこれを判定しています。

**pos**は俳句の最初や最後に使っていいか判断するために使いました。例えば括弧などは入れられない、終助詞は俳句の最初に使うとおかしい。などです。

ある文章を構文解析した一部が以下です

```
    "tokens" : [ {
      "id" : 48,
      "form" : "個別",
      "kana" : "コベツ",
      "lemma" : "個別",
      "pos" : "名詞",
      "features" : [ ],
      "attributes" : { }
    }, {
      "id" : 49,
      "form" : "辞書",
      "kana" : "ジショ",
      "lemma" : "辞書",
      "pos" : "名詞",
      "features" : [ ],
      "dependency_labels" : [ {
        "token_id" : 47,
        "label" : "nmod"
      }, {
        "token_id" : 48,
        "label" : "compound"
      }, {
        "token_id" : 50,
        "label" : "case"
      } ],
      "attributes" : { }
    }, {
      "id" : 50,
      "form" : "に",
      "kana" : "ニ",
      "lemma" : "に",
      "pos" : "格助詞",
      "features" : [ "連用" ],
      "attributes" : { }
    } ]
```



# 詠んでみる
これらの処理で俳句に使えそうな単語を抽出して俳句を作ります！

[COTOHA APIについて]
(https://api.ce-cotoha.com/contents/about.html)の一部の文章を俳句にします

```
COTOHA APIの強みは、「①日本語辞書」「②意味属性付与」「③個別辞書登録・チューニング」です。
これにより、日本語文章を正しく解析・理解でき、またサービス用語や専門用語などをお客さま個別辞書に登録し、チューニングができるため、確実に精度向上ができます。
```

## こんな感じのものができました
<img width="383" alt="スクリーンショット 2020-03-15 8.56.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199256/dc192e05-5102-a4cd-5346-515d99a8a374.png">


# 改善：何とかして季語のようなものを表現できないか
さらに進化させたいと思い、何とか季語を表現できないか考えました。


COTOHA APIには[固有表現抽出API](https://api.ce-cotoha.com/contents/reference/apireference.html#entity)があり、花の名前や食べ物名などを抽出できます。これによって抽出されるものを優先的に取り込むことによってより俳句に近づくのでは？
チャレンジしてみました。


[気象庁ページ](https://www.data.jma.go.jp/sakura/data/index.html)よりめっちゃ季語らしきものが含まれた以下の文章

```
気象庁では、全国の気象官署で統一した基準によりうめ・さくらの開花した日、かえで・いちょうが紅（黄）葉した日などの植物季節観測（注）や、うぐいす・あぶらぜみの鳴き声を初めて聞いた日、つばめ・ほたるを初めて見た日などの動物季節観測を行っています。
観測された結果は、季節の遅れ進みや、気候の違いなど総合的な気象状況の推移を把握するのに用いられる他、新聞やテレビなどにより生活情報のひとつとして利用されています。
```

以下のものができました。UIもややパワーアップ！
<img width="1440" alt="スクリーンショット 2020-03-15 15.17.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199256/09cb6401-6fd1-3509-e159-8f3f1a175991.png">


他にはこのような俳句ができています。
気象庁とあぶらぜみ好きすぎやろ、、、

```
あぶらぜみの 把握するのに 気象庁
鳴き声を 把握するのに 気象庁
あぶらぜみの 季節の遅れ 気象庁
行って 把握するのに 気象庁
新聞や さくらの開花 気象庁
テレビなど 季節観測 気象庁
用いられる さくらの開花 あぶらぜみ
あぶらぜみ 観測された 気象庁
観測さ 推移を把握 気象庁
鳴き声を 気象庁では 気象庁
観測され 季節の遅れ 気象庁
あぶらぜみの 観測された 気象庁
観測され さくらの開花 あぶらぜみ
鳴き声を 季節観測 気象庁
```
GASでスクレイピングを基本動作やってみる。解説付き。


スプレッドシートに項目を追加します。
左上から【ファイル】、【編集】、、という感じで、【スクリプト実行】という項目が現れます。onOpen関数は、スプレッドシートを開いた時に実行されるイベントハンドラですね。

```コード.gs
function onOpen() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  var entries = [
    {
      name : "タイトルを取得する",
      functionName : "update"
    }
  ];
  sheet.addMenu("スクリプト実行", entries);
}
```

そして、基本的な流れですね。シートのセル情報を２次元配列に格納します。
スプレッドシートのAPI操作はかなり遅いです。
なので、
①【セル情報をシートでまとめて取得する】
②【GAS側でまとめて配列処理する】
③【配列をシートにまとめて格納する】
としています。


```コード.gs
function update(){
  var urls = [];
  var titles =[];

  var sheet = SpreadsheetApp.getActive().getSheetByName('シート1');
  var sheet_data = sheet.getDataRange().getValues();    // シート全体のデータを取得する。dataにはシートのデータが２次元配列で入る

  Logger.log("data.length:", sheet_data.length);

  urls = getUrls(sheet_data);
  sheet_data = getTitles(sheet_data, urls);
  setSheet(sheet_data, sheet);
}
```

配列からURLのデータを抜き出すところです。


```コード.gs
function getUrls(sheet_data){

  var urls = [];                                  // URL列のURLを格納する
  const urlColumnIndex = 0;                         // URL列を指定する
  Logger.log("sheet_data.length:" + sheet_data.length);
  
  for (var i = 0; i < sheet_data.length; i++) {
    urls.push(sheet_data[i][urlColumnIndex]);
    Logger.log("url:", urls[i]);
  }
  return urls;
}
```
ここが今回のキモですね。
スクレイピングします。
抜き出したいところを【beginning_tag】と【ending_tag】で挟まれるように指定します。下の例は、【ほにゃらら】を抜き出します。


```コード.gs
function getTitles(sheet_data, urls) {

  // <title> ほにゃらら</title>;

  var beginning_tag = "<title>";
  var beginning_index;

  var ending_tag = "</title>";
  var ending_index;

  var html;
  var url;
  var titles = [];
  const titleColumnIndex = 1;     // タイトル列を指定する
  
  for (var i = 0; i < urls.length; i++) {
    url = urls[i];
    
    if (i==0 && url == "URL"){
      titles[i] = "タイトル";
    }
    if (url !== "URL"){
      html = UrlFetchApp.fetch(url).getContentText('UTF-8');
      beginning_index = html.indexOf(beginning_tag);
      ending_index = html.indexOf(ending_tag);        
      if (beginning_index !== -1 && ending_index !== -1) {
        titles[i] = html.substring(beginning_index + beginning_tag.length, ending_index);
      }
    }
    Logger.log("title:", titles[i]);
  }
  
  for(i=0; i<titles.length; i++){
    sheet_data[i][titleColumnIndex] = titles[i];
  }
  
  return sheet_data;
}
```
最後にシートにスクレイピングした文字列を格納する作業です。
ここも時間短縮するために、配列をまとめてスプレッドシートに格納してます。
コードも見易くなりますね。

```コード.gs
function setSheet(sheet_data,sheet){
  
  const LastRow = sheet.getDataRange().getLastRow();  
  const LastCol = sheet.getDataRange().getLastColumn();  
  
  sheet.getRange(1,1,LastRow,LastCol).setValues(sheet_data);
}
```

URLがA列、タイトルがB列ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603084/ca8b26a3-d278-d78a-cbd0-562c63634f80.png)
NeoVimでFlutterの開発環境を整える

##目的
Flutterの開発環境といえばAndroid Studioなどが主流な感じがする。しかし、これらの開発環境は非常に重い。この記事はNeovim や Vimを使うことで開発環境を多少でも軽くすることを目的とする。

##導入した環境
OS : Ubuntu 18.04 LTS
カーネル : 5.3.0-40-generic
Neovim : 0.3.8

##準備
プラグイン管理ツールを用意

##使用するプラグイン
[dart-vim-plugin](https://github.com/dart-lang/dart-vim-plugin)
[vim-flutter](https://github.com/thosakwe/vim-flutter)

##導入方法
deinでの導入方法はdein.tomlに当該プラグインを記述するだけ。ただし、起動時にdein.tomlを読み込むようにする必要がある。再起動すれば自動でインストールが始まる。

```dein.toml
[[plugins]]
repo = 'dart-lang/dart-vim-plugin'
[[plugins]]
repo = 'thosakwe/vim-flutter'
```

.vimrcもしくは.nvimrcに直接書き込むことも可能。deinのREADMEに導入方法は書いてあるので、先程貼ったリンクを参照。

これで、DartとFlutterの環境導入はおわり。dart-vim-pluginでは~~~コード解析や補完などを行ってくれる~~~シンタックスハイライトがつく。使い方はREADMEを参照。vim-flutterではエミュレータの起動、デバックなどをvim内でできるようにしてくれる。こちらも使い方はREADMEを参照してほしい。

##補完機能が欲しい場合
DartのLSPを導入して、coc.nvimなどのプラグインの設定をすれば補完が利くようになる。
coc.nvimでは多くの言語のLSPの設定方法をまとめてくれているのでおすすめ。
[こちら](https://github.com/neoclide/coc.nvim/wiki/Language-servers)を参照。

##おわりに
vimやneovimでプラグイン管理を始めれば、新しい言語を学ぶ際も環境導入を楽にすすめることができるので、ぜひ使うことをおすすめする。
パナソニックプログラミングコンテスト2020 A~C

パナソニックプログラミングコンテスト2020
https://atcoder.jp/contests/panasonic2020/tasks

#A問題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475270/c464f1ab-c255-b0d0-e7af-83268cb5e9c5.png)

```A問題.c++
#include <bits/stdc++.h>
#define rep(i,n) for (int i=0; i<(n); i++)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

int main(){
    int A[32]={1, 1, 1, 2, 1, 2, 1, 5, 2, 2, 1, 5, 1, 2, 1, 14, 1, 5, 1, 5, 2, 2, 1, 15, 2, 2, 5, 4, 1, 4, 1, 51};
    int K; cin >> K;
    cout << A[K-1] << endl;
    return 0;
}
```

#B問題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475270/efcaea72-4406-0b43-3fe4-1d83c771c937.png)

```B問題.c++
#include <bits/stdc++.h>
#define rep(i,n) for (int i=0; i<(n); i++)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

int main(){
    ll H,W; cin >> H >> W;
    if (H==1 || W==1) cout << 1 << endl;
    else if (H%2!=0 && W%2!=0) cout << H*W/2+1 << endl;
    else cout << H*W/2 << endl;
    return 0;
}
```

#C問題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475270/13efa716-0796-0007-2968-386dfb3a0f00.png)

```C問題.c++
#include <bits/stdc++.h>
#define rep(i,n) for (int i=0; i<(n); i++)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

int main(){
    ll a,b,c; cin >> a >> b >> c;
    ll tmp=c-(a+b);
    if (tmp>0 && 4*a*b<tmp*tmp) cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
}
```

#まとめ
・B問題　**if (H==1 || W==1) cout << 1 << endl;**を考慮出来てなかった…
・C問題　**sqrt使うにはdouble型**にしなければいけないが、double型でやると**誤差**が生じるため、なんとか**ll型(整数型)**にしなければいけなかった…**（場合分けに注意！）**
決定木の可視化ライブラリdtreevizのインストール

# サマリ

決定木の可視化ライブラリとしてよく利用されるdtreevizに関して、pip install dtreeviz後の実行時エラーの対応がとりあえずconda installしておけばOKという記事をいくつか見ましたが、、、

conda installのせいでanaconda環境が壊れた経験があり、conda installをしたくない方のための環境構築方法。

# 結論

Graphvizの実行ファイルを[公式サイト](https://graphviz.gitlab.io/download/)からインストールしてPATHに通すことで、conda installなしで実行可能となる。

急ぎの方は、[解決策へGO](#解決策)


# 環境
- windows10
- anaconda環境 (dtreevizライブライをインストール済であることを想定。まだの方は下記実行後に本記事をご参照ください)

```
pip install dtreeviz
```

# 出現していたエラー

```
FileNotFoundError: [WinError 2] 指定されたファイルが見つかりません。
During handling of the above exception, another exception occurred:
ExecutableNotFound                        Traceback (most recent call last)

```
や

```
ExecutableNotFound: failed to execute 
['dot', '-Tsvg', '-o', 'C:\\Users\\XXXX\\AppData\\Local\\Temp\\DTreeViz_15304.svg', 
'C:/Users/XXXX/AppData/Local/Temp\\DTreeViz_15304'], 
make sure the Graphviz executables are on your systems' PATH
```

# エラーの内容

ともに`dot`コマンドが実行できなかったことに起因している。

エラー内容の２つ目を意訳すると、、、

> make sure the Graphviz executables are on your systems' PATH

Graphvizの実行可能ファイルがPATHに通されているか確認して！

> ['dot', '-Tsvg', '-o', 'C:\\Users\\XXXX\\AppData\\Local\\Temp\\DTreeViz_15304.svg', 'C:/Users/XXXX/AppData/Local/Temp\\DTreeViz_15304']

dotコマンドをオプション2つ付きでsvgファイルを実行しようとしたけど、なかったから！

# 解決策の前に・・・

そもそもdotコマンドとはgraphvizを利用するときに用いるコマンドである。
macではbrewですぐに利用できるようになるが、windowsではそうはいかない。

とりあえずエラー文言でググり、エラー解消方法を探すも、とにかく下記を実行して！

```
conda install python-graphviz
```

がたくさん出てくるが conda install は極力したくなかったので、下記の解決策を取りました。

# 解決策

1. Graphvizの公式サイトへ飛ぶ　[link](https://graphviz.gitlab.io/download/)
2. 「Stable X.XX Windows install packages」を押下
![click.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369559/af772322-51f7-5ea6-6df2-5dfcfbe70db4.png)
3. 「graphviz-X.XX.msi」を押下してダウンロード
![msi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369559/08a45576-a9e4-f5c3-286e-9c8da333b0f4.png)
4. インストール先のフォルダパスを確認　例）　C:\Program Files (x86)\GraphvizX.XX\
5. 上記フォルダ + binフォルダに「dot.exe」が格納されていることを確認
![dot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369559/1f5838bc-5011-1de1-a7a9-ec146533926f.png)
6. binフォルダのパスを環境変数に追加※
![path.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369559/e71797ea-6fa0-e140-d626-1ebec0cd30e8.png)

※[windows] + [pause/break]　→ システムの詳細設定 → 環境変数 → ユーザー環境変数 Path　を編集 → 新規でbinフォルダのパスを追加

＊あとがきも参照！

# あとがき

- なぜconda installしなければならないのか？・・・という点の詳解がなかったので、試行したにすぎずconda installでもうまくいくと思います。
- 弊社の実行環境がpip install推奨であり、conda install 自体に深い因縁があるわけではないです。- 2020年3月時点の私は、dtreevizが決定木には最も適していると考えているため、上記方法を取っていますが時代が変われば方針も柔軟に対応する予定です

＊簡単のため仮想環境でない方のPATHに追加していますが、環境分離意識の高い方は設定先をanacondaの仮想環境のみのPATHに設定することをおすすめします！
Pythonで「インターネット アクセスなし」から蘇る

# はじめに
**みなさん、突然の「インターネットアクセスなし」に悩まされていませんか？**

![netsh_test1 (3)_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110876/0511c206-12cf-9556-09ab-57b64c051e46.jpeg)

私は悩まされていました。
定型業務を自動化するためにスクリプトを組んで古いPCに常駐させているのですが、
PCをつけっぱなしにしているといつの間にか「インターネット アクセスなし」の状態になっていて、手動でPCのネットワークを切断、再接続する必要がありました。
自動化して放置しているのにいつの間にか処理が止まってるの、怖いですよね。

そこで、スクリプト内でネットワークの状態確認、再接続を行うようにしてみたので紹介します。

(そもそもなんでインターネットアクセスなしになるのかとか分からないので詳しい人教えてください)

# 環境
・Windows7
・Anaconda3

# とりあえず結論(コード)
内容はほぼWindowsのコマンドですが、スクリプトの一部のためPythonからコマンドを呼び出しています。

```python
def is_ping_ok():
    proc = subprocess.run(["ping", "yahoo.co.jp"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    ret = proc.stdout.decode("cp932")
    if "見つかりません" in ret:
        return False
    else: return True

def restart_network():
    subprocess.run(["netsh", "wlan", "disconnect"])
    subprocess.run(["netsh", "wlan", "connect", 'name="接続したいSSID"'])
    time.sleep(5)

def check_network():
    if not is_ping_ok():
        restart_network()

        if is_ping_ok():
            return "Restarted!"
        else: return "Error"
    return "OK"
```

とりあえず一回試して復活しなければあきらめるようにしていますが、負けず嫌いの方は復活するまで徹底的に再帰してもいいかと思います。

# 解説
## ネットワークの状態を確認

インターネットアクセスがあるかどうかは ping コマンドで確認します。
突然出てきたsubprocessに関しては[この記事](https://qiita.com/caprest/items/0245a16825789b0263ad)とか参照してみてください。

下記はインターネットアクセスありの場合

```python
>>> import subprocess

>>> proc = subprocess.run(["ping","yahoo.co.jp"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> print(proc.stdout.decode("cp932"))

yahoo.co.jp [182.22.59.229]に ping を送信しています 32 バイトのデータ:
182.22.59.229 からの応答: バイト数 =32 時間 =11ms TTL=50
182.22.59.229 からの応答: バイト数 =32 時間 =16ms TTL=50
182.22.59.229 からの応答: バイト数 =32 時間 =21ms TTL=50
182.22.59.229 からの応答: バイト数 =32 時間 =21ms TTL=50

182.22.59.229 の ping 統計:
    パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 11ms、最大 = 21ms、平均 = 17ms

```

インターネットアクセスなしの場合

```python
>>> proc = subprocess.run(["ping","yahoo.co.jp"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> print(proc.stdout.decode("cp932"))
ping 要求ではホスト yahoo.co.jp が見つかりませんでした。ホスト名を確認してもう一度実行してください。
```

返り値に「見つかりません」が含まれる場合に、インターネットアクセスなしと判定することにしました。
ここは端末の言語とかによると思います。

```python
def is_ping_ok():
    proc = subprocess.run(["ping", "yahoo.co.jp"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    ret = proc.stdout.decode("cp932")
    if "見つかりません" in ret:
        return False
    else: return True
```

## ネットワーク再起動
インターネットアクセスなしになっていた場合、下記コマンドでネットワークの再接続を試みます。
コマンドの詳細は[この記事](https://qiita.com/mindwood/items/22e0895473578c4e0c7e)を参考にしました。


```
> netsh wlan disconnect
インターフェイス "ワイヤレス ネットワーク接続" の切断要求が正常に完了しました。

> netsh wlan connect name="接続したいSSID"
接続要求が正常に完了しました。
```

pythonで呼び出すと下記のようになります。
接続完了しないまま次の処理へ移らないよう、sleepを入れてます。

```python
def restart_network():
    subprocess.run(["netsh", "wlan", "disconnect"])
    subprocess.run(["netsh", "wlan", "connect", 'name="接続したいSSID"'])
    time.sleep(5)
```


# まとめ
突然の「インターネットアクセスなし」と戦うすべを紹介しました。

もっとスマートなやり方募集してます。
WebAssemblyStudioを使ってブラウザ上で動くDxLibアプリを開発する

# WebAssemblyStudioへのリンク

- <https://nokotan.github.io/WebAssemblyStudio/index>
- 本家WebAssemblyStudioとの違いは [本家WebAssemblyStudio と何が違うか](#本家WebAssemblyStudio と何が違うか) を参照してください

# WebAssemblyStudio の概要

## WebAssemblyStudio を使うことでできること

- ブラウザ上で WebAssembly を使ったプログラム開発ができる統合開発環境
- すなわち, **ブラウザ上で C言語やC++ を記述し, そのC言語やC++ で書かれたプログラムをコンパイルし, 実行することができる**

## WebAssemblyStudio ではできないこと

- スマホ上で C/C++ ソースコードを編集して実行する
- インテリセンスを使う (C/C++ 用の言語サーバを JavaScript で実装する必要がある)
- デバッグ機能を使う (変数ウォッチ、ブレークポイントなど)

## 本家WebAssemblyStudio と何が違うか

- C言語やC++のコンパイルに emscripten を使用していること
- emscripten は OpenGL や OpenAL, SDL2 などの幅広いライブラリに対応している
- すなわち, OpenGL や OpenAL, SDL2 を使ったグラフィカルなアプリケーションさえ, Web上でコンパイルし, 実行することができる

# DxLibアプリケーションを動かしてみる [入門編]

## プロジェクトの作成

WebAssembly Studio 起動直後は、プロジェクトテンプレートの選択画面が表示されます。
このプロジェクトテンプレートのうち、"Hello DxLib in C++" を選んで、左下の Create をクリックしてください。

![CreateProject.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/e83f3508-fae4-a9c7-7bee-378f3cc4b21c.png)

## プロジェクトのビルドと実行

上部にある "Build & Run" をクリックすると、ソースファイルのコンパイルを行ったのち、右下のプレビューウィンドウにおいてアプリが実行されます。

![BuildProject.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/a23b981c-7c70-0432-d368-19da70ea1610.png)

![RunProject.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/76315bab-e5d3-f982-9207-9821ad70340e.png)

# プロジェクトを保存し共有する [入門編]

## プロジェクトをクラウド上に保存

上部にある "Fork" をクリックすると、プロジェクトのクラウド上への保存が開始されます。
下部の Output ウィンドウに Saved Project OK と表示されると保存完了です。

![SaveProject.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/d8506718-434a-c3e0-db12-b545f414bb31.png)

## プロジェクトを共有する

プロジェクトのクラウド上への保存を行った後、上部にある "Share" をクリックすると、
クラウド上に保存されたプロジェクトへのリンクと埋め込み用のリンクが表示されます。

![ShareProject1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/2479fa01-7933-3d59-1597-f08877a96f97.png)

![ShareProject2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158514/feb91e2f-da30-a6d5-4f39-ba2e7ce71662.png)

# フォントを描画する [発展編]

Module.preRun コールバックにおいて、仮想ファイルシステムにフォントファイルを保存し、実行時にその仮想ファイルシステムからフォントファイルを読み込まれるようにする必要があります。

<https://nokotan.github.io/WebAssemblyStudio/index?f=jot2c0a3cmi> を参考にしてください

```js
// main.html

var Module = {
  canvas: (function() {
    var canvas = document.querySelector('canvas');
    canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
    return canvas;
  })(),
  dynamicLibraries: ["DxLib.wasm"],
  preRun: function() {
    const fontUrl = getFileURL("src/07LogoTypeGothic7.ttf");
    console.log(fontUrl);
    FS.mkdir("/assets");
    FS.createPreloadedFile("/assets", "07LogoTypeGothic7.ttf", fontUrl, true, false);
  }
}
```
#TypeScript の三項演算子は、文字列が空の場合に false で判定されるようだ。というか javascript でも同じ挙動みたいですね。

```typescript


const a = ""
console.log(a ? "A PRESENT" : "A EMPTY") // A EMPTY

const b = "B"
console.log(b ? "B PRESENT" : "B EMPTY") // B PRESENT

// js
//
// var a = "";
// console.log(a ? "A PRESENT" : "A EMPTY");
// var b = "B";
// console.log(b ? "B PRESENT" : "B EMPTY");



```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3020








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
lamda, api gateway使って、クライアントに値を返すなど

主に自分用メモ。

client->api gateway->youtube apiとかやりたい。

参考: [Amazon API Gateway とは?](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/welcome.html)

# まずlamda, api gaytewayを触ってみる

下記を見ればだいたいわかる。
[ゼロから作りながら覚えるAPI Gateway環境構築](https://dev.classmethod.jp/cloud/aws/getting-start-api-gateway/)

lamdaでのコードをローカルで作る際にはこちらを参考にした。
https://qiita.com/toshihirock/items/d28505442526e0ae7793

# 次にapi gateway->youtube apiをやってみる
ココやる上で、手元ではうまくresponse返ってきてるが、lamdaのところではresponseがnullになってて、なんでだろうとしていた。
結論は、event handlerが非同期的に処理される？ので、promiseとかでちゃんと作って値を返さないとだめだった。

youtube用には下記のnpmを利用した。
https://github.com/nodenica/youtube-node

外から叩いてみて、値が返ってたらOK！
文字列のエンコード・デコードを瞬殺するencodeMaxを作りました

![ezgif-7-09b26e7fce74.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30743/6fa95811-a1df-268b-31b6-b19cf4e0ed7d.gif)
[encodemax.com](https://encodemax.com/)

文字列のエンコード・デコードについては、「URLエンコード オンライン」みたいにググったらなんぼでもツールが出てくるのですが、だいたいどこのサイトも、「文字列を入力して変換をクリック」ってそのクリックする手間がイラッとしません？
あげくサーバサイドに通信しにいってHTTPの応答を待つ時間とかもうほんとに無駄！

あと、「URLエンコード・デコードができるサイトです」とか、それしか出来ないんかーい！どうせどれも似たような処理なんだから一つのサイトで出来たっていいじゃん。

よく働くコンピュータの代わりにぼくがどんどん怠惰になった結果、そんなふうに今あるサイトが不便に感じるようになってきたので、文字列を入れたら、その瞬間にエンコード・デコードを一通り試して結果が出力されるサイトというのを作りました。

[encodemax.com](https://encodemax.com/)

# 構成

ソース: [github.com/mogya/encodemax](https://github.com/mogya/encodemax)

たった１ページしかないのに[Nuxt.js](https://nuxtjs.org/)でgenerateした(だって楽だし)ものを[Netlify](https://www.netlify.com/)でホスティングしています。

ユーザーさんの入力をv-modelのバインディングで変数につっこんで、エンコード・デコードのロジックをcomputedで書いておけば、入力が更新されるたびに勝手に演算されて結果が更新される感じですね。

```vuejs
<textarea v-model="original_code" 
```
```vuejs
  <label>
    Base64 Decode
  </label>
  <input type="text"
    :value="base64_decode" />
```
```vuejs
computed: {
  base64_encode: function(){
    return window.btoa(unescape(encodeURIComponent(this.original_code)))
  },
```

あと演算結果欄は、余計な編集ができると使いづらいので、read-onlyにしつつ、こういうコードを付けておくことで、タップした瞬間全選択状態になって、ctrl+Aを押さなくていいようにしてあります。

```vuejs
  methods: {
    on_click: function(event){
      event.target.select();
    }
```
![onclick.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30743/487d710d-0386-4bd7-02c6-880123cd64c8.gif)

よかったら使ってみてください。

[encodemax.com](https://encodemax.com/)
Docbaseでタグ設定済み/未設定の条件でメモを検索する

情報共有ツール[Docbase](https://docbase.io/)で、「タグ設定済み（タグあり）」および「タグ未設定（タグなし）」の条件でメモを検索する際のオプションを確認してみた。

## タグ設定済み
タグが設定されている（何らかのタグが１つ以上付与されている）メモを検索するオプション

- `-missing:tag`

![image.png](https://image.docbase.io/uploads/433a4062-681a-482d-9c83-8cc85f74a1a6.png)

## タグ未設定
タグが設定されていない（タグが１つも付与されていない）メモを検索するオプション

- `missing:tag`

![image.png](https://image.docbase.io/uploads/5e483991-920e-4c04-a897-a4ba708dc436.png)

## 参考
- https://help.docbase.io/posts/59432

以上
#TypeScript で、はてなマーク二個のあいつは、値が null か undefined の場合にだけ、後ろが評価されるみたいだ。

```

console.log("A" ?? 'NULL OR UNDEFINED') // A
console.log(1 ?? 'NULL OR UNDEFINED') // 1

console.log(true ?? 'NULL OR UNDEFINED') // true
console.log(false ?? 'NULL OR UNDEFINED') // false

console.log(null ?? 'NULL OR UNDEFINED') // NULL OR UNDEFINED
console.log(undefined ?? 'NULL OR UNDEFINED') // NULL OR UNDEFINED


// js version
//
// var _a, _b, _c, _d, _e;
// console.log((_a = "A", (_a !== null && _a !== void 0 ? _a : 'NULL OR UNDEFINED'))); // A
// console.log((_b = 1, (_b !== null && _b !== void 0 ? _b : 'NULL OR UNDEFINED'))); // 1
// console.log((_c = true, (_c !== null && _c !== void 0 ? _c : 'NULL OR UNDEFINED'))); // true
// console.log((_d = false, (_d !== null && _d !== void 0 ? _d : 'NULL OR UNDEFINED'))); // false
// console.log((_e = null, (_e !== null && _e !== void 0 ? _e : 'NULL OR UNDEFINED'))); // NULL OR UNDEFINED
// console.log((undefined !== null && undefined !== void 0 ? undefined : 'NULL OR UNDEFINED')); // NULL OR UNDEFINED

```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3018








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Zabbixとfluentdでログからアクセス数と平均レスポンスタイムを取得

# 背景
Zabbix単体でログからレスポンスタイムを計測をしたかったのですが、以下で試したところ問題があったためfluentdと連携して実装することにしました。
https://qiita.com/_zaiko/items/c941594483364a8dc6a8

# 概要
Zabbixとfluentdを使用してログから以下を取得する。

- 平均応答時間
- 最大応答時間
- アクセス回数

fluentdからZabbixに直接データ登録する方法とzabbix_senderコマンドで登録する元ファイルを作る2パターンの方法で実装する。集計されたデータはログに記載されている時間ではなく、fluentdがデータ取得したタイミングをもとに集計する。
![chart2 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443775/6e98d3b7-360a-c9f5-6d68-ad7bba9356b4.png)


# 構築環境
centos 7
Zabbix 4.2
fluentd 1.9.2 

# 構築方法
## 0. Apacheでレスポンスタイムを表示
以下と同じ実装。
https://qiita.com/_zaiko/items/c941594483364a8dc6a8#0-apache%E3%81%A7%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%92%E8%A1%A8%E7%A4%BA

## 1. Zabbixの設定
以下のアイテムを作成する。

### アクセス数
```
・名前: ApacheResponseTime_COUNT (任意)
・タイプ: Zabbixトラッパー
・キー: apache.response.num
・データ型: 数値(整数)
・単位: 回
```

### 最大値
```
- 名前:  ApacheResponseTime_MAX (任意)
- タイプ: Zabbixトラッパー
- キー: apache.response.max
- データ型: 数値(浮動小数点)
- 保存前処理: 乗数、0.000001
```

### 平均値
```
- 名前: ApacheResponseTime_AVG (任意)
- タイプ: Zabbixトラッパー
- キー: apache.response.avg
- データ型: 数値(浮動小数点)
- 保存前処理: 乗数、0.000001
```

## 2.fluentdの構築
### インストール 
fluentdのバージョンは 1.9.2 を使った。古いもので試したところ内蔵されているrubyのバージョンが古くてプラグインが動作しなかった。

```
## インストールとsystemd設定
curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent3.sh | sh
systemctl enable td-agent
systemctl start td-agent

## 稼働確認
echo '{"setup test":"hello"}' | /opt/td-agent/embedded/bin/fluent-cat debug.test

## td-agent.log に以下出力があればOK
tail /var/log/td-agent/td-agent.log
2020-03-15 14:42:24.983374117 +0900 debug.test: {"setup test":"hello"}

## プラグインの追加
/opt/td-agent/embedded/bin/fluent-gem install fluent-plugin-numeric-monitor fluent-plugin-zabbix
 systemctl restart td-agent

## 一時ファイル出力用ディレクトリ作成
mkdir -m 755 /var/log/fluent
```

### 設定
/etc/td-agent/td-agent.conf に以下を追記する。

```
## ログからデータを抽出する設定
<source>
  @type tail
  path /var/log/httpd/access_log,/var/log/httpd/access_log-%Y%m%d
  read_from_head true
  tag apache.access
  pos_file /var/log/fluent/access_log.pos
# 時間のフォーマット。日付と時間を_でつないでいたり一般的でないかもしれないので必要に応じて修正してください。
  time_format %Y/%m/%d_%H:%M:%S %z
# データとして、timeとresponse_timeを抽出する。
  format /^time:(?<time>[^\t]*).*response_time:(?<response_time>[0-9]*)$/
</source>

## 抽出したデータを集計する
<match apache.access>
  @type numeric_monitor
  @label @monitor_result
  tag monitor.duration
# 1分単位で集計
  unit minute
  aggregate all
  monitor_key response_time
</match>

## データをZabbixに登録する
<label @monitor_result>
  <match monitor.duration>
  @type zabbix
# Zabbix サーバのIP
  zabbix_server 127.0.0.1
# ホスト名。Zabbix上でアイテムを作成したホストと同じである必要がある。
  host ${hostname}
# add_key_prefix + name_keys がZabbix上で作成したアイテムのキーとなるようにする。apache.response.avgなど。
  add_key_prefix apache.response
  name_keys avg,num,max
  </match>
</label>

```
Google認証（ManagementAPI利用時）にて「idpiframe_initialization_failed 」エラー

Google Management APIを使うために、JavaScriptのクイックスタート「HelloAnalytics.html」では普通に取得に成功。

しかし、Laravelに移管して試すと、なぜかresponse.errorで「idpiframe_initialization_failed 」が帰ってくる。

調べるとcookieとかなんとか書いてある記事ばかりにぶつかるが、ブラウザ設定の問題であれば、なぜHelloAnalyticsではうまくいくのか問題があるので、調べていると「response.details」で詳細も調べられる模様。

すると、「Not a valid origin for the client: http://localhost:8000 has not been whitelisted for client ID 445466545626-no2p05n4ehh5f2q8ria3loh78ddh6r1k.apps.googleusercontent.com. Please go to https://console.developers.google.com/ and whitelist this origin for your project's client ID.」と、要はDeveloper Consoleでホワイトリストに入れていないからダメというアラート。

いやいや、localhostはきちんと入力しているし、クイックスタートもlocalhostだけど動いてるやん！


https://stackoverflow.com/questions/43964539/google-api-not-a-valid-origin-for-the-client-url-has-not-been-whitelisted-for

この記事で解決。

どうも、Google認証の「OAuth 2.0 クライアント ID」は、一度あるポートで使うと、その後で違うポートで利用することはできないらしい。

クイックスタートはMAMP（ポート80）で動かしていて、LaravelはLaravelサーバ（ポート8000）で動かしたためNGだった模様。

新しくOAuth 2.0 クライアント IDを作り直したら、あっさり解決。
python でプロパティ呼び出し時にプライベート変数初期化したい

# やりたいこと
- メモリを大量に使うオブジェクトを格納するプライベート変数がある。
- 初期化処理を極力後回しにするため、初回の当該変数用プロパティ呼び出し時に初期化処理を走らせたい。

# やったこと
```python
class Hoge():
    @property
    def fuga(self):
        if not hasattr(self, '_fuga'):
            print("initialize!")
            self._fuga = "hello"
        return self._fuga
h = Hoge()
print(h.fuga)
print(h.fuga)
```
```sh
initialize!
hello
hello
```

<details>
<summary>コメント反映前の内容</summary>
<div>

```python
class Hoge():
    @property
    def fuga(self):
        if not hasattr(self, '_Hoge__fuga'): # 接頭辞に"_クラス名"を書くのがイケてない
            print("initialize!")
            self.__fuga = "hello"
        return self.__fuga
h = Hoge()
print(h.fuga)
print(h.fuga)
```

```sh
initialize!
hello
hello
```
</div>
</details>
npmパッケージ公開の手順

プログラミング歴半年の素人が書いています。

間違いのないようご自身でも良く調べた上でお願いいたします。

以下の記事を参考にさせていただきました。
https://qiita.com/TsutomuNakamura/items/f943e0490d509f128ae2


# npmにサインアップ

まずはnpmの公式サイトから、会員登録しましょう。

https://www.npmjs.com/


# npm ユーザの作成

ターミナルからユーザー情報を登録します。

```bash
$ npm set init.author.name "Ai Uehara"
$ npm set init.author.email "ai-uehara@example.com"
$ npm set init.author.url "http://qiita.com/aiuehara"
$ npm adduser  # 会員登録情報の入力
```


# npmパッケージの作成

`npm init`を実行すると`package.json`ファイルが作成され、npmパッケージとしてディレクトリを管理することができるようになります。

```bash
$ npm init
```


# npmパッケージに必要なプログラムを記述する

以下のようなファイル構成になります。
`index.js`と`package.json`が必須。
その他に必要なファイルがあればもちろん追加してOK。

```
作業ディレクトリ/
  +-- index.js
  +-- package.json
  +-- test/
    +-- test-index.js
```


# ライブラリの追加

自分のnpmパッケージに必要なライブラリをインストールするときは、以下のコマンドを使用することで、自動的に`package,json`に依存関係の記述が追加される。

```bash
$ npm i --save パッケージ名
```


## 開発環境のみで使用するライブラリの追加

テストなど開発環境のみで使用するパッケージは、以下のコマンドを使用する

```bash
$ npm i --save-dev パッケージ名
```


# ライセンスファイルの作成

公開するnpmパッケージのライセンスについて、明記しておきます。
誰でも自由に使用できるライセンス（MIT）として公開することが一般的です。

`LICENSE.txt`ファイルを作成し、[The MIT License](https://opensource.org/licenses/MIT)から丸々コピーします。

`Copyright <YEAR> <COPYRIGHT HOLDER>`の部分を、書き換えて保存します。


# npmに公開

```bash
$ git add -A
$ git commit -m "first commit"
$ git tag -a v1.0.0 -m "My first version v1.0.0"
$ git push origin tags/v1.0.0
$ npm publish ./
```


# バージョンアップするとき

一度npmに公開したパッケージをパージョンアップさせる時には、バージョン情報も合わせて更新する必要があります。

## パッチ バージョンアップ

```bash
$ npm version patch              # <- v1.0.0 からv1.0.1 にアップ
v1.0.1
$ git tag                        # <- git のtag も自動的に作成される
v1.0.0
v1.0.1
$ git push origin tags/v1.0.1    # <- ただし、git push まではやってくれないので、必要に応じて自分でgit push ...
$ npm publish ./                 # <- npm で公開
```


## マイナーバージョンアップ、メジャーバージョンアップ

```bash
$ npm version minor    # v1.0.1 からv1.1.0 にアップ
v1.1.0

$ npm version major    # v1.0.1 からv2.0.0 にアップ
v2.0.0
```
[Django] select文でDBの中身を確認する

# 前提
* DB: postgresql
* Shellアプリ: Terminal(Mac)

# dbshellを使用します

### 起動

※設定ファイルを環境ごとに使い分けていない場合、--settingsオプションは不要です。

```shell
$ python manage.py dbshell --settings <project name>.<settingsファイル名(拡張子なし)>
```

### テーブル一覧表示

```shell

dbname=> \dt
                         List of relations
 Schema |                 Name                 | Type  |   Owner
--------+--------------------------------------+-------+------------
 public | account_emailaddress                 | table | diary_user
 public | account_emailconfirmation            | table | diary_user
 public | accounts_customuser                  | table | diary_user
 public | accounts_customuser_groups           | table | diary_user
 public | accounts_customuser_user_permissions | table | diary_user
 public | auth_group                           | table | diary_user
 public | auth_group_permissions               | table | diary_user
 public | auth_permission                      | table | diary_user
 public | django_admin_log                     | table | diary_user
 public | django_content_type                  | table | diary_user
 public | django_migrations                    | table | diary_user
 public | django_session                       | table | diary_user
 public | django_site                          | table | diary_user
(13 rows)

```

### 指定したテーブルの全レコード表示

※django_siteはテーブル名

```shell

dbname=> select * from django_site;
 id |   domain    |    name
----+-------------+-------------
  1 | example.com | example.com
(1 row)

```
TypeScript プロパティの代入時チェックを行うデコレータを作った🥺

```ts


    @rule(age => 18 <= age && age <= 60, 'Value is out of range 18~60')

```

## プロパティの代入時チェックを行いたい

TypeScriptにはデコレータでプロパティの動作をカスタマイズできる機能がある。それを利用して、プロパティへの代入時に値チェックを行うデコレータを作成した。

https://github.com/kanamodesu/property-check-decorator/blob/master/rule.ts

使い方は代入時チェックを行いたいプロパティに`@rule`デコレータを付与する。
`@rule`デコレータは引数に条件式とエラーメッセージを取る。

例) Userクラスのageプロパティに代入される値を18以上60以下にしたい場合...

```ts
class User {
    @rule(age => 18 <= age && age <= 60, 'Value is out of range 18~60')
    age: number;

    name: string;

    constructor(age: number, name: string) {
        this.age = age;
        this.name = name;
    }
}
```

ageに条件式が成立しない値を代入するとエラーが発生します。
GitHub Desktopで新規リポジトリ作成後、Push/Pull/同期エラーが出たときの対処

# 概要
MacでGitHub Desktopクライアント([https://desktop.github.com/](https://desktop.github.com/))を入れて使用したところ、新しいプライベートリポジトリ作成時にPUSHができなかった。対処方法を調べたのでメモしておく。
結果を先に書くと、```.git/config```を修正し、https→SSHに変更することで認証が通るようになった。

# 環境
- macOS 10.15
- GitHub Desktop 2.3.1
- GitHub.comにはSSH鍵での認証を設定済

# 事象
1. GitHub Desktopから「New Repository」で作成し、何かCommitする。
1. 同期ボタンを押す。
<img width="940" alt="スクリーンショット 2020-03-15 14.58.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365444/64c75819-2b55-ada2-7559-680a74b56bd3.png">
1. PrivateでPublish Repositoryする。
<img width="452" alt="スクリーンショット 2020-03-15 14.58.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365444/7510c00b-25ec-2d8e-b27e-ffa5ac693c77.png">

1. エラーが発生せず、うまく動作しているように見えて、2回目以降に同期ボタンを押すと以下のエラーが発生する。
```Error
The repository does not seem to exist anymore. You may not have access, or it may have been deleted or renamed.
``` 
<img width="596" alt="スクリーンショット 2020-03-15 14.59.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365444/cfc11b29-523d-2d27-0f85-fd4cc8eb2d31.png">

- なお、リポジトリ自体は正常にGitHub.com側にできている
(ただし、初回コミットしたファイルはアップロードされていない）。このため、GitHub.comとの認証のやりとり自体には問題ないと思い、余計に原因がわからなかった。
- 先にGitHub.comで新規リポジトリを作成し、GitHub Desktopでcloneしてみたが、clone完了後に同じエラーが発生した。
- プライベートリポジトリだと発生した。パブリックリポジトリだと通常通り使える。

# 対処方法
```.git/config```の```remote origin url```を変更する  

```ruby:.git/config(変更前)
[remote "origin"]
        url = https://github.com/{USER_NAME}/{REPO_NAME}.git
```
```ruby:.git/config(変更後)
[remote "origin"]
        url = git@github.com:{USER_NAME}/{REPO_NAME}.git
```

もしGitHub.comにSSH接続できるよう設定していなければ設定する。公開鍵秘密鍵のペアを作成し、公開鍵をGitHub.comに登録する。  
参考：https://qiita.com/shizuma/items/2b2f873a0034839e47ce
error TS7053: Element implicitly has an 'any' type because expression of type '"A"' can't be used to index type ... #TypeScript 

```

const props : any = {}

props["A"] = "a"
props["B"] = { "b": "c"}

console.log(props["A"]) // a

console.log(props["B"]) // { b: 'c' }

// When not specify "any"
// raise error on type script build

// const props  = {}

// props["A"] = "a"
// props["B"] = { "b": "c"}


// $ tsc --strict props.ts
// ../.ghq/github.com/YumaInaura/YumaInaura/type-script/props.ts:8:1 - error TS7053: Element implicitly has an 'any' type because expression of type '"A"' can't be used to index type '{}'.
//   Property 'A' does not exist on type '{}'.

// 8 props["A"] = "a"
//   ~~~~~~~~~~

// ../.ghq/github.com/YumaInaura/YumaInaura/type-script/props.ts:9:1 - error TS7053: Element implicitly has an 'any' type because expression of type '"B"' can't be used to index type '{}'.
//   Property 'B' does not exist on type '{}'.

// 9 props["B"] = { "b": "c"}
//   ~~~~~~~~~~


// Found 2 errors.

// const props = {}

```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3017








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
ESP32-CAM(MicroPython)からサーバーへ画像をPOSTする

ESP32-CAMを手っ取り早く使うならArduino IDEを使えばいいけど

１、IO0/GNDをショートさせてスケッチを書き込み
２、書き込みが完了したら元に戻して起動

というのがなんとも面倒。

そこで登場するのがMicroPython。
>公式ドキュメントから引用
>>MicroPython は、さまざまなシステムおよびハードウェアプラットフォームで動作します。

ただ現在はESP32-CAMをサポートしていないのでカメラを使うためのライブラリがない。(カメラが使えるカスタムFWがあり今回はそれを使った)
さらにMicroPythonはPythonのサブセットなので一部サポートされていないメソッドやモジュールがある。

# requestsのMicroPython版 urequests
MicroPythonにはurequestというライブラリありほとんどrequestsと同じように使うことができる。
インストールも簡単にできる。

```
import upip
upip.install('urequests')
```

ただこの方法でインストールしたところ何故がメソッドが呼び出せなかった。
なのでMicroPython公式のリポジトリから引っ張ってきた物をesp32へ転送して使った。
[urequest.py](https://github.com/micropython/micropython-lib/blob/master/urequests/urequests.py)
esp32への転送にはampyを使うと簡単。

```
# ampyのインストール
$ pip install adafruit-ampy

#esp32へのファイル転送
$ ampy -p /dev/tty.<環境に合わせて> put <ファイル>
```

当初はPythonのrequestsを使う時と同じように、

```
urequests.post(url, files={'image': open('画像ファイル', 'rb)})
```
で行けるかと思っていたけどurequestsにはfilesがない。

いろいろ調べた結果、一度JSONにすることで行けそうだとわかった。

```
buf = camera.capture()
img_byte = base64.b64encode(buf)
img_json = ujson.dumps({"image": img_byte})
res = urequests.post(url, data=img_json)
```

こちらの記事を参考にしました。
[Pythonで画像データをJSONにしてネットワーク越しに送受信する](https://qiita.com/Motonaga/items/8da21f52e379469d744b)

受け取ったサーバー側(Flask)での処理はこんな感じ

```
data = request.data.decode('utf-8')
data_json = json.loads(data)
image = data_json['image']
image_dec = base64.b64decode(image)
data_np = np.frombuffer(image_dec, dtype='uint8')
decimg = cv2.imdecode(data_np, 1)
cv2.imwrite(filename, decimg)
```

とりあえず「ESP32-CAMで撮影した画像をPOSTする」という目的は果たせた。
作ったものはこちら↓
[ESP32-CAM_ImagePost](https://github.com/tkinjo1985/ESP32-CAM_ImagePost)
RuboCopのAbcSizeチェックの対応

Rubyの静的コード解析をやってくれるRuboCopをRails開発に導入しました。そこで発生したAbcSizeチェックについての作業メモ。

## AbcSizeとは
実装したメソッドに対してRuboCop君が計算してくれるスコア。
以下の3つのカウントが評価対象。

- Assignment : 代入
- Branch : メソッド呼び出し
- Condition : 条件

デフォルトで15を超えると警告が出て、もっとスコア下げてねと言われる。

## 警告が出たメソッド
ユーザーのサインイン機能を担う、こちらの`SessionsController.create`。

```sessions_controller.rb
def create
  @user = User.find_by(email: params[:session][:email].downcase)
  if @user&.authenticate(params[:session][:password])
    # ユーザーログイン後にユーザ情報のページにリダイレクトする
    log_in @user
    params[:session][:remember_me] == '1' ? remember(@user) : forget(@user)
    recdirect_back_or @user
  else
    # エラーメッセージを作成する
    flash.now[:danger] = 'Invalid email/password combination'
    render 'new'
  end
end
```
出た警告はこちら。
> Assignment Branch Condition size for create is too high. [<2, 19, 4> 19.52/15] (convention:Metrics/AbcSize)",

どうやらスコアは19.52らしく、評価項目毎だとこうなってる。

- Assignment => 2
- Branch => 19
- Condition => 4


## 対策
...とはいえ現状可読性は問題ない(主観)し、メソッド抽出が必要なほどロジックは複雑ではないので、AbcSizeチェックの基準値を調整しておく。

```yml:.rubocop.yml

Metrics/AbcSize:
  Max: 20
```

## おわりに
デフォルトの15を下回れるような解決方法があれば後ほど更新したい。

ちなみにRuboCop自体の`.rubocop_todo.yml`では基準値が18になっているという...

https://github.com/rubocop-hq/rubocop/blob/b10f7b63b2d1b4d71cc80661e30db569e7079237/.rubocop_todo.yml#L9-L11
【今日のエラー】クラスとインスタンス

railsの勉強の際、あまりにもインスタンスの理解が浅かったのでRubyの復習をしてきました。

#クラスとインスタンス
簡単にまとめると、クラスという設計図をまず作ることによってその設計図からいくらでもインスタンスを生成することができる。

イメージとしては設計図から大量の実物が生成されるイメージ。
例えば

```ruby_test.rb
class Tanaka
attr_accessor :name, :age

def initialize
    self.name = '田中'
    self.age = 10
end

  
  def introduce(personal_name)
    puts "#{self.name}が#{personal_name}を紹介して#{self.age}歳という年齢を教えた"
  end
end

tanaka_A = Tanaka.new

tanaka_A.introduce('佐藤')

p tanaka_A
```

**結果**
`田中が佐藤を紹介して10歳という年齢を教えた`

日本語的には非常に怪しいですが笑

田中というクラスから名前や年齢などのインスタンスが生成されそれを`tanaka_A.introduce()`とすることでintroduceメソッドを呼び出したりすることもできる。
かなり直感的に理解しやすかったです。

またこの`self.`の部分は下で書いた`tanaka_A`のインスタンスを指すということを理解しておくとなおよい。


間違ってたら指摘お願いします笑

##参考文献
[クラスメソッドの使い方まとめ](https://26gram.com/ruby-class-and-instance-methods)
Windows10でのdockerのやり方について

初心者の私がWindows10でdockerを始めた時の備忘録です。

いろいろなサイトを参考にしながら行ったのですが、はまってしまった箇所について備忘録として、残したいと思います。

①WSL2のインストールではまってしまった所
　Windowsのバージョンが低かったので、インストールが出来ませんでした。バージョンを最新にしたらできました。自分の場合 Windows10 HOMEなのですが、バージョンを2004にしました。

②Dockerではまった所
　インストールして、さて始めようかとしましたら、docker-compose upではまりました。

つまり、docker-compose upを入力しても、下記のエラーが出て動作しない。

【エラー】
ERROR: Couldn't connect to Docker daemon at http+docker://localunixsocket - is it running?
If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable.

 いろいろ調べまして、監理者権限(sudo)で行えば出来るとあったで、行ってみましたが出来ませんでした。同じエラーです。

入力したコマンド　→　sudo docker-compose up

さらにいろいろ調べて、、、ここにたどりつきまして、　ココ　→　https://yukituna.com/2201

sudo /etc/init.d/docker start　

をしたらできました。つまりdockerが起動していなかったみたいです。「かえるのほんだな」さんありがとうございました。

③ユーザー追加について
　補足なのですが、Dockerでのユーザーをグループに登録すればsudoを使わなくてもできるよと、あったのですが、今使っているユーザーは何？どうやって登録するのとなってしまったので、それについてです。

　今のユーザーは下記のコマンドで知ることができます。
　whoami

　今のユーザーが分からなくても下記のコマンドでユーザーに追加できます。

　sudo groupadd docker
 　sudo usermod -aG docker $USER

これで sudo を付けなくても、compose出来るようになりました。
kubernetesのrestartPolicyを理解する

## きっかけ

podを作成する際、コマンドラインとマニフェストファイルのどちらを使ったとしても`restart`や`restartPolicy`を使うことが多々ある。

よくよく調べてみると納得感があり、深淵なk8sへの理解に近づいたと感じたため記事にまとめてみる。

ちなみにkubectlではrestartを、マニフェストファイルではrestartPolicyを用いる。

## 公式ドキュメントを見てみる


[kubectl run](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#run)のコマンドによると

>The restart policy for this Pod. Legal values [Always, OnFailure, Never]. If set to 'Always' a deployment is created, if set to 'OnFailure' a job is created, if set to 'Never', a regular pod is created. For the latter two --replicas must be 1. Default 'Always', for CronJobs Never.

ざっくり翻訳してみると

- kebectl runによってpodを作成する時のrestart policy
- 引数はAlways, OnFailure, Neverの3つ
- `--restart=Always`ならDeploymentが作成される
- `--restart=OnFailure`ならJobがが作成される
- `--restart=Never`なら通常のpodが作成される
- デフォルト値はAlwaysである
- CronJobsを作成する時は`--restart=Never`とする
- OnFailureかNeverを選択した場合は、kubectl run `replicas=1`とする必要がある

## やってみる

試しにコマンドで操作してみる。
まずはAlwaysを渡す。

```bash

$ kubectl run --restart=Always always-pod --image=nginx:alpine
deployment.apps/always-pod created

$ kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
always-pod-55b8f9df58-hwz2q   1/1     Running   0          2m1s

$ kubectl get deployment
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
always-pod   1/1     1            1           3m5s
```

確かにDeploymentとして作成された。

次にOnFailureを渡す。

```bash

$ kubectl run --restart=OnFailure onfailure-pod --image=nginx:alpine
job.batch/onfailure-pod created

$ kubectl get pods
onfailure-pod-75jd8           1/1     Running   0          29s

$ kubectl get job
NAME                        COMPLETIONS   DURATION   AGE
onfailure-pod               0/1           58s        58s
```

これもJobが作成された。

次にNeverを渡す。

```bash

$ kubectl run --restart=Never never-pod --image=nginx:alpine
pod/never-pod created

$ kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
never-pod                     1/1     Running   0          17s
```

普通のpodが作成された。

## 考察

なぜAlways, OnFailure, Neverという名前によってpod（の起動方法）が変わるのか考察する。

[kubernetesの公式ドキュメント](https://kubernetes.io/ja/docs/concepts/workloads/pods/pod-lifecycle/#restartpolicy)によると以下のように書かれている。

>PodSpecには、Always、OnFailure、またはNeverのいずれかの値を持つrestartPolicyフィールドがあります。 デフォルト値はAlwaysです。restartPolicyは、Pod内のすべてのコンテナに適用されます。 restartPolicyは、同じNode上のkubeletによるコンテナの再起動のみを参照します。 


他のドキュメントと突き合わせて考えると、

- 各ノードに存在するkubelet（ノードエージェント）がpodを定期的に監視する
- kubeletは、podのspecに記述されているコンテナが正常に実行されている状態に保つ
- その際にkebeletが読み取る情報の1つがpodのrestart policy

となる。

Alwaysであれば、kubeletは「podが常に動き続けている状態」を保証しようと振る舞うので、Deployment

OnFailureであれば、kubeletは「podに障害が発生した時や障害が発生した時に新しいpodを開始させる」ように振る舞うので、Job

Neverであれば、特にrestartする必要がないので通常のpodとなる
TypeScript ツメ将棋ならぬツメ型定義🥺

こんにちは

TypeScriptの型定義の文法を調べてるとき、こんな記法あったのか～と唸ったことが何回かあったので、型定義クイズを作ってみました。

全4問あります。
コード中の `???`に何を入力すべきか当ててみてください。

※TypeScriptのバージョンは3.8です。


## 問題

### 問1 難易度★★☆☆☆

`Dict`インタフェースが、`dict`, `dict2`共に型一致するよう???を埋めてください。

```ts

interface Dict { 
    ???: number | string;
}

const dict: Dict = {
    a: 100,
    b: 200
};

const dict2: Dict = {
    hello: 'world'
};
```

### 問2 難易度★★★☆☆

`shopList`の型は`Book`インタフェースの`shop`プロパティと同じ型です。
???を埋めて、`shopList`に正しい型を指定してください。

```ts
interface Book {
    author: string;
    price: number;
    shop: {
        name: string;
        sales: number;
    }[];
}

const shopList: Book??? = [{
    name: 'BookOn',
    sales: 123
}, {
    name: 'Yafoo',
    sales: 100
}];
```

### 問3 難易度★★★★☆

UserValidFunc2の???を埋めて、UserValidFuncと同じ型にして下さい

```ts
interface User {
    name: string;
    age: number;
    tag: string[];
}

type UserValidFunc = {
    name: (p: string) => boolean;
    age: (p: number) => boolean;
    tag: (p: string[]) => boolean;
}

type UserValidFunc2 = {
    [???]: (p: ???) => boolean;
}

```

### 問4 難易度★★★★★

UnArray<T>は指定された型Tの配列でない型を返す型

例) UnArray<string[]> === string

```ts
type UnArray<T> = ???;

const n: UnArray<number[]> = 1;
const s: UnArray<string[]> = 'str';
const b: UnArray<boolean[]> = false;
```

## 正解

### 問1

```ts
interface Dict { 
    [key: string]: number | string;
}
```

**インデックスシグネチャ**を使う
参考) https://typescript-jp.gitbook.io/deep-dive/type-system/index-signatures#indekkusushigunechawosuru

- インタフェースのプロパティを定義する際は、通常`プロパティ名: 型名;`と定義します、が`[key: キーの型名]: 型名;`と定義することで、任意のプロパティに対する型指定を行えます。

### 問2

```ts

const shopOnly: Book['shop'] = [{
    name: 'BookOn',
```

**Lookup Types**を使う
参考) https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#keyof-and-lookup-types

- `型名['プロパティ名']`でプロパティの型を取得できる。


### 問3

```ts

type UserValidFunc2 = {
    [P in keyof User]: (p: User[P]) => boolean;
}
```

**Mapped Types**を使う
参考) https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types

#### Mapped Types の展開の説明

```ts
[P in keyof User]: (p: User[P]) => boolean;

↓ 1) 'keyofが展開される' keyof User -> ('name' | 'age' | 'tag')

[P in ('name' | 'age' | 'tag')]: (p: User[P]) => boolean;

↓ 2) 'in で各プロパティ名がPに展開される'

['name']: (p: User['name']) => boolean;
['age']: (p: User['age']) => boolean;
['tag']: (p: User['tag']) => boolean;

↓ 3) '整理する'

name: (p: string) => boolean;
age: (p: number) => boolean;
tag: (p: string[]) => boolean;
```

### 問4

```ts
type UnArray<T> = T extends (infer R)[] ? R : never;
```

- type定義の右辺で`extends`を記載すると、型を継承しているかで3項演算子的な条件分岐を行うことができる。
- 条件式で`infer Hogehoge`を記載すると型推論が働いたうえ、3項演算子の返却部分で参照できる。

参考) https://log.pocka.io/posts/typescript-promisetype/
GoogleAPIの認証で「Permission denied to generate login hint for target domain.」エラーの解決

自分用メモ。

Google APIsの「認証情報」にて、「OAuth 2.0 クライアント ID」を作りローカルで動かすも、「Permission denied to generate login hint for target domain.」というエラーで繋がらない。

ううむ、クイックスタートでサンプルをまんま動かした時は動いたのに。

https://stackoverflow.com/questions/36020374/google-permission-denied-to-generate-login-hint-for-target-domain-not-on-localh

この記事のおかげで解決。

Google認証は、「127.0.0.1」というIPアドレスは認めておらず、「actual urls」というらしい？いわゆるaaa.jpやbbb.comといった形式でないとエラーを返す模様。


クイックスタートでは「localhost」でやっていたが、今回は「127.0.0.1」でやってしまっていたことが原因。

「localhost」にアドレスを変えるだけで、すんなり解決。
Vimの定義元ジャンプをctagsからany-jump.vimに乗り換えた

# 概要
長らくvimの定義元ジャンプにはctagsを使っていましたが、any-jumpが良さげだったので乗り換えました

## 必要環境

- `vim 8.2` または `neovim 0.4+`
- `ripgrep 11.0.0+` または `ag`

## 使い方

ジャンプしたい文字の上で `:AnyJump` を実行するだけ。
![スクリーンショット 2020-03-15 15.03.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68643/078dba17-5ed9-9f43-8f7f-48171967017f.png)

実行するとpopupウィンドウが表示されて、定義されている場所と使用されている場所の一覧が表示されるので、ジャンプしたい場所を選択。

## GitHubリポジトリ
[pechorin/any-jump.vim](https://github.com/pechorin/any-jump.vim)
[Git]Forkしたブランチを最新にする方法

#はじめに

[リポジトリをフォークする](https://help.github.com/ja/github/getting-started-with-github/fork-a-repo)と[フォークを同期する](https://help.github.com/ja/github/collaborating-with-issues-and-pull-requests/syncing-a-fork)
を参考にして書いています！:sunny:


#方法


:sunny:upstreamに本家のリモートを登録

```
$ git remote add upstream https://github.com/cakephp/docs.git
```

※`https://github.com/cakephp/docs.git`はFork元のURLに変更してください。

※含まれているかの確認は`$ git remote -v`のようにしてください。以下画像はサンプルです。

|<img width="438" alt="スクリーンショット 2020-03-15 14.50.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133940/2d3fa966-37f8-49e0-da43-67f3c20f2c8a.png">|
|:-:|


:sunny:本家の内容を持ってくる。
:man_tone3:今回の元のブランチが私は`4.x`なのでupstream/4.xに入ってくるらしい、、、

```
$ git fetch upstream
```


:sunny:あとは自分の最新にしたいブランチのところで持ってきたものをマージする。今回は4.xの部分で以下コマンドを打った感じです！

```
$ git merge upstream/4.x
```

※`4.x`のところは人それぞれです。

|<img width="363" alt="スクリーンショット 2020-03-15 15.04.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133940/2ec05a2a-5f15-eaf4-51e5-98e0f81e469d.png">|
|:-:|

なんとなくいらない部分隠してみました！


#最後に
終わりです！
Azure Functions[HTTP trigger]を試してみた

#はじめに
[Azure for Students](https://azure.microsoft.com/ja-jp/offers/ms-azr-0170p/)という学生に優しいサービスがあった！！
だからAzureをいろいろ試してみることにした！
第1弾として、Azure Functions
※自身が今後利用するためのメモ書き

#Azure Functions
##関数アプリからサービスを作成
Azureのポータルメニューから、「関数アプリ」を選択する。
<img width="1225" alt="スクリーンショット 2020-03-15 14.30.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505689/35cedd90-8bcd-499e-888a-b79b63cc67ec.png">
左上の「追加」ボタンをクリックする。
<img width="1429" alt="スクリーンショット 2020-03-14 22.39.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505689/a95fcb19-77d9-2742-1607-19eecb0c13e0.png">
プロジェクトの詳細を設定する。
・サブスクリプション:Azure for Students
・リソースグループ:ない場合は新規作成
・関数アプリ名:任意の関数アプリ名を指定
・ランタイムスタック:使用する言語を選択(今回はNode.jsを選択)
・バージョン:ランタイムスタックのバージョンを選択
・地域:地域を選択する
「確認および作成」ボタンをクリックする。
<img width="1429" alt="スクリーンショット 2020-03-14 22.40.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505689/88c688c4-92e0-3674-3f8d-4933cf81813c.png">
作成後、真ん中上の「新しい関数」ボタンをクリックする。
<img width="1429" alt="スクリーンショット 2020-03-14 23.00.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505689/eeaf451b-28a7-fac2-ceaf-fc54bb313853.png">
今回は、「HTTP trigger」を選択する。
<img width="1429" alt="スクリーンショット 2020-03-14 23.01.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505689/5a7fe460-9dc5-239f-cccd-ef7990dd18bc.png">
function.jsonでnameプロパティを$returnに変更する。

```json:function.json
{
    "type": "http",
    "direction": "out",
    "name": "$return"
}
```

index.jsを次のようにする。

```javascript:index.js
module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');
    return {
        body: "Hello, world!"
    };
};
```

「実行」ボタンをクリックする。
<img width="834" alt="スクリーンショット 2020-03-15 14.56.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505689/2dce09e8-8818-1faa-37d3-7ea54e59da03.png">
そして、「</>関数のURLの取得」をクリックして、そのURLにアクセスして確かめる。

#おわりに
メモ書きのため、伝わりにくい部分があったら申し訳ありません。
アドバイスをコメントなどでもらえると助かります。