OmniAICreator/Qiita-1.07M huggingface dataset:
第02回　独自開発した「ニューロ型データベースモデリング Ver.1」　【学習】方法を考える

###
はじめに
---
【 ニューロ型データベースモデリング Ver.1 】とは

「脳を構成する神経細胞（neuron）が繋がり合って情報を司る」
という仕組み（ネイチャーテクノロジー）に着目し
私が独自で研究・開発 してきた「データベースモデリング」です。
使用する静的テーブルは「２個(２種類)だけ」なのでシンプルな構造となり結果的に基本メンテナンスフリー の 汎用データベースモデリング が出来上がりました。

詳しくは【 [開発の歴史](https://kuhen.org/ndb/?page_id=77)：2016-03-04～05　総務省「異能vation」協力・協賛企業マッチングイベントに「ニューロ型データベースモデリング」が選定される 】をご覧下さい。

###
【学習】機能を考える（一般的にも良くやる処理ですが）
---
「脳」の「神経細胞」同士が繋がりあっている画像を見ると繋がり合っているその線が太ければ太いほど【よく使う】ということではないのか？

それをデータベースの静的テーブルに実装するには
　　「太さ」＝「数値の大小」
だと考えた。

そこで新たに【リンクID使用回数】という「列」を追加し
識別名（ひな型名）【住所】で登録されている「自宅」と「実家」を開く度に
この「リンクID使用回数」をカウント（数値の追加）をしていけば
**【よく使う】**住所として以下の図だと「自宅」が**【記憶される】**。

![16.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567414/6cd061d2-0728-da9d-a7f0-a7723a8bbc0e.jpeg)

**例えば：　【勤務先】　情報が過去を含め　「３社」　あるとする**

現在は**「C社」**で勤務しているとする。
やはり「過去」の会社の「リンクID使用回数」の方が数値としては大きい。

**【現在】**の学習状態

| 入力項目      |       入力データ |    リンクID使用回数（降順）    |
|:-----------------|------------------:|:------------------:|
| 勤務先          |            B社(1982年-2000年) |       **883**       |
| 勤務先             |              A社（-1982年) |        48        |
| 勤務先             |              C社(2000年-) |        30        |

　
新たに【C社】を　これから【よく使う】「勤務先」
として**【学習させる】**　→　数値を 【　**10000**　】 **加算する**

**【最新】**の学習状態

| 入力項目      |       入力データ |    リンクID使用回数（降順）    |
|:-----------------|------------------:|:------------------:|
| 勤務先             |              C社(2000年-) |       **10030**        |
| 勤務先          |            B社(1982年-2000年) |       883       |
| 勤務先             |              A社（-1982年) |        48        |

###
【応用編】テーブルを【複数】繋げて「辞書学習」処理を考えてみた
---

例：　**お父さん**

**５個のテーブルをリンク**して行き「お父さん」にたどり着く

　**お　→　と　→　う　→　さ　→　ん**

| 入力項目      |       入力データ |    リンクID使用回数（降順）    |
|:-----------------|------------------:|:------------------:|
| 辞書「お」  →       |            と |       xxxxxx      |

　　　　　　　　　　　　↓

| 入力項目      |       入力データ |    リンクID使用回数（降順）    |
|:-----------------|------------------:|:------------------:|
| 辞書「おと」         |              う |       xxxxxx        |


　　　　　　　　　　　　↓

**「おとうさん」と「おとうふ」の優先順位**

| 入力項目      |       入力データ |    リンクID使用回数（降順）    |
|:-----------------|------------------:|:------------------:|
| 辞書「おとう」         |              さ |       50000        |
| 辞書「おとう」         |              ふ |       3000        |


　　　　　　　　　　　　↓


| 入力項目      |       入力データ |    リンクID使用回数（降順）    |
|:-----------------|------------------:|:------------------:|
| 辞書「おとうさ」         |              ん |      xxxxxx        |

　　　　　　　　　　　　↓


| 入力項目      |       入力データ |    リンクID使用回数（降順）    |
|:-----------------|------------------:|:------------------:|
| 辞書「おとうさん」         |              お父さん |              |

###
まとめ
---
【学習】方法として「リンクID使用回数（降順）」を利用してみました。
このモデリングは**１種類の静的テーブル**を沢山（無限に）リンクして処理が出来ることを今回の記事で知っていただければと思います。

「多くなりすぎたテーブル（正規化後）」は　→　「上下に連結（非正規化）」にしてしまえば良いと思います。


###
関連投稿記事
---
前回　[第01回　独自開発した「ニューロ型データベースモデリング Ver.1」で個人情報保護の簡単実装を考えてみた](https://qiita.com/kuhen-org/items/39b9af60800065af9185)

次回　[第03回　独自開発した「ニューロ型データベースモデリング Ver.1」　縦連結したデータの表示順（ソート順）を【 サブグループ 】で管理する](https://qiita.com/kuhen-org/items/d380a393fc934768b0a3)
APIのKeyをGithubに上げたくないのでしたこと（PHP）

Google Map APIを利用する際に、自分のAPI keyをGithubに上げたくないので、方法を探していたが、結局以下の方法で動いているのでよしとした。

APIへのアクセス部分は
`<script src="https://maps.googleapis.com/maps/api/js?key=<?php include("keys/googlemap.php"); ?>&callback=initMap"></script>
`

上記アクセス部分が書かれているファイルと同じ階層にディレクトリ「keys」をつくり、その中にファイル名「googlemap.php」でファイルを作成後、そのファイルの中にテキストで自分のAPI keyの値を書くだけ。

そのあと、.gitignoreファイルの中に「keys/」を追加。

以上
Qiita 表で文字数超過になったときerror

a marged list of Autosar abbreviation list v.3
https://qiita.com/kaizen_nagoya/items/b237af7a63b013115660

の表を作るとき、なぜかExcelからの貼り付けでは
markdownの表にならなかった。

そこで、

Copy Table in Excel and Paste as a Markdown Table
https://thisdavej.com/copy-table-in-excel-and-paste-as-a-markdown-table/

でcopy and pasteして作った表をqiitaに貼り付けると

![qiitqerror.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51423/4864f270-4085-e3af-4300-8df7c2d70f26.png)

と出た。

複数の空白を一つの空白に変換したら、保存できた。

下書き保存の際には、保存できても、qiitaに投稿のときは上記エラーがでることがわかった。

複数の空白を一つの空白にする置換のほか、
縦棒と空白を縦棒に
空白と縦棒を縦棒に
改行3つを2つに
変換して、空白、改行をできる限り少なくした。
### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
#### Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.
Docker(compose)にDjango開発環境を移行する際の備忘録

## Dockerfile

```dockerfile

FROM python:3.7
ENV PYTHONUNBUFFERED 1
WORKDIR /code
COPY requirements.txt /code/
RUN pip install --no-cache-dir -r requirements.txt
COPY ./code /code/.
RUN python manage.py migrate
```
- FROMでpython3.7環境を使用
- ENVでエラー出力抑制（らしい）
- WORKDIRで一時作業フォルダを指定
- WORKDIRにDockerfileと同じディレクトリに配置しているrequirements.txtをコピーする
- RUNでrequirements.txtにしたがってインストールを行う
- COPYでmanage.pyがあるディレクトリを丸ごとWORKDIR配下にコピー
- RUNでmigrateしておく

ハマりポイントとしては、WORKDIRへのファイルコピー。
Dockerfileと同じディレクトリにあるcodeディレクトリ(Djangoプロジェクト)を指定できずFile Not Foundを連発。
前提条件として、Dockerfileとrequirements.txt、codeディレクトリはすべて同じ階層に配置している。

## docker-compose.yml

```docker-compose.yml
version: '3'
services:
        web:
                build: .
                ports:
                        - "8000:8000"
                volumes:
                        - ./code:/code
                command: python3 manage.py runserver 0.0.0.0:8000
```
- versionは3を指定
- web:は一時的な名称として指定。
- build:でDockerfileの位置を指定。カレントディレクトリにあるので'.'を指定。
- ports:でDjangoのポートを指定。
- volumes:でカレントディレクトリにあるDjangoプロジェクトのディレクトリをコンテナ内の/codeにマウントする。マウントすることでvscodeなどから直接編集した内容がコンテナ上に反映される。
- command:でDjangoのWebサーバーを起動させる。引数のIPアドレスとポート番号は必要ないかもしれない。

## コマンド類

### Dockerコマンドをsudoなしで実行させる場合
```
$ sudo usermod -aG docker ユーザー名
$ newgrp docker
```
newgrp dockerを.bashrcなどに書いておくと楽になるかもしれない。

### イメージの削除
```
$ docker images
$ docker rmi イメージID先頭3桁
```
割り当てられているコンテナが存在する場合は-fをつけて強制的に削除する。

```
$ docker rmi -f イメージID先頭3桁
```

### コンテナの削除
```
$ docker rm コンテナID
```

### exited状態のコンテナ複数を一度に削除する
```
$ docker rm $(docker ps -a --filter 'status=exited' -q)
```

### コンテナにログインしてコマンドを実行したい場合
```
$ docker exec -it コンテナ名 /bin/bash
```
Alpine Linux（aarch64）に Docker ＆ docker-compose をインストールする方法

# 1. はじめに
今回は、自分自身への備忘録を兼ねて、Raspberry Pi にインストールしたAlpine Linux（aarch64）上に Docker ＆ docker-compose をインストールする方法を、お伝えしたいと思います。

- 参考：[Alpine Linux に Docker をインストールする手順](https://kmor1.blogspot.com/2018/11/alpine-linux-docker.html)

# 2. この記事を読んでできること
- Alpine Linux（aarch64）で Docker ＆ docker-compose を使えるようになる。

# 3. 注意事項
- 特になし。

# 4. 必要なもの
- Alpine Linux（aarch64）が動作しているホストOS環境（この記事では Raspberry Pi3B ＋ Alpine Linux（aarch64）を利用）
- インターネット環境

# 5. リポジトリの追加登録
- dockerをインストールできるようにするために、/etc/apk/repositoriesファイルにcommunityリポジトリを追加する。
- docker-composeをインストールできるようにするために、/etc/apk/repositoriesファイルにtestingリポジトリを追加する。
- 実際には、該当箇所をコメントアウト（#）を解除するだけでOKです。

```plaintext:コマンドプロンプト
// リポジトリの追加登録
# vi /etc/apk/repositories

＝＝＝
http://dl-cdn.alpinelinux.org/alpine/v3.11/main
#http://dl-cdn.alpinelinux.org/alpine/v3.11/community
#http://dl-cdn.alpinelinux.org/alpine/edge/main
http://dl-cdn.alpinelinux.org/alpine/edge/community
http://dl-cdn.alpinelinux.org/alpine/edge/testing
＝＝＝

```

# 6. dockerとdocker-composeのインストール
- Dockerをインストールします。
- Dockerだけの利用でよければ、以下のコマンドだけで完了です。

```plaintext:コマンドプロンプト
// インストール
# apk add docker docker-compose

// dockerのバージョン確認
# docker -v
Docker version 19.03.6, build 369ce74a3ce86a392e39e45d3960ce970fdfac97

// docker-composのバージョン確認
# docker-compose -v
docker-compose version 1.25.2, build unknown

// dockerの起動
# service docker start

// dockerの自動起動有効化
# rc-update add docker boot
```

# 7. dockerの動作確認

```plaintext:コマンドプロンプト
// dockerの実行（ハローワールド）
# docker run --rm hello-world
```

# 8. docker-composeの動作確認
- docker-compose.ymlファイルを作成し、ファイル保存する。

```yml:docker-compose.yml
version: "2"

services:
  app:
    image: hello-world

```

- docker-composeを実行する。

```shell:コマンドライン
// docker-compose.ymlファイルが存在することを事前確認
# ls
docker-compose.yml

// docker-composeを実行
# sudo docker-compose up
```

# 9. 参考：Dockerコマンド、docker-composeコマンド
- [（備忘録）Dockerコマンド](https://qiita.com/zono_0/items/7a25d283cd4b09d6ffb0)

# 10. おわりに
いかがでしたでしょうか？意外と簡単にDocker ＆ docker-composeをはじめることができたのではないかなと思います。
今回の記事が、みなさまの学習の参考になれば幸いです。

2020/02/23 TAKAHIRO NISHIZONO
FriendlyDesktop(Linux) can't boot

The SOM-RK3399 displayed `FriendlyElec`(that is the rogo before OS boot like `Android`) then nothing happen.
I guess the device couldn't boot. but I didn't find any data to solve the problem for friendlyDesktop OS.

So the way is Bold. just Flash FriendlyDesktop ROM again with AndroidTool_Release_v2.71 or more. that's the way I did.

After that the OS was boot without any problem.

Probably, it started when I changed all the permissions under /etc using `chmod -R 777 /etc`.
After that, a number of problems occurred, and the permissions under/ etc were changed many times by `chmod`. (I forgot 400 or 555 or 444 or other).

That is very ridiculous.

Probably, in linux, it is highly possible that the startup script is stored under /etc.
that is the reason the device couldn't boot I think.
zipfileの圧縮・展開

```py:1
import zipfile
import glob

with zipfile.ZipFile('test.zip', 'w') as z:
    for f in glob.glob('test_dir/**', recursive=True):
        z.write(f)
#test_dir以下をtest.zipというファイル名でzipfileに圧縮

with zipfile.ZipFile('test.zip', 'r') as z:
    z.extractall(path='zzz2')
#zzz2というディレクトリにtest.zipを展開
```

```py:2
import zipfile

with zipfile.ZipFile('test.zip', 'r') as z:
    with z.open('test_dir/sub_dir/sub_test.txt') as f:
        print(f.read())
#zipfileに圧縮されたtest.zipを展開することなく、sub_test.txtを出力
```
RstanにおけるCompilation Error : no such file or directoryの発生

##はじめに

確率的プログラミング言語にStanというものがあり、Rでstanを使うためにRrstanというインターフェースがあります。問題なく使えていたのですが、最近、突然、Compilation Error : no such file or directoryがでてしまいました。どうやらstanのコンパイルエラーのようです。Rとパッケージ群をアンインストールして、再インストールし直したのですが、症状は直りません。ubuntu版のRでは問題は発生しませんでしたので、どうやらwindows版の問題かもしれません。

## 環境
・windows10pro
・R version3.6.2
・RStudio Version 1.2.5033
・rstan 2.19.3

##症状
このようなエラーが出て止まります。
Error in compileCode(f, code, language = language, verbose = verbose) : Compilation ERROR, function(s)/method(s) not created!
g++.exe: error: Files/R/R-3.6.2/library/StanHeaders/include/stan/math/prim/mat/fun/Eigen.hpp: No such file or directory
・・以下省略・・

どうやらStanHeadersに問題がありそうです。

##解決
ググって調べたところ、日本語サイトにはなく、英語のサイトに、似たような症状で困っている事例がありました。
https://discourse.mc-stan.org/t/compilation-error-with-stanheaders-no-such-file-or-directory/13007

このサイトによると、どうやらstanheadersのversionsの問題のようです。
使っていたstanheadersのversionsは2.21になっていました。そこで、サイトにしたがって次のとおり再インストールを試みました、

```{r}
install.packages(c("rstan","StanHeaders"),type="source")
```

しかしながら、なぜかstanheadersのversionsのダウングレードはうまくいかず、インストールされませんでしたので、再びR、Rtoolsとパッケージをすべて消去、再インストールし、CRANを使わずに上記のコマンドを使ってパッケージを入れるとstanheadersのversions2.19.2が入り、無事に動くようになりました。
(パッケージは、プログラムフォルダ内のRフォルダ毎削除しました）

##終わりに
エラーの原因はstanheadersとrstanのversionsの相性のようです。なぜかubuntu版のRでは最新のstanheadersのversionsでも問題はありませんでした。しかし、パッケージをアップデートさせるときは気を付けた方がいいですね  :sweat:

##追記
最近、R version4.0.2にアップデートさせたら、

```{r}
エラー: サイズ 14037.2 Gb のベクトルを割り当てることができません
```
と謎のエラーがでて、再び Stanが走らなくなりました。解決は結局、全てアンインストールの上、パッケージもフォルダ毎削除して、完全にRを消してしまってから、R version3.6.3　Rtools35　Rstudio　の順に再インストールしてから、
install.packages(c("rstan","StanHeaders"),type="source")　により（注：結構時間がかかる）治りました。
windows版RでRstanを動かそうと思うと、まだ最新版(version4.0.2）にはアップデートしない方がいいのかもしれません。

**2020.8.18現在**
windows版R(version4.0.2）でパッケージ‘StanHeaders’ version 2.21.0-6にアップデートできます。
これでwindows版R(version4.0.2）でRstanは**正常に動きました！**

---


また、Ubuntu版のRの話になりますが、(OS:Ubuntu 18.04.4 LTS)最新のR version4.0.2にしてRstanをインストールしようとすると次のような症状が発生します。

```
The downloaded source packages are in
	‘/tmp/RtmpatLnqJ/downloaded_packages’
> library(lattice, lib.loc = "/usr/lib/R/library")
 エラー: package or namespace load failed for ‘lattice’:
 package ‘lattice’ was installed before R 4.0.0: please re-install it
```
もともとインストールされているSystem libraryであるlatticeがversion4.0に対応していないことが原因！？そんなことがあるの？
これだけ別途、User libraryにcranからインストールすると、正常にRstanもインストールでき、動きました。（従ってlatticeはSystem libraryとUser libraryで、２つ存在することになります）
なんじゃ、こりゃ
あなたの言葉をイクラちゃんが喋るとどうなるのか？

# はじめに
毎週日曜よる6時30分にフジテレビで放送されている「サザエさん」というアニメの登場人物に「イクラちゃん」というキャラクターがいます。

イクラちゃんは年齢が1歳半くらいで基本的に以下の3つの言葉しか話すことができません。[^1] [^2]

- ハーイ
- チャーン
- バブー

では、私たちが普段話している言葉をイクラちゃんが話すとどの言葉を発するのか。
今回は一説として、類似度を基に推定してみようと思います。

# 実装方法
[COTOHA API](https://api.ce-cotoha.com/)の[類似度算出API](https://api.ce-cotoha.com/contents/api-all.html)を利用しました。

このAPIはテキストに含まれる単語の意味情報を用いて類似度を算出しているため、異なった単語を含むテキスト間の類似性も推定することができるそうです。

そのため、イクラちゃんがそれぞれの言葉をどのような意味で使い分けているかを含めて推定できそうですね。

<details><summary>ソースコードはこちら</summary>
<div>
CLIENT_ID, CLIENT_SECRETはご自身で取得したものをご利用ください。

```python
import requests
import json
import numpy as np

BASE_URL = "https://api.ce-cotoha.com/api/dev/nlp/"
CLIENT_ID = ""
CLIENT_SECRET = ""

def get_token(client_id, client_secret):
    token_url = "https://api.ce-cotoha.com/v1/oauth/accesstokens"
    
    headers = {
        "Content-Type": "application/json",
        "charset": "UTF-8"
    }

    data = {
        "grantType": "client_credentials",
        "clientId": client_id,
        "clientSecret": client_secret
    }
    r = requests.post(token_url,
                      headers=headers,
                      data=json.dumps(data))
    
    return r.json()["access_token"]

def similarity(s1, s2, access_token):
    base_url = BASE_URL
    
    headers = {
        "Content-Type": "application/json",
        "charset": "UTF-8",
        "Authorization": "Bearer {}".format(access_token)
    }
    
    data = {
        "s1": s1,
        "s2": s2,
        "type": "kuzure"
    }
    
    r = requests.post(base_url + "v1/similarity",
                      headers=headers,
                      data=json.dumps(data))
    return r.json()["result"]["score"]

def said_ikurachan(sentence):
  access_token = get_token(CLIENT_ID, CLIENT_SECRET)
  ikurachan_words = ["ハーイ", "チャーン", "バブー"]
  similarity_arr = []
  for word in ikurachan_words:
    similarity_arr.append(similarity(sentence, word, access_token))
  return ikurachan_words[np.argmax(np.array(similarity_arr))]
```
</div>
</details>

# 実行結果
まずは挨拶系から

```python
said_ikurachan("おはようございます", access_token)
# => 'ハーイ'

said_ikurachan("こんにちは", access_token)
# => 'ハーイ'

said_ikurachan("こんばんは", access_token)
# => 'ハーイ'
```

挨拶は「ハーイ」でよさそうですね。

次に、名言がどのようになるかを見てみましょう。

```python
said_ikurachan("天才とは1%のひらめきと99%の努力である", access_token)
# => 'チャーン'

said_ikurachan("Stay hungry, stay foolish", access_token)
# => 'チャーン'

said_ikurachan("地球は青かった", access_token)
# => 'チャーン'
```

名言は「チャーン」でよいかもしれません。

最後に、不満がどのようになるかを見てみましょう。

```python
said_ikurachan("なんであいつのために俺が苦労しないといけないんだ")
# => 'バブー'

said_ikurachan("本当にやる意味あるのかなこれ")
# => 'バブー'

said_ikurachan("なんで自分だけこんな目に遭わないといけないのか")
# => 'バブー'
```

不満は「バブー」となりそうですね。

# おわりに
チャーン。チャーン。

（今回は私たちが発している言葉がイクラちゃんだったらどの言葉を発するかについて、COTOHA APIの類似度算出APIを利用して推定しました。あくまで一説ですのでこれが真実かどうかは分かりませんが、参考になれば幸いです。)

# 参考
 [社会性フィルターでSNS時代を生き抜く](https://qiita.com/karasuyama/items/7bad0d4e46d80af4e33f)

[^1]: [公式サイト](http://www.sazaesan.jp/charactors-2.html#content)の波野イクラの項より
[^2]: 作品番号No.2433からNo.3991までは別の言葉を喋る回があったそうです。
Firebaseでお手軽サーバレスアプリ（Realtime Database+CloudFunctions+Cloud Messaging+Android(kotlin)+iOS(swift)）その１

# はじめに
Firebaseを使ってモバイルアプリとそれをつなぐバックエンドを含むシステムを構築します。
できるだけコードを書かず、構築の手間をかけずにどこまでできるかを試します。
その１ではfirebaseの設定とAndroidアプリアプリの準備を行い、Androidアプリからfirebaseのdbにアクセスする所までを行います。

# 全体像
![全体像.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577898/20c67c7d-d966-1af6-92c6-f8e347a501c8.png)


# 参考にした情報
https://qiita.com/Natsukii/items/c3d76b3fa2048f214aac

https://qiita.com/tetsukick/items/638501babc692ec55858

# firebaseの準備

上記のページを参考にしました

## プロジェクトを追加


https://console.firebase.google.com/?hl=ja

- プロジェクトの作成（1/3）
    - プロジェクトに名前を付ける

- プロジェクトの作成（2/3）
    - Googleアナリティクスを「有効」にする
　「有効にしない」選択も可能

- プロジェクトの作成（3/3）
    - Google アナリティクスの構成
　「Dafault Account for Firebase」を選択

## Realtime databaseを作成

- メニューから「Database」を選択
    - Cloud FirestoreまたはRealtime Databaseを選択可能 ここでは「Realtime Database」を選択

- Realtime Database のセキュリティ ルール
    - とりあえず実験なので、「テストモード」で開始を選択


# アプリの準備

- Create New ProjectでBasic Activityを選択
![アクティビティの選択_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577898/2847dd21-411a-f0d2-cc96-3123bad00821.jpeg)



    - ScrollViewを追加
    - ScrollViewにConstraintを設定
    - TextViewを追加
![ScrollViewの追加.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577898/42745333-958c-8e5f-2207-6644c434f97d.png)
- ToolsからFirebaseを選択
    - 「realtime database」
    - 「Save and retrieve data」
    - 「Connect your app to Firebase」
        - 先ほどWebでつくったプロジェクトを選択（ここで新規に作成も可能）

    - Add the Realtime Database to your app」
        - ダイアログの内容を確認し、「Accept Changes」
        - 「Write to your database」にあるコードをMainActivity.ktに追加

```kotlin:MainActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)

        fab.setOnClickListener { view ->

            val database = FirebaseDatabase.getInstance()
            val myRef = database.getReference("message")
            myRef.setValue("Hello, World!")            

        }
    }
```

## データが書き込まれたか確認

ボタンを押すとデータを書き込みます
FirebaseのコンソールからDBの内容を確認します![Screenshot_20200223-113718_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577898/7ca63f84-84fc-bbfb-1ccb-535ae2221fa6.jpeg)

「message:"Hello,World!"」と書き込まれていれば成功

![firebaseコンソール.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577898/08761f7a-15c5-9cc4-5660-cb284389e6ef.png)

# まとめ
今回書いたコードは3行です。しかもコピペ。それでここまでできちゃいました。
次回は、書き込んだデータを取得し、表示する所を実装します。

# このシリーズについて

 [その１:全体像とFirebaseの準備](https://qiita.com/uchi2020/items/22cec9cbd8b65298844f)

 [その２:Androidのクライアントアプリからデータの登録と表示まで](https://qiita.com/uchi2020/items/3857098ca5e9052f4b52)


 [その３:iOSのクライアントアプリからデータの登録と表示まで](https://qiita.com/uchi2020/items/6cc6f1bc2465f6d4b318)


 [その４:準備中]

 [その５:準備中]
PythonにTensorFlowをimportすると「ImportError: DLL load failed: 指定されたモジュールが見つかりません。」と出る

# 環境

* Windows10
* Anaconda
* Python 3.7.4
* pip 20.0.2

# 何が起こった

深層学習を試すためTensorFlowをPythonで導入しようと、

```
pip install tensorflow
```

と普通にインストール。問題なくインストールが完了。
ここで、きちんとインポートできるかどうか確認すると...

```
Using TensorFlow backend.
Traceback (most recent call last):
    File "C:...
    ...
    File "C:...
       return _load(spec)
ImportError: DLL load failed: 指定されたモジュールが見つかりません。

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
    File "C:...
    ...
    File "C:...
       return _load(spec)
ImportError: DLL load failed: 指定されたモジュールが見つかりません。


Failed to load the native TensorFlow runtime.

See https://www.tensorflow.org/install/errors

for some common reasons and solutions.  Include the entire stack trace
above this error message when asking for help.
```

とエラーが出る（長いので途中省略）。

DLLとは汎用性の高い機能をまとめて部品化したプログラムのことで、おおもとのプログラム実行時に動的に（Dynamic）リンクする（Link）ライブラリ（Library）のことである。これが見当たらないぞというよく見かけるエラーなのだが、いろいろ調べ、いろいろやったものの解決せず。

# 解決策：TensorFlowをダウングレードする

バージョンを指定せずにインストールすると記事作成時点での最新版tensorflow==2.1.0がインストールされるので、プロンプトで以下のように古いバージョンを指定して実行。

```
pip install --upgrade tensorflow==2.0.0
```

こうして `python` コマンドでインタプリタを起動し

```
>>> import tensorflow
```

で確認すると問題なくインポートに成功。

バージョンは、

```
pip install --upgrade tensorflow==
```

で、吐かれるエラーメッセージ

```
ERROR: Could not find a version that satisfies the requirement tensorflow== (from versions: ...（ここにインストール可能なバージョンのリストが表示される）...)
ERROR: No matching distribution found for tensorflow==
```

から問題なくインポートできるバージョンを探した。

経験上とりあえずバージョンを下げるとうまくいくことが多い気がするが、深層学習のライブラリは環境依存が他より顕著なのできちんと公式HPなどを確認してあげたい。
「何か食べたいけど何が食べたいのか分からない」あなたへ

# きょう何食べようか悩んでいるあなたへ
5つの質問に答えるだけで、料理ジャンルをサジェストしてくれるサービスを公開しました :hugging:
https://kyounanitaberu.appspot.com/
※シャットダウンしました。
<img height="100" border="1" alt="スクリーンショット 2020-02-23 11.03.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32524/f54dfc86-55c8-bdf0-7ef9-7e73f8f5244d.png"> <img height="150" alt="スクリーンショット 2020-02-23 11.03.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32524/5e08bf59-aa3e-73c8-7154-202284e616d4.png">


# きっかけ
<img width="722" alt="スクリーンショット 2020-02-23 2.59.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32524/a742574c-ef5f-d620-28bb-8a0866cf0fbf.png">
きっかけは一つの動画。
私は美味しいものを食べることが大好きなんですが、好きが故に**何を食べるかめちゃくちゃ悩んで時間を消費**してしまいます。
この動画を見て「同じことを思っている人がいるんだ」と気づけたので
２択で今の気分を選ぶと、料理ジャンルをサジェストしてくれるWebアプリケーションを作りました。

# システム
システムとしては**Vue.js**で作ったアプリを**GCP（GoogleCloudPlatform）**にデプロイしているちょーシンプルな構成です。

画面構成も”NavBarコンポーネント”と”Cardコンポーネント”と至って簡単。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32524/c97b5ad1-74dd-6832-2e73-6d84b1b65cec.png)
↓ファイル構成はこんな感じ。

```console
$ tree -L 2 --matchdirs src
src
├── App.vue
├── components
│   ├── Card.vue
│   ├── NavBar.vue
│   ├── Search.vue ←食べログとUberEatsのリンク
│   └── Share.vue ←SNSのリンク
├── data
│   ├── questions.js ←”質問・回答”と”次の質問・回答”or”サジェストする料理ジャンルID”のマッピングファイル
│   └── results.js ←”料理ジャンルID”と”ジャンル名や画像”とのマッピングファイル
├── main.js
├── store
│   ├── actions.js
│   ├── index.js
│   └── mutations.js
└── views
    └── Main.vue
```

ちなみに表示するカードの切り替えには**Vuex**、UIライブラリには**Bootstrap**を使っているので、Vueを勉強したての人が一通り復習するのにいいかも、と思いました :thinking: 


また、GCPへのデプロイは、[Vue.jsで作成したSPAなアプリをGoogle App Engineへデプロイする](https://qiita.com/kai_kou/items/7feb5428d3dfcf2f6437)を参考にさせていただきました、ありがとうございます。

# 感想
昨日さっそく使ってみたのですが、いつも30分くらい悩むところを（悩みすぎ）5分くらいでパパッと決められて満足です。

改善点は色々ありますが、質問や回答を自分で考えてファイルとして定義しているので、こういうところで機械学習を使っていきたいなーと思いました。

最後に、私はVueもGCPも初心者ですが1〜2日（ずっと開発してたわけではない）でゼロから公開までできました。
**VueやGCPに興味をお持ちの方に「このくらいのものは作れるんだ」と思ってもらえると嬉しい**です :thumbsup:
RSSについて

iOSアプリで自分好みのRSSリーダーが欲しくなり、作ろうと思ったのですがそもそもRSSとは何だっけ？ということになり１から調べ直しました。
# RSSとは
```
ニュースやブログなど各種のウェブサイトの更新情報を配信するための文書フォーマットの総称である。
※Wikipediaより抜粋
```
また、RSSという名前自体にも複数の意味解釈がありました。
### RDF Site Summary
ファイル拡張子が.rdfとなっているもの。全体がrdf要素（＜rdf＞～＜/rdf＞）で囲まれていることからも分かります。系統としてはRSS0.9→1.0系に分類されます。

### Really Simple Syndication
ファイル拡張子が.rssまたは.xmlとなっているもの。RDFとは異なる体型で発展していったものです。系統としてはRSS2.0系に分類されます。

### ATOM
ファイル拡張子が.xmlとなっているもの。RSSと同じ目的で異なるデータ形式で記述されたものという解釈でいいと思います。ATOMもRSSとして総称されることが多いようです。

# フィードリーダー
```
フィードリーダー（feed reader）、またはフィード・アグリゲーター（feed aggregator）は、
ブログやポッドキャスト、ニュースサイトなどが配信するフィードを取得・購読するための
アプリケーションソフトウェアの総称。フィードのファイルフォーマットとしてRSSが先行していたことから、
現在でも「RSSリーダー」と呼ばれることが多い。
※Wikipediaより抜粋
```
以上のことからRSSには様々なフォーマットがあるので、リーダーを作るためには様々なフォーマットに対応したParserを実装する必要がありそうでした。

# iOSでのRSSリーダー
今まで調べたことから、これからiOSアプリにおいてRSSリーダーを作る場合にはRSS1.0, RSS2.0, ATOMそれぞれのデータフォーマットに対応したParserを作ってあげる必要がありそうです。
自分で一から作るのもいいですが、車輪の再発明をしてもしょうがないなと思い、ライブラリがないか探してみました。するとやはりすでによさげなものがありました。
### FeedKit
https://github.com/nmdias/FeedKit
RSS, ATOM, JSONに対応したFeed Parserです。
このライブラリの中身を読んでいて驚いたのが、データ取得をするのにURL Sessionなどの一般的なデータ転送処理が一切書かれていませんでした。
データの取得には

```Swift
data = try Data(contentsOf: sanitizedSchemeUrl)
```
これだけです！賢い！

# 参考
https://ja.wikipedia.org/wiki/RSS
https://oshiete.goo.ne.jp/qa/3951173.html
https://www.nishishi.com/blog/2006/02/rss_rdf_xml.html
http://e-words.jp/w/RSS.html
http://e-words.jp/w/RSS%E3%83%95%E3%82%A3%E3%83%BC%E3%83%89.html
PHP使ってユーザ作成・登録する時にパスワードをハッシュ化する

例えば

`$lpw = $_POST["lpw"];`

とかでログインパスワードをPOSTで受け取った際に

`$hash = password_hash($lpw, PASSWORD_DEFAULT);`

と記載して、その受け取ったパスワードをハッシュ化して、データベースに書き込むときにそのハッシュ化されたパスワードを放り込む。

```
$stmt = $pdo->prepare("INSERT INTO test_user_table(id,lid,lpw)VALUES(NULL,:lid,:lpw)");
$stmt->bindValue(':lid', $lid, PDO::PARAM_STR);
$stmt->bindValue(':lpw', $hash, PDO::PARAM_STR);
```
【PHP超初心者用】エラーは敵じゃなくて味方だよ

# 書くことになった経緯
誰しも初心者の頃ってエラーが出たりでバグらせたりすると、意味わかんねーよって投げ出したりすることもあったと思うんですよね。意味不明な英語だけの羅列が出ると焦ってやめたくなる気持ちも本当に分かります。

でも実はその意味不明な英語の羅列って、どこどこが間違ってるよって教えてくれたりしてくれてるんですよね。（もちろん意味不明なことを言ってることもありますが。笑）

そこで今回はどのようにエラーが書かれているかを見ることで、「こいつ実はいいやつだったんじゃね」っていう感覚を味わってほしいなと思っています。

# エラーってどんなのがあるの
エラーにもいろんな種類があるのですが、その一例は以下のようなものです。
`Fatal error: Uncaught Error: Call to undefined function hell() in /public_html/fatal_error.php on line 6`

今回はこのエラーを詳しく見ていきます。
では順番に見ていきましょう。


## Fatal error: Uncaught Error:
まずはエラーのこの部分です。
**Fatal error: Uncaught Error:** Call to undefined function hell() in /public_html/fatal_error.php on line 6

ここでは**エラーの種類**が記述されています。
`Fatal error`は日本語にすると「致命的なエラー」、`Uncaught Error`は「捕らえられなかったエラー」となります。
この種類によっては実行が途中で停止したり、そもそも最初から動かなかったりというのが決まっています。

今回出てきたエラーは**致命的な**エラーですので、完全に処理がとまってしまいます。
他にも`Parse error`（構文エラー）や`Warning`（警告）などの種類がありますね。

`Uncaught Error`については初心者の方には少し分かりづらいかもしれませんが、プログラマーはエラーに対して「キャッチ（捕捉）する」という表現をよく使います。`try-catch`などを理解すれば感覚は分かると思うのですが、今回はそういう表現をするんだくらいで大丈夫です。


##  Call to undefined function hell()
次はこの部分です。
Fatal error: Uncaught Error: **Call to undefined function hell()** in /public_html/fatal_error.php on line 6

ここには**エラーの原因であるだろう**ことが書かれています。
今回の部分を訳すと、「定義されていないhell()という関数が呼ばれているよ」になります。

このように原因を真についた分かりやすいことを言ってくれることもありますが、まったく違うことを言ってくることもあります。
例えば、`;`を最後に忘れちゃったときは間違いの次の行が間違ってるよと言われます。


## in /public_html/fatal_error.php on line 6
いよいよ最後です。
Fatal error: Uncaught Error: Call to undefined function hell() **in /public_html/fatal_error.php on line 6**

ここでは、**エラーの場所**を教えてくれています。
今回で言うと、`fatal_error.php`というファイルの6行目が間違ってるよ、といった感じです。

そのファイルがどこにあるのかを教えてくれているのが`/public_html/`の部分です。

文字だけでファイル構造を表現する場合、hogeファイルの中にあるhoge.txtを`hoge/hoge.txt`と表します。

なので、今回で言うと`public_html`の中にある`fatal_error.php`という意味です。


# まとめ
ここまでをまとめると、エラー文はこのように分解できます。

**[エラーの種類]:[エラーの原因]in[エラーの場所]**

こう見ると実は結構単純で簡単なんだと分かると思います。
これで少しはエラーに対して恐怖心がなくなったのではないでしょうか。


さらにエラーの詳しい種類や解決方法を知りたい方は以下の記事をご覧ください。
[【実例で見る】PHPのエラーの種類と解決方法](https://qiita.com/uni_uniq/items/83521a9fec03f559bcbe)
ゲーム開発者がやってみた親子Scratch　1回目

小二の息子がプログラムに興味を示してきたので、Scratchを始めました。

まずはサンプルを私が作成して、息子がそれを改造する、という流れで進めています。

それ用のミニゲームを作成してみましたので、良ければ参考にしてください。

このゲームの仕組みは簡単ですので、ソースの流用はご自由に！

小学校の先生でサンプル作成に困っている方には良いかと。特に必要はないですが、使用された際はご連絡いただけるとすごく喜びます。ご連絡はtwitterアカウントにてお願いします！

#■落下物をとるゲーム

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530491/e7d101a7-9946-0324-5724-84ecf0641dd7.png)

※以下のページで公開しています！
https://scratch.mit.edu/projects/368643368

こちらのゲームは
・ネコを左右キーで動かします。
・コウモリがリンゴを落とします。ネコがリンゴをとると+10点
・お化けがオレンジ色のボールを落とします。オレンジ色のボールをとると-10点
・ゲームオーバー無しです。

まあ、基本的な落ちてくるアイテムをキャッチするゲームですね。
子供に理解させるにはこれくらい単純な方がいいかと思います。

こちらのスクリプトを好きに改造してみなさい、ということでやらせてみました。

#■息子はどんな改造をしたか

わかりやすいところで自分が好きなキャラクターにしていましたね。

お化けのスプライトを変えてみたり、リンゴのスプライトを変えてみたり。

リンゴを落とすコウモリはもっと味方みたいな画像にしたかったのですが、あんまりそういったスプライトがプリセットされていないんですよね。

オレンジ色のボールの画像に関しても、もっと爆弾みたいなのがほしかったのですが。

シューティングゲーム作るためのミサイルや、爆発なんかもほしいのですが。

まあ、ただで使えるものなので贅沢ですよね。

そのあたりを工夫して描いて使うところに、scratchのゲーム制作のだいご味があるのかもしれません。

息子的には仮面ライダーの画像にしたいということで、画像検索で探していました。
※著作権的に問題があるので、アップはしません！

今まではタブレットの音声で画像検索をしたことはあるのですが、文字入力でのやり方を覚えたのは収穫ですね。

あと散々webはみていたのに、「ブラウザ」という言葉を知らなかったのは新鮮でした。

知らずに使っていたのねー。でもPCの基本的な使い方や、ローマ字なんかも学べたのでよかったですね。

#■最終的にどんな感じになったか

上からアイテムを落とすキャラクターをどんどん増やしていましたね。

あとは点数がたくさん入ると面白いようで、とれる点数のインフレが起きていました。

効果音なんかいじるかな、と思っていましたが少し触っただけであんまり興味がないようでしたね。

リンゴやオレンジ色のボールはコウモリやお化けの位置から落ちるようにしてあります。

スクリプトを単純にコピーすると、それがそのままになってしまうので発生位置を指定し直す必要があります。

そういったオペレーションを覚えたのが、今後の作業につながっていく気がします。

リンゴを逆方向に動かしたいということで、「どうしたらいいと思う？」と逆質問したら、ある程度誘導はしましたがｙ移動を逆方向にすればいい、と気が付くことができました。

こういった感覚がちゃんとしているのは、ゲームをプレイしているおかげなんだと思います。

最終的にアイテムを落とすキャラクターが6対くらいになりました。

#■スクリプトの工夫について

スクリプトに関して簡単に説明しておきます。

BGMですが、プリセットされているものをループしてあります。

これ単純に「ずっと」で鳴らしておけばいいのかと思っていたのですが、それだと最初のところで連続再生がかかるんですね。

ちゃんとループさせるためには、その音が鳴る時間を指定して、その時間分待ってから次のループを始めないといけない。

あとお化けとコウモリが上下しています。

これはsin波を使用しています。

sin関数があるのはわかっていたのですが、変数に与えるものってなんだろうと思っていたのですが、ズバリ角度ですね。

まあ言われてみればそりゃそうかなんですが、わかりやすく書いていた記事がなくて少し戸惑いました。

角度を30度とか45度とか変化させていくと-1~1の間で数値が変化されますので、上下最大30ドット移動させたいのであれば、その出た値に30をかければよいです。

#■次は

簡単なシューティングゲームを作成してみるつもりです。

後はタイトル画面を作成してみましょうかね。

いまはゲーム全体にかかわるような初期化でも、特定のスプライトで初期化をしているのですが、きれいなやり方ってなんなんでしょうね。

あと、スプライトが途中で出なくなるバグなんて言うのも遭遇しています。

そのあたりも調査できるとよいなー

あと下記ブログもやっていますのでよろしければのぞいてみてください

ゲームプロマネのブログ
http://game-pm.com/
大学卒業にあたってのアカウント整理事項まとめ

#はじめに
大学を卒業するので、研究室として作ったものと個人で作ったものの整理をしようと思っています。備忘録兼ねてToDOリストをまとめます。とりあえずToDoリストだけですが、実際に作業してみてつまったところがでてきたら（＆気が向いたら）追記しようと思います。
#To Do
##GitHub
今、研究室アドレスで登録しているアカウント（以下、研究アカウント）をメインで使っているので、その登録情報を変更するか、もしくは新たにアカウントを作り直す。研究室アドレスのやつはそのまま残しといたほうがいい気がするので、まずは新たにアカウントを作りなおす方針でいく。

* 個人アドレスで新たにアカウント（以下、個人アカウント）を作る
* 研究アカウントのうち汎用性が高いコード、趣味で開発したコードを個人アカウントに移行する
* EclipseのEgitを使って開発しているので、今後、個人で開発していくものについては、リモートリポジトリURLの設定などを変更する
* リモートサーバにおいてあるGitHubプロジェクトを更新する
* GitHubPagesで公開済みのものについては個人アカウントで新たに公開する。研究アカウントのGitHubPagesには新しいURLへのリンクを表示させる
* GitHubでログインしたいろんなサービス（Qiitaなど）を洗い出し整理する。対応の必要があれば対応する

##Google Drive
* Google Driveも研究アカウントで登録しているものをメインで使っているので、汎用的に使えて秘匿性の低いものは、個人アカウントのGoogle Driveに移行する

##Google Cloud API
* こちらは逆に個人アカウントで（立替払いで）契約したものを研究開発に使っていたので、APIキーなどを研究開発物から除く

##Dropbox
有料プラン(2TB)で契約していた。卒業したら2TBも必要ないので解約し、GoogleDriveメインにする。Dropbox上の大学関連データはHDDにダウンロードし、大学においていく。プライベートなデータは個人アカウントのGoogleDriveに移行する。
##Grammerly
学位論文を書くために３ヶ月だけ契約した。しばらくは不要なので、解約しておく
##PaperPile
文献管理アプリ。投稿中の論文の査読対応を卒業後もしなければならないので、それらが終了するまでは契約しておく。
#おわりに
他にもあるかもですので思いついたら追記します。
OpenCVでトリミングする　～覗き動画を作る～

# はじめに
釣りタイトルっぽいな。

# OpenCVでトリミング
OpenCVのタイプはnumpy.ndarray。だから[スライス](https://qiita.com/mo256man/items/ed8ea21bd0ae94e5ed48)でその一部を取り出すことができる。
行列だから行・列の順。行列だから「どの行（列）からどの行（列）まで」を指定する。「左上座標と切り取るサイズ」ではない。
要はimg[r1: r2, c1: c2]だが、理屈を理解すれば **img[r: r+h, c: c+w]** という書き方を暗記するのは容易だ。

ところで、左上座標を x, y = …と定義したとき、サイズの書き方は h, w = … と w, h = … のどちらが適切なのだろうか。小学校算数の[かけ算の順序問題](https://ja.wikipedia.org/wiki/%E3%81%8B%E3%81%91%E7%AE%97%E3%81%AE%E9%A0%86%E5%BA%8F%E5%95%8F%E9%A1%8C)が話題になっている昨今、必修化されるプログラミング教育の授業で本件は新たな火種となってしまう可能性がある。

なお、トリミングは当然PIL（Pillow）でもできるが、PILの仕様を書くと混乱してしまうのでここではいっさい触れない。

## 基本的なプログラム

```Python:trim.py
import cv2

filename = "nurse.jpg"
img = cv2.imread(filename)

x, y = 380, 30
h, w = 160, 120
img_trim = img[y:y+h, x:x+w]

cv2.imshow("origin", img)
cv2.imshow("trim", img_trim)
cv2.imwrite("trimmed_image.jpg", img_trim)

cv2.waitKey(0)
cv2.destroyAllWindows()
```

元画像（[スキマナース](https://nurse-web.jp/photo/archives/214)）から、
![bakudan.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520216/76f331b8-4117-81a5-4325-f5f60d9e9355.jpeg)
(x,y)=(380,30)から始まる高さ160×幅120のエリアを取り出すことができた。
![trim.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520216/c8334850-99fd-4d81-a428-3b5dd2d9d5ab.jpeg)
もちろん、顔認識を入れれば位置やサイズを手打ちする必要はなくなる。

## OpenCVで画像を保存　cv2.imwrite()
cv2.imwrite(*filename*, *mat*) という使い方をする。
*filename*はファイル名。画像フォーマットはファイル名の拡張子で自動的に決まる。
*mat*は画像データ。

## 応用例
これだけでは面白くないので、ループを回しながらトリミング位置を変えるというプログラムを書いてみた。

```Python:peep.py
import cv2
from PIL import Image

filename = "nurse.jpg"
img = cv2.imread(filename)
imgH, imgW = img.shape[:2]

# ご自由にどうぞ
x, y = 50, 100
dx,dy = 2, 3
h, w = 160, 160

imgs=[]
while True:
    if 0 <= x+dx <= imgW-w : #こんな書き方ができるんだねえ。
        x = x+dx
    else:
        dx = -dx

    if 0 <= y+dy <= imgH-h :
        y = y+dy
    else:
        dy = -dy

    window = img[y:y+h, x:x+w]
    cv2.imshow("", window)

# この一文を有効にするとどうなるか君の目で確かめてくれ！
#    cv2.moveWindow("", x+100, y+100)

    imgPIL=Image.fromarray(window[:,:,::-1])
    imgs.append(imgPIL)

    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

cv2.destroyAllWindows()
imgs[0].save("peep.gif", save_all=True,
             append_images=imgs[1:], optimize=False,
             duration=20, loop=0)
```

このプログラムにより、こんなアニメーションGIFが作られる。
![peep.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520216/02253391-47a5-68e5-3d77-e3625adcaf7f.gif)

この手のゲームをピープホール（覗き穴）と呼ぶと昔ベーマガで読んだのだが、この言葉が使われているのを見たことがないぞ。

# 終わりに
Excelにはじめて触れたとき、R1C1形式を見て「RとC、どっちが行でどっちが列なんだ！」「Rが行でCが列なのはわかったけど、xy座標はx,yと書くのに行列がRCだと並びが逆じゃないか！」と憤ったことを思い出す。
その違和感とまた付き合うことになるとは思わなかった。
アンジュの画像をyahooからダウンロードする。


前回、アンジュの画像をDLしましたが、
https://qiita.com/helloworld2/items/6008d5408a33dfe1a2a8
結局取れたのはサムネイルだったし、それじゃショボいので、いろいろがんばってグーグル画像検索の元イメージをスクレイピングしようとしたんですが、**非常に困難だ**ということがわかりました。

ということで、若干敗北感もありますが、スクレイピングではなく**画像DLの自動化**に方針を切り替えてトライしてみます。

sleniumというブラウザ操作を自動化する便利ツールがあり、(当然のように)pythonラッパーも提供されているのでpythonで実装します。


#やったこと
yahooの画像検索からアンジュの画像を150枚DL。

yahoo画像検索はグーグル検索画面と違って、フォトプレーヤ的な機能が実装されています。これをseleniumで叩くと、良い感じに検索結果画像を閲覧していくことが出来ます。


#コードのメイン処理
```python

picker = YahooImagePicker('アンジュ・カトリーナ', 150)
picker.jump()
for i, u in enumerate(picker.image_urls()):
    r = requests.get(u)
    with open(os.path.join(IMAGE_FOLDER, 'ange_{}.jpg'.format(i)), 'wb') as f:
       f.write(r.content)
```
イメージピッカーのインスタンス生成(キーワード「アンジュ」、枚数=150)して、最初の画像イメージまでジャンプします。

後は画像DL＝＞次の画像へジャンプ＝＞画像DLの繰り返しです。ピッカーのimage_urlsメソッドはyield実装してあるので、指定された枚数分、毎回画像URLを返します。

#ピッカークラス実装
```python
class YahooImagePicker:
    def __init__(self, keyword, count):
        self._keyword = keyword
        self._count = count
        self._driver = webdriver.Chrome()

    def jump(self):
        # yahooページへ遷移
        self._driver.get('http://yahoo.co.jp')

        # 検索キーワード入力/実行
        query = self._driver.find_element_by_name('p')
        query.send_keys(self._keyword)
        query.submit()
        time.sleep(3)

        # 画像リンクページへ遷移
        self._driver.find_element_by_link_text('画像').click()
        time.sleep(3)

        # 最初の画像イメージをクリック
        self._driver.find_element_by_tag_name('img').click()
        time.sleep(3)

    def image_urls(self):
        while True:
            # イメージリンク取得
            c = self._driver.find_element_by_id('imgContainer')
            c.find_element_by_id('imgInner')
            i = c.find_element_by_id('imgInner')
            i.find_element_by_tag_name('img')
            i2 = i.find_element_by_tag_name('img')
            i2.get_attribute('src')
            u = i2.get_attribute('src')

            # 次のイメージへ移動
            self._driver.find_element_by_class_name('next').click()
            time.sleep(3)

            print('count = {}'.format(self._count))
            self._count -= 1
            if self._count > 0:
                yield u
            else:
                return u
```
コンストラクタでchromeのドライバを生成し、jumpメソッドで最初の画像ページまでジャンプ、image_urlsで画像URLを取得します。ところどころに入っているtime.sleepは、seleniumのwait機能を使ってかしこくつくるべきだし、イメージリンクの抽出はもっと少ない行で可能だと思いますが、**とりあえず動いた**のでよしとします。

![範囲を選択_005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244766/207e1776-1258-64c4-3ee5-9df8340bd1be.png)

大量にアンジュの画像が集まってきます。seleniumすばらしい。

![範囲を選択_006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244766/208937bf-4101-c3e7-ef58-adb613e2a7ec.png)

いにゅいの画像が混ざったりしてるのはグーグルAIの限界でしょうか。
いくつかDLに失敗してるファイルもあります。これらはtime.sleepというベタ制御のせい・・だと思いますが、どうだろう。

全コードは以下。
https://github.com/mogrodown/hobby_python/blob/master/ange_picker.py
[Tips] shell script:q

#Tips
/bin/shを利用したTips

## コマンドライン引数を利用したい場合に
*getopts*

```shell:example
while getopts "ab:" argument # 引数をargumentへ代入
# 付与された引数を検知し、以降の処理で判定、実行を行う
# オプションに引数を指定する倍位には":"を付与する
``` 

## キーボード入力によって処理を中断したい場合に
*trap*

```shell:example
trap 'echo "EXIT"; exit' INT
# INTで検知するシグナルを指定する
# kill -l にてシグナルの一覧を閲覧できる
```

## 入力値を表示しないようにする
*stty*

```shell:example
stty -echo # 入力値非表示化
read pswd
stty echo  # 入力値表示化
```

## キーバッファを行わない
*stty*

```shell:example
stty raw   # キーバッファ無効化
# y/n制御時の利用が例として挙げられる
```

## カレンダー機能
*dialog --calendar*

```shell:example
dialog --calendar "select date" 2 60 2> test.tmp
```

## デフォルト値の判定
:= :?

```shell:example
cp file ${EXAMPLE:=/tmp}
# 変数が存在しない、もしくは、空だった場合に/tmpへファイルがコピーされる

: ${EXAMPLE:=/tmp}
# 処理の先頭での初期化に利用できる

: ${EXAMPLE:? 未定義変数}
# 変数が存在しない、もしくは、空だった場合に、文言を出力
```

## 値がint(整数)か判断
*test*

```shell:example
test $1 -eq 0 2>/dev/null
echo $? #0 or 1 or 2
# 0 = 0が渡されている場合。
# 1 = 0以外の整数が渡されている場合
# 2 = int以外が渡されている場合
```

## ファイルが存在する時だけ、外部ファイルを読み込む
*[ -f <fiel path> ]*

```shell:example
[ -f ./funcs.sh ] && . ./funcs.sh
# []はtestを省略した形

```

## 未定義変数をエラーとして扱う
*set -u*

```shell:example
set -u
$EXAMPLE # エラーとして出力される

# バグを防ぐ、ひとつの方法として挙げられる
# コマンドライン引数を複数扱う場合には、エラーが発生する可能性が高くなるので注意が必要
```

## 実行ユーザによって影響されないモジュールの記述方法
*dirname*


```shell:example
cd "$(dirname "$0")"
# 絶対パス、相対パス、どちらの実行にも対応することができる
# 絶対パス記述でもよいが、運用保守がめんどうになる
```


## コマンドライン引数の上限を超えて扱う
*xargs*

```shell:example
find ./ -name "*.txt" -print | xargs grep "example" /dev/null
```

## example

*example*

```shell:example

```
Android でもとりあえず Ubuntu のデスクトップ環境を使いたい（Termux 版 - デスクトップ環境で日本語入力）

## はじめに

[Android でもとりあえず Ubuntu のデスクトップ環境を使いたい（Termux 版）](https://qiita.com/tacchi/items/a532aafd9c05fdf7be45)
の続きです。
Ubuntu の LXDE、XFCEデスクトップ環境で日本語入力を行うための設定を記載します。
fcitx-mozc はどうしても動作させることができなかった（オンになっているはずなのに、日本語が入力できない。。。）ので、fcitx-anthy を使用しています。

## インストール

まずは日本語フォントおよび Anthy （日本語をキーボードから入力するためのツール）のインストールを行います。
dbus-x11 は入力ツールの不足分を補完します。
Ubuntu の LXDE または XFCE デスクトップ環境を立ち上げてから、以下のコマンドを LXTerminal 等のシェルで実行して下さい。

```

apt install -y fonts-noto
apt install -y fcitx-anthy
apt install -y dbus-x11

```

## 設定

続いて入力ツールの設定ダイアログで設定を行います。
以下のコマンドでダイアログを開いて下さい。

```

fcitx-configtool

```

もしダイアログが立ち上がらなかったら以下のコマンドを実行してからもう一度、ダイアログを立ち上げて下さい。

```

fcitx-autostart

```

入力ツールのダイアログを表示したら以下の手順で Anthy を使えるように設定してください。

1. Input Method タブを選択
2. + ボタンを押す
3. Only Show Current Language のチェックボックスからチェックを外す
4. チェックボックスの下の入力欄に Anthy と入力する
5. Anthy が上のボックスに出るので選択し、OKボタンを押す
6. Anthy が上から2番目の位置になるよう、Anthy を選択してから + ボタンの右側にある ↑ ボタンや ↓ ボタンで移動する
7. 続いて、Global Config タブを選択
8. Trigger Input Method で日本語と英語を切り替えるボタンを設定する（※）
9. ダイアログの右上のｘを押してダイアログを閉じる

※任意です。ネットで見ると 右ALT や Shift+SPACE など好みで設定しているようです。
 Android Studio を使っている人は、デフォルトで設定されている Ctrl+SPACE を別の設定に変えましょう。
 Ctrl+SPACE は Android Studio のコード補完のショートカットになります。

続いて設定ファイルに環境変数とfcitxの起動コマンドを記載します。
以下のコマンドを実行して設定ファイルを編集します。

```

vim ~/.bashrc

```

以下を .bashrc ファイル内の適当な位置に記載します。
私は一番下に記載しました。

```

export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx

fcitx > /dev/null 2>&1

```

最後に Termux と XSDLを終了し起動し直します。
Android の通知領域に Termux の文字が2行出ているので上の方をタップします。
左下に Exit の文言が出ますので、Exit をタップして Termux を終了します。
XSDL は Android の各ランチャーの手順に従って終了してください。
再び Termux + XSDL でデスクトップ環境を立ち上げるとAnthyで日本語入力できるようになります。

なお私の環境では Termux を再起動しないと Anthy で日本語入力出来ませんでした。
.bashrc を souce コマンドで読み込んでも駄目だったので、何か起動時に行わないといけないことがあるのかもしれません。

## 参考サイト

[ChromebookのLinux（Crostini）の日本語入力をAnthyで構築]
(https://qiita.com/shin1kt/items/8d6be8e16e309db9cd79)

[Chromebook C101PAでVSCodeを使う。(Crostini使用)]
(https://www.taneyats.com/entry/vscode-on-c101pa#%E3%83%95%E3%82%A9%E3%83%B3%E3%83%88%E3%82%92%E8%BF%BD%E5%8A%A0)

[fcitxで「正しくfcitxに接続できません。」エラーが発生したときの対応]
(https://kunst1080.hatenablog.com/entry/2017/11/25/215016)

[Chrombook C101PAにVisual Studio Codeをインストールしてみる](https://qiita.com/DiceYellowhouse/items/6ce930a4671508545144)
【実例で見る】PHPのエラーの種類と解決方法

# 本記事の位置づけ
PHPでよく出くわすエラーの種類を実際の事例と共に紹介していきます。

# エラーの種類
よく出るものはこんな感じ。

- [Fatal error（致命的なエラー）](#fatal-error致命的なエラー)
- [Parse error: syntax error（構文エラー）](#parse-error-syntax-error構文エラー)
- [Warning（警告）](#warning警告)
- [Notice（注意）](#notice注意)

# 実例と共に見る解決方法
## Fatal error（致命的なエラー）
これは重大な致命的なエラーです。処理はこのエラー部分で停止します。

【よくある原因】
関数の二重定義や未定義関数の呼び出しなど。

【実例】
「未定義の関数を呼び出す」
以下のコードは、スペルミスによって未定義のhellという関数を呼び出してしまっています。

```fatal_error.php
<?php
    function hello(){
        $hello = "こんにちは";
        echo $hello;
    }
    hell();
?>
```

【表示されるエラー】
undefined（未定義）な関数の`hell()`が呼ばれていると言われています。
`Fatal error: Uncaught Error: Call to undefined function hell() in /public_html/fatal_error.php:6 `

## Parse error: syntax error（構文エラー）
これは構文（文法）のエラーです。この場合は処理はされず、エラーが表示されるだけの画面になります。

【よくある原因】
スペルミスや括弧の閉じ忘れなど。
(特に初心者の方は`{}`,`<>`などのように括弧を開いたら閉じる習慣をつけましょう。)

【実例】
「`"；"`（セミコロン）忘れ」
以下のコードは、`$hello = ` の行に`";"`を忘れています。

```syntax_error.php
<?php
    $hello = "こんにちは"
    echo $hello;
?>
```
【表示されるエラー】
実際に付け忘れている行ではなく、一つ下の`echo`にエラーが出ます。
`Parse error: syntax error, unexpected 'echo' (T_ECHO) in /public_html/syntax_error.php on line 3`

## Warning（警告）
これは直したほうがいいだろうくらいの間違いの指摘です。実行自体は止まらずに進み続けます。

【よくある原因】
参照先のファイルがないときや引数の型が違うときなど。

【実例】
「存在しないファイルの参照」
以下のコードは、存在していない`hello.txt`というファイルを参照しようとしています。

```warning_error.php
<?php
    $filename = "hello.txt";
    $hello = file_get_contents($filename);
    echo $hello;
?>
```

【表示されるエラー】
ファイルを開くことが出来なかったと言われています。
`Warning: file_get_contents(hello.txt): failed to open stream: No such file or directory in /public_html/warning_error.php on line 3`

## Notice（注意）
これは単なる注意なだけで、処理自体は無視して実行されます。しかし、セキュリティ的な面から見てもよくないエラーです。

【よくある原因】
未定義の変数の使用や関数の引数ミスなど。

【実例】
「未定義の変数の使用」
以下のコードは、未定義の`$hello`という変数を使用しています。

```notice_error.php
<?php
    echo $hello;
    $hello = "こんにちは";
?>
```

【表示されるエラー】
`hello`がUndefined(未定義)だと言われています。
`Notice: Undefined variable: hello in /public_html/notice_error.php on line 2`

# 参考
[$_GET, $_POSTなどを受け取る際の処理(Qiita)](https://qiita.com/mpyw/items/2f9955db1c02eeef43ea)
[基本中の基本！PHPのプログラミングエラーの種類と内容](https://liginc.co.jp/programmer/archives/4107)
AWSのSTSが使われるシュチュエーションをまとめてみた

#はじめに
AWS初学者（ASSを受験のため勉強中）である僕が、ネットや参考書などから集めてきた情報です。。間違いがあればコメントいただければ幸いです。

# STSとは
一時的なアクセス制御に使われるAWSサービス。セッショントークンを発行することで、アクセスを許可することができる。

# 使用例
### アカウント間で付与する場合
本番アカウントにあるEC2インスタンスからcloudwatchで取得したログを開発アカウントにあるDynamoDBに渡すことを開発側のLamdbaで処理する場合、STSを使用すれば、本番アカウントのアクセスIDなどを知らなくても処理が可能になる。

### アプリケーションユーザがS3に保存したリソースを読み取りできるようにする場合
アプリケーションユーザログインする時に、サードパーティのログインを使用（Googleや Facebookなど）させ、STSのWebフェデレーションを使うことで、AWSリソースのアクセス許可することができる。
→WebIDフェデレーション

### 企業内の認証機能をAWSで使用する場合
元々企業内にある認証機能をAWSと紐づけることで、企業内認証するだけでSTSを使って、AWSリソースを扱うことができる機能（シングルサインオンを簡単にしてくれる）。SAML２.0やOpenID Connectと互換性のある認証プロトコルをサポートしている。
花粉症対策デジタル医療相談Botの開発　ユーザーIDと位置情報をFirestoreで管理

##概要
耳鼻咽喉科の開業医をしながらデジタルテクノロジーを使った医療の効率化や患者さん向けサービスの開発研究を行っています。

スギ花粉の飛散量が増えてきました。花粉症の方にはつらい季節ですね。
忙しくて医療機関を受診できなかったり、新型コロナウイルスが心配で受診を控えている方も多いのではないでしょうか？

最近薬局や通販で購入できる医療用医薬品（医療機関で処方されるものと同成分）が増えてきたのはご存じでしょうか？これらの薬を上手に利用できれば医療機関を受診できなくても花粉シーズンを乗り越えることが出来るかもしれません。

上手に利用するには自分の花粉症状がどの程度重症なのかや、利用しようとする薬の特性を知っていないといけませんが、その辺を教えてくれるサービスがなかったので作成してみました。現在（2020年2月19日～3月4日）クラウドファンディングプラットフォームCAMPFIREでテスト版ユーザー募集しています。プロジェクトはサクセスしましたが、たくさんの花粉症の方に使って頂いて、サービス向上のためご意見ご感想をいただきたいと思っています。

CAMPFIREのプロジェクトページはこちら
[LINEで花粉症の重症度や最適な市販薬がわかるデジタル医療相談【アレルナビ】](https://camp-fire.jp/projects/view/218592)

このサービスではユーザーが特定した地点のピンポイント花粉飛散予測を返す機能があります。ユーザーから送っていただいた位置情報とLINE IDはFirestoreで管理しましたのでその辺りをまとめました。

##FirestoreのDatabase
・コレクションに位置情報をまとめた「locations」とLINE IDをまとめた「users」が作成されています。
・コレクション「locations」と「users」のドキュメントはユーザーがLINEを使うときに取得できるidで紐づけられています。
・コレクション「locations」のフィールドはユーザーから位置情報が送られてくるたびに更新されます（latitude緯度、longitude経度）。
・コレクション「users」のフィールドはユーザーのLINE IDが入ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/40e2d2c7-79fa-8a04-f8e4-d8fdb80a2b6a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/0d1d2e71-e69d-f7e5-705d-13c8f7c0e0bf.png)

##作成方法
**1. Firebaseで新規プロジェクトを作成**
・Googleにログインしている状態で、[Firebase公式ページ](https://firebase.google.com/)の右上にある「コンソールへ移動」ボタンから、ユーザーページに移動。
・「プロジェクトを追加」から新規プロジェクトを作成。

**2. Firestoreを作成**
・プロジェクトメインページ左のメニューバーから「Database」を選び、「データベースの作成」に進む。
・「テストモードで開始」を選択し、「有効にする」をクリックしデータベースを作成。

**3. Firebaseとnode.jsで開発したアプリを連携**
・Firebaseのプロジェクトのメインページから、「アプリを追加」→「ウェブ」に進む。
・任意のアプリ名を入力し、「アプリを登録」をクリックし連携に必要なコードを表示する。

**4. Firebase SDK を追加して Firebase を初期化**
こちらを参考にしました。
[Firebase を JavaScript プロジェクトに追加する](https://firebase.google.com/docs/web/setup?hl=ja)

**5. プログラム作成**
ユーザーからメッセージが来たらユーザーIDが登録されているかを判定
登録されてなければFirebaseに登録

```js
 let userRef = db.collection('users');
  let snapshot = await userRef.where("line_user_id", "==", event.source.userId).get();
  let user_id = "";
  if (snapshot.empty) {
    user_id = await userRef.add({
      line_user_id: event.source.userId
    }).then(ref => ref.id);
  } else {
    user_id = snapshot.docs[0].id;
  }
  console.log(user_id);
```

位置情報が送られてきたらFirebaseの位置情報をidに紐づけて更新し
「位置情報が登録されました」をユーザーに返す

```js
 if (event.message.type === "location") { 
    client.replyMessage(event.replyToken, {
      type: 'text',
      text: "位置情報が登録されました。"
    });
    let locationsRef = db.collection('locations').doc(user_id);   
    let setAda = locationsRef.set({
      latitude:event.message.latitude,
      longitude: event.message.longitude,     
    });      
    return Promise.resolve(null);
  } 
```

##完成図##
ピンポイント花粉情報がユーザーに返されます
<img width="375" alt="IMG-0997.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/d16714bb-f0ab-68db-2c82-175ac7048601.png">


##考察
最初はユーザーから送られるすべてのIDと位置情報をFirebaseに登録しif文で取得していたため、ユーザーが増えると処理に時間がかかりそうでした。idは重複がないように、位置情報は最新のものだけを登録できたのでスッキリして気持ちがよいですね。今後は内服薬やアレルギーの重症度、花粉飛散の実測値を登録・分析することによってユーザーの住んでいる場所の予測飛散量とユーザーの重症度から適切な治療薬を推奨できるようにしていきたいと思っています。
UCAM-DLE300Tの修理

HardoffのジャンクでELECOMの[UCAM-DLE300T](https://www.elecom.co.jp/news/201101/ucam-dle300t/index.html)を値札無しの110円で買ってきました。

Macにつないだところ認識しません。110円にはわけがありありました。

USB機器の故障はケーブルが原因のことが多いので確認してみます。

![写真（2020-02-22 13.28）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/a54b803a-8f44-25bc-bdf3-24f14071a753.jpeg)

赤のケーブルのVCCが切れてることが確認できました。

![写真（2020-02-22 13.58）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/7bedb939-b63f-34cd-6f9b-2b6e58678e61.jpeg)

ここで確認しても切れているのでAコネクタが原因のようです。今回はAコネクタですが、機器側の付け根が断線していることも良くあります。

ちなみにチップはVimicroのVC0342でした。EPROMが付いていてELECOMのVIDにしているものと思われます。ELECOMは他にはEtronのチップを使ったwebcamも作ってます。

最初にUSB電流電圧チェッカーで確認するのも良かったかもしれません。

ケーブルを外して別のものに変えてみたのですが、D+,D-のパターンを剥がしてしまい、結構無理やり直しました。

USBのケーブルやコネクタのパターンは弱いことも多いので、あまりいじらないようにするのが良いかもしれません。

ケーブルの真ん中で切って、ケーブルは外さずにコネクタを変える方がお手軽だったような気がします。

![スクリーンショット 2020-02-23 9.38.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/dd06ff8d-55f0-770b-1e0f-4c6706c0d295.png)

UVCなカメラなのでMacのPhoto Boothで使えます。

![original..png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/2bd64718-7495-a94c-9c89-a4ea72fdbd58.png)

結構綺麗です。

[以前試したmotion](https://qiita.com/yamori813/items/bacf57b4f5050444a0a9)で使ってみようと思っています。
正規表現でURLの余分な文字列を除去



```
import re

pattern = re.compile(r"(^[^-]*-[^-]*)-[^-,]*")

with open('out.csv', encoding='utf-8') as f:
    for row in f.readlines():
        m = pattern.match(row)
        if m:
            print(m.group(1))
```

out.csv

```
https://www.abcde.com/-0w69e7e1w00-あいうえお
https://www.abcde.com/-0w69e7e9w70-かきくけこ
https://www.abcde.com/-0w08e1e0w00-さしすせそ
https://www.abcde.com/-0w69e7e1w70-たちつてと
https://www.abcde.com/-0w69e6e2w54-なにぬねの
```
正規表現を使用し特定語句の前後に.*, .*|を挿入

# Anacondaに、pyperclipをインストール

```
conda install -c conda-forge pyperclip
```


# 下記コードを実行

```src = ''' ```
以下の文字列を変更可能

```
 # -*- coding: utf-8 -*-
import pyperclip


src = pyperclip.paste()
 
src = '''ことば
supeinn
いぬ
ねこ
たぬき
きつね
'''
dest = ''
for s in src.splitlines():
    dest += '.*{}.*|'.format(s)

print(dest)# コンソール出力
pyperclip.copy(dest) # クリップボード出力
```
[python] 関数を辞書にいれて管理する（コマンドテーブル、関数テーブル、関数ポインタ)

# はじめに
[★こちらを参考にさせていただきました!★](https://amzn.to/2xbp2Xv)

関数が増えたときは関数を辞書にいれてコマンド化すると管理しやすくなると@shiracamusさんに教えていただいたのでメモ。

https://qiita.com/mochihisa/items/2bb433636c4c615b0961#comment-f5565d1700921d4edc9f

# やりかた
関数テーブルのように関数ポインタに名前をつけてあげます。

こちらの記事と比較すると便利さがわかると思います（自虐）
[関数をリストに入れて管理する](https://qiita.com/osorezugoing/items/1d83360c121898cab77b#comment-6ae3f8588aea74d5813b)


```
├── modules
│   └──logic.py
│ 
└─ main.py
```

```python:modules/logic.py
def func1(word):
    print('こちらfunc1' + word)

def func2(word):
    print('こちらfunc2' + word)

def func3(word):
    print('こちらfunc3' + word)

def func4(word):
    print('こちらfunc4' + word)

def func5(word):
    print('こちらfunc5' + word)

def help_command():
    print("""\
func1 ---- func1を呼び出す
func2 ---- func2を呼び出す
func3 ---- func3を呼び出す
func4 ---- func4を呼び出す
func5 ---- func5を呼び出す
    """)

COMMANDS = {
    "func1": func1,
    "func2": func2,
    "func3": func3,
    "func4": func4,
    "func5": func5,
}

```

```python:main.py
import modules.logic as logic


logic.help_command()
logic.COMMANDS['func1']('です')
logic.COMMANDS['func2']('やで')
logic.COMMANDS['func3']('だよ')
logic.COMMANDS['func4']('にょろ')
logic.COMMANDS['func5']('だじぇ')
```

# 実行結果
```
$ python main.py

func1 ---- func1を呼び出す
func2 ---- func2を呼び出す
func3 ---- func3を呼び出す
func4 ---- func4を呼び出す
func5 ---- func5を呼び出す
    
こちらfunc1です
こちらfunc2やで
こちらfunc3だよ
こちらfunc4にょろ
こちらfunc5だじぇ
```
AWS Solution Architect Professional 取得 - 2020年

AWS Solution Architect Professionalを取得した。
3年後に恐らくは認定更新試験を受けているであろう自分に向けてのメモも兼ねて記録する。

## 試験準備
Udemyの練習テストがセールで1000円ちょっとで買えたので、2周ほどして75%以上取れるようにした。
https://www.udemy.com/course/aws-solutions-architect-professional-practice-exams-amazon/

全編英語なので下手したら本試験以上に辛い。Google翻訳で頑張るが、英語もある程度読む必要がある。これは日本語で本試験を受ける場合も同じで、意味不明瞭な日本語を発見し、英語で解き直すというプロセスは本試験そのままである。

みんな大好きBlakbeltは普段触れていないサービスを中心に読む。無味乾燥な試験問題と格闘している最中では最良の息抜きになりえる。
https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/

試験準備期間は2週間ほどだが実務でもAWSをバリバリ触っているのでアテにならない。 

##試験の難しさについて
今まで様々なペーパーテストを受けてきたが、この試験はなかなかに難しいと感じた。いくつかの理由があるように思う。

* 日本語の翻訳文がおかしい。明らかに日本語の意味のまま選択肢を選ぶと間違える問題がある
* 文章が長い。中～長文問題を75問、3時間にわたって解くのは人間の集中力限界を超えている。SAP試験のあとにTOEICを受けると驚くほど早く終る気がする
* 試験範囲が広く、実務で全く触れたことのないサービスが出てくる

##試験当日
普段あまり食べない朝食をしっかり食べ、リポビタンDを飲み、脳に刺激を与えるためにガムを噛むという念の入れよう。そのぐらい3時間の試験というのは長い。

試験の難しさへの対策として、少しでも文章をおかしく感じたら英語で試験を解き直す、25問ごとに30秒～1分ほどの休憩をいれる。全く聞いたこともないようなサービスが登場したら天を仰いで悪態をつく。「やれやれだぜ」

上記を手抜かりなく実施すると不思議なことに試験時間は残り3分とかになっている。
あとで見直そうとマークをつけていた問題が数えたら24問もあり、3分の1は見直せないだろjkと脳が見直し拒否したのですぐ試験終了した。

結果は80%ほどであった。合格ラインは75%なのでギリギリ。

## 心得
一石二鳥を狙わない。
SAP取るついでに英語の勉強もできたら最高じゃんと欲を出して練習問題とかUserGuideとか英語で読みきろうとした。
非常に疲れる。効率も悪い気がする。
試験に受かることが目的なら、とりあえずそのことに集中し、英語は別の機会に勉強したほうがいいかなと思った。

##これから
英語で受験したほうが本質以外のことに脳カロリーを回さなくて済む。
次回は、英語受験してみても良いかもしれない。