OmniAICreator/Qiita-1.07M huggingface dataset:
【ClarisConnect】FileMakerからGoogleカレンダーのスケジュールを登録する

#この記事でできること

ClarisConnectをつかって、ClarisFileMakerからGoogleカレンダーにスケジュール登録できるようにする。

※本記事ではFileMakerのスクリプト、Connectのフローの設定を中心に記載しています。各ツールのアカウント作成・セキュリティ設定などの初期設定については省略。
※筆者のうっかりでキャプチャはChromeの日本語翻訳をした状態になっています。（日本語版熱望）

#用意したもの
ClarisConnect
FileMakerProAdvanced18
FileMakerServer18
GoogleCalender

#できたもの
【操作】FileMakerでイベント日時を入力し、Googleカレンダーへ登録ボタンを押下。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/d46223fa-6c00-0266-dc45-25807208cf21.png)

【結果】指定した日時でGoogleカレンダーにスケジュールが新規登録される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/f01d2c88-c52f-640a-da9e-e1d7b8e108c3.png)


#設定方法
ClarisConnectで設定するアクションは２つだけ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/2b5eba01-7dc5-5f1a-a15a-fecee8c52026.png)

##【Connect】FileMaker スクリプトトリガ
アクションに追加するとFileMaker側で設定すべき情報と、コールバックURLが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/ef446015-eef7-06d4-a051-4391f81afbeb.png)

##【FileMaker】スクリプトを作成
Connectで表記された情報を元に、ボタン押下で実行するスクリプトを作成します。３ステップだけ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/e712b641-4a50-341e-c2df-12526c7d4681.png)

変数 $$JSONdata　の中身は下記のとおり。※最低限必要なものだけ抜粋

```ruby:qiita.rb
JSONSetElement ( "{}" ; 
 ["action" ; "script" ; JSONString] ;
 ["start" ;  Substitute ( 顧客::打合せ日 ; "/" ; "-" ) & "T" & 顧客::打合せ時刻 & "+0900" ; JSONString] ; 
 ["end" ; Substitute ( 顧客::打合せ日 ; "/" ; "-" ) & "T" & 顧客::打合せ終了時刻 & "+0900"  ; JSONString] ; 
 )
```
Connect側でタイムゾーンの設定がうまくいかなかったので、今回はGoogleカレンダーAPIに合わせてFileMaker側で日時を`yyyy-mm-ddThh:mm:ss+0900`に編集しています（もっといい方法があるかも）
※日時の末尾+0900がないと、協定世界時でスケジュール登録されるので実際と違う時刻で登録されます。

##【Connect】Googleカレンダー　イベントを作成
イベント作成は現在時刻で新規登録する平易なものと、上級者向けのアクションがあります。
本記事では上級者向けのアクションを選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/a0b512aa-8878-943f-75fc-4646b397cdf0.png)
カレンダー名：（事前にGoogleカレンダーの用意が必要）ドロップダウンリストからカレンダー名を指定
開始日時： 右の＋ボタンを押下＞前アクションのFileMakerを選択＞引数`start`を指定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/66faeb62-5702-bf3c-4446-d4dba5a4b840.png)
終了日時： 右の＋ボタンを押下＞前アクションのFileMakerを選択＞引数`end`を指定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/fdff09f5-bef8-91dd-e89c-086dca40e354.png)
イベント繰り返しルール：　今回は単発イベントなので空欄にする（デフォルトのコードを消去）


以上

#感想
上記では省略しましたが、参加者の設定もできます。普段からGoogleカレンダーを利用している場合、普段FileMakerを利用していない人や社外の人ともスケジュール共有ができて便利です。

本記事ではスケジュールの新規登録だけですが、作成したスケジュールのidを取得してFileMakerに保存しておくとスケジュールの変更・削除もできそうです。（できたらまた書きますね）
Raspberry PiでRTKLIBをインストール

#RTK-GNSSをやりたいからデータを送ろう!!
RTKを行う際、基準局と移動局の2つが必要です。
データ送信自体は、シリアル通信で来るものをtcpで飛ばしているだけのはず。

##用意するもの

* Raspberry Pi（Wi-Fiに接続できるもの）
* pc　データ確認用
* 接続用ケーブル類
* m8p(移動局用)
* GPSアンテナ


![機材](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549680/20dde0de-beb3-2d8e-ec6f-7bd85333dccc.jpeg)


##Raspberry PiにRTKLIBをインストール
ここからダウンロードしてきます


```
git clone https://github.com/tomojitakasu/RTKLIB.git
```

フォルダー移動


```
cd RTKLIB
cd app
```
続いて権限を付与します
そしてmakeall.shを実行することでRTKLIBのインストールができました。

```
chmod 755 makeall.sh

./makeall.sh
```


早速コマンドをたたいてデータ送信してみましょう

```
実行ファイルが存在するところに移動
cd /home/pi/RTKLIB/app/str2str/gcc

データ送信コマンド
./str2str -in serial://ttyACM0:115200 -out tcpcli://[IPaddress]

///////////////////////////////////////////////////////////

データ送信コマンド実行例
./str2str -in serial://ttyACM0:115200 -out tcpcli://192.168.11.7:5000
```
このほかにもいろいろなコマンドがあるのでぜひRTKLIBのマニュアルを読んでみてください
EC2からRDSに接続がうまく行かない時のチェックポイント

**はじめに**
ポートフォリオ作成中にEC2からRDSにうまく接続できずに丸一日費やしてやっと解決したので皆さんに共有したと思います。

###前提
- EC２でアプリケーションが動いている
- RDSをすでに作成済み

###やったこと
まず、DBクライエントからRDSにつながるか確認しましょう。
自分の場合、アプリケーションでつながらないなーってなってRDSの設定を変更してみたいな形で最初はDB接続の確認していたのですが、とにかくまずはSequelPro等を使って繋がるかどうか確認しましょう。

###SequelPro
![Screen Shot 2020-08-13 at 15.48.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321545/df0e28fb-72e3-9ac1-fdc7-4bf742380ae7.png)
ここにエンドポイント等を入れてつながれば、EC2からも繋がるはずですので、まずはここからアクセスできることを目標にする。

###RDSのチェックポイント
![Screen Shot 2020-08-13 at 15.33.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321545/cccaf514-a253-34cc-d004-244452c30bac.png)

- まずパブリックアクセシビリティが**あり**となっていることを確認する。
- 次にセキュリティーグループを確認
![Screen Shot 2020-08-13 at 15.40.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321545/0b1e453f-4b3e-698f-050c-59a2872882f8.png)
画像のようにセキュリティーグループにMYSQLを追加してポートを開放する

###終わりに
自分の場合は以上の２つで無事DB接続できるようになりました。RDS作成方法は他の方に記事を参考にしていただければ大丈夫だと思いますが、それでも自分のようにうまく接続できなかった場合はこの記事のチェックポイントをご確認いただき、問題解決につながれば幸いです。
審査本番で Admobがクラッシュしたと思うんですが手元ではクラッシュしないんです

## はじまり
App store の APPについて数ヶ月前に　AppleさんからiOS13 SDK使いなはれ、GoogleさんからAdmobのSDK換えなはれMailが来ていた。
対応しないとだめかなーとだらだら引き伸ばししていましたが、することになる。
配信APPでは特に問題がないのに、もぅーめんど草がとても大変な事となりました。

## 最初はMacさんが・・・
うちの　Macさん　High Sierraなんですが、Xcodeの新しいものはダメだとおっしゃる。
OSもアップグレードできんらしい。とても頑固なやつです。新入の登場となる
→ 審査用として中古のMAC購入。（ToT)/~

## はじめのクラッシュ
新入MACにて、　新しいXcodeでstoryboard使って、新しいGoogleSDK乗っけて終わり。のはずが
クラッシュ
→ Google SDKで引き起こされてた
　ググったら
　Info.plistにGADApplicationIdentifierがなくて❌
　[[GADMobileAds sharedInstance] startWithCompletionHandler:nil];がないので❌
　でした。
　修正して、足らない画像とか準備して審査提出

## はじめのお叱り
→ APPLEから　「クラッシュするから、ログ見て直してね」
実はシミュレータでは問題なかったのでOKかなと気にしていたのだが
やっぱり現物で確認しないとわからないから　渋々iPhoneSE購入となる。（ToT)/~
→ 現物で問題なし（無駄だったのかよ）
きっと何かの手違いと思いGoogle SDKを最新にして審査提出

## ２回目のお叱り
→ APPLEから　「クラッシュするから、ログ見て直してね」
へ？現物でOKだったのにー
ログを覗くと
　①EXC_CRASH (SIGABRT)
　②Thread 4 name:  Dispatch queue: com.apple.root.default-qos
　　Thread 4 Crashed:
→ よくわからんが　Dispatch　queue 使ってるので、何か問題あるのか解析
→ メモリー管理関連で怪しい部分あったので修正して審査提出

## ３回目のお叱り
→ APPLEから　「クラッシュするから、ログ見て直してね」
へ？また？
元々StoryBoard使っていなかったのですが使うように修正した時に何かチョンボ
したかなと確認して不足分修正して審査提出

## 4回目のお叱り
→ APPLEから　「クラッシュするから、ログ見て直してね」
そろそろノーヒントでは厳しくなってきてます。
ログをよくよく見ると機種がiPadでした（iPhone,iPad両対応だったんだ）
そこかーとシミュレーションで確認したら確かに操作でクラッシュする事確認
キター
対応して審査提出

## ５回目のお叱り
→ APPLEから　「クラッシュするから、ログ見て直してね」
やる気だいぶん失せてます。
こそっとiPadなしで審査提出したら、Xcodeから「ちゃんとサポートしなさい」と怒られる
やっぱり現物で確認しないとわからないから　渋々iPadmini購入となる。（ToT)/~
→ 現物で問題なし（また無駄だったのかよ）
これまでの間に他のAPPも審査提出したが問題なく通ってる事からadMobの有無に見える。
最新のSDKが出てたので入れ替えて審査提出

## ６回目のお叱り
→ APPLEから　クラッシュするから、ログ見て直してね
投げやりになってきてます。
adMob関連の記事、情報をかき集め設定する。
Info.plistの設定

	<key>gad_preferred_webview</key>
	<string>wkwebview</string>
とか
　　　　　NSLayoutConstraint constraintWithItem:　の追加とか

こちらで見て動作問題ないので審査提出

## ７回目のお叱り
→ APPLEから　クラッシュするから、ログ見て直してね
いいかげんやになってます。
ログの解析を真面目にやって確認した情報を持って確認
どうもadMobでクラッシュしている模様
まるで
Info.plistにGADApplicationIdentifierがなくて❌
のログに似てる
もしかして審査パッケージのplist間違えてるんではと思い

あっちこっちにInfo.plistがあるのでを整理
①テスト用の　.xctest含むファイルを削
②Info.plistの場所と名前変更
　build setting で plistで検索
　Packagingに設定がある。

とりあえず修正して審査提出

## ８回目のお叱り
→ APPLEから　クラッシュするから、ログ見て直してね
一体どなってんねん。こっちでは起こっとらんちゅーのに
でもadMobが関連している事は確かな模様

adMobでいろいろ実験して
設定関連（Info.plist）を最小にして、余分な設定（６回目のお叱り)も削除
GADMobileAds.sharedInstance().start(completionHandler: nil)
　のパラメータと睨めっっこ　

>completionHandler: 

「`広告を読み込む前に`、アプリで GADMobileAds.sharedInstance の startWithCompletionHandler: メソッドを呼び出し、Google Mobile Ads SDK を初期化する必要があります。これにより、SDK が初期化され、初期化の完了後（または 30 秒のタイムアウト後）に完了ハンドラが呼び出されます。この処理は 1 回だけ行います。アプリの起動時に行うのが理想的で、できるだけ早く呼び出す必要があります。」

とGoogleさんは言ってますが・・・・・そんなに急かされてもねぇ


んん？　`広告を読み込む前に` ??? 広告のリクエストはするけど　読み込みはGoogleさんSDKがするんで
ないかい？

つまり初期化が終わるまで待ちなさいって事？
終わったらこのハンドラが呼ばれるって事かい

実験実験

ハンドラの呼び出しとリクエストの呼び出しのタイミング見ると

ハンドラ関連
https://developers.google.com/admob/ios/api/reference/Classes/GADMobileAds
の　-startWithCompletionHandler:　参考


ハンドラは、どーもバックグラウンドで実行されてるようで、ハンドラが呼び出される前にリクエストしているようだ

！！！！！！！！！！！！

タイミングが早いとクラッシュ？？

## ファイナルアンサー
クラッシュは初期化が完了していない（Info.plist読み込み）時に広告読み込みしたので
クラッシュしたと推測、広告の処理は、ハンドラが呼び出されてから広告リクエストするようにに修正した

修正して審査提出



## "Ready for Sale".

Mailきましたー　　大当たり

 :dancer_tone3::dancer_tone3::dancer_tone3::dancer_tone3::dancer_tone3:　当たりどす
Smartyのtplファイルでデバッグする方法

## smarty
Smartyは、PHPで実装され、主にPHPアプリケーションで使用されるテンプレートエンジンです。
今回は、smarty側でのvar_dumpする方法の紹介になります。

tplファイル

```
{{$array_test = ["a" => "aaa", "b" => "bbb", "c"]}}

{{$array_test|@var_dump}}
```

viewページ

```
array(3) {
  ["a"]=
  string(3) "aaa"
  ["b"]=
  string(3) "bbb"
  [0]=
  string(1) "c"
}
```
と表示されます。
画面上で見やすくするためには

```
{$array|@debug_print_var}
```

でも良いかもしれません
npmでローカルにインストールしたコマンドを実行する

## エラー内容

チュートリアルのサンプルコードを実行しようとして、コマンドが存在しないエラーになりました。

```bash

% jest my-test --notify --config=config.json
zsh: command not found: jest
```

## 解決方法

コマンドは```./node_modules/.bin```に集められています。下記のようにパスを指定して実行してください。

```bash

% ./node_modules/.bin/jest --notify --config=config.json
```

# 追記

npm5.2.0からはnpxコマンドで同じことができますので、npxをご利用ください。

```bash
% npx jest --notify --config=config.json
```

npmのバージョン表示は

```
% npm -v
6.14.8
```

## 参照

npxの詳しい説明
https://qiita.com/tonkotsuboy_com/items/8227f5993769c3df533d

npxの公式リファレンス
https://www.npmjs.com/package/npx
Unity 3D入門 #14 [表示するテキストのデザイン]

今現在Panelを使用して表示させているテキストには以下の問題が発生しています。
1. 画面の大きさを変えるとはみ出す
2. フォントがダサい

まず、画面の大きさを変えるとテキストがはみ出す問題は、Canvas ScalarをConstant Pixel SizeからScale With Screen Sizeに設定することで解決しました。
参考URL：https://dojican-lab.blogspot.com/2015/08/unity.html

また、表示フォントに関してはhttps://qiita.com/saffron_furafoop/items/a210da60951626e6b12d を参考に簡単に変更できます。
【Python】文字列の埋め込みにはf文字列を使うべき

## 出典
この記事は「**Effective Python 第二版**」の項目4:「**Cスタイルフォーマット文字列とstr.formatは使わずf文字列で埋め込む**」を読んで、自分なりにまとめたものです。

## Pythonの文字列埋め込み
Pythonには文字列を埋め込む方法が大きく分けて以下3つある。

- %を使う方法
- str.format()を使う方法
- f文字列を使う方法

自分はあまり意識せずに使っていたのだけど、これを機にどれが適切なのかを考えたい。

##%を使う方法
JavaやC言語をやっている人からすると慣れ親しんだ方法。
 以下のように書く。

``` python
name = 'チーズ牛丼太郎'
age = 21 
print('私の名前は%sです。%d歳です。' % (name, age))
```

出力

```
私の名前はチーズ牛丼太郎です。21歳です。
```

うん。よさそうに見える。
でも実はこの方法にはいくつか問題がある。
次の例をみてみる。

``` python
name = 'チーズ牛丼太郎'
age = 21 
weight = 55.1525 
 
print('私の名前は%sです。%d歳です。体重はだいたい%dkgです。これからも%sをよろしくね。' % (name, age, int(weight), name))
```

**出力**

```
私の名前はチーズ牛丼太郎です。21歳です。体重はだいたい55kgです。これからもチーズ牛丼太郎をよろしくね。
```

上のコードには以下の4つの問題がある。

- **問題点1 : 型の順番を間違えるとエラーになる**

例えば上のコードで最初の`name`と`age`を逆にしてしまうと以下のエラーが出る

``` python
Traceback (most recent call last):
  File "cheese.py", line 8, in <module>
    print('私の名前は%sです。%d歳です。体重はだいたい%dkgです。これからも%sをよろしくね。' % (age, name, int(weight), name))
TypeError: %d format: a number is required, not str
```
１つめの型が整数, ２つめが文字列の型なので逆にするとだめということ。
常に型と順番に気をつけなければならない。

- **問題点2 : 長くなると読みづらくなる**

上の場合は`weight`を整数に変換したりしているが、代入する式が複雑になればなるほど可読性が下がる。
「どの変数がどれに対応するんだっけ？」
を注意深くみる必要がある。

- **問題点3 : 同じ値を使う場合に何回も書く必要がある**
上の例だと`name`という同じ変数を二回使っているが、右側のタプルにも二回書く必要がある。

- **問題点4 : 辞書を使うと冗長になる**

1と3の問題点はタプルではなく辞書を使うことで解消できる。
以下のように書けば良い。

``` python
name = 'チーズ牛丼太郎'
age = 21 
weight = 55.1525 
 
print('私の名前は%(name)sです。%(age)d歳です。体重はだいたい%(weight)dkgです。これからも%(name)sをよろしくね。' % {'age':age, 'name':name, 'weight':int(weight)})
```

出力は同じ。
このように書けば、二回出てくる`name`は一回でいいし、変数の順番も気にしなくてよくなる。
ただ、辞書を使ったことでさらに冗長でごちゃごちゃしてしまった。

## 組み込みのformatやstr.formatを使う方法
次に`str.format()`を使った方法をみていく。

``` python
name = 'チーズ牛丼太郎'
age = 21 
print('私の名前は{}です。{}歳です。'.format(name, age))
```
こんな感じで書く。
また、以下のようにindexを設定して変数の順番を変えることもできる。

``` python
print('私の名前は{1}です。{0}歳です。'.format(age, name))
```

先ほどの例に当てはめる。

``` python
name = 'チーズ牛丼太郎'
age = 21 
weight = 55.1525 
 
print('私の名前は{0}です。{1}歳です。体重はだいたい{2}kgです。これからも{0}をよろしくね。'.format(age, name, int(weight)))
```
indexを使うことで上記の問題１と３は解決できそう。
ただ、`%`で辞書を使う方法に比べるとすっきりとはしたものの、やはりまだ冗長である。

## f文字列を使う方法
最後にf文字列を使った方法を考える。
こんな感じで書く。

``` python
name = 'チーズ牛丼太郎'
age = 21 
weight = 55.1525 
 
print(f'私の名前は{name}です。{age}歳です。')
```
さきほどの例に当てはめる

``` python
name = 'チーズ牛丼太郎'
age = 21 
weight = 55.1525 

print(f'私の名前は{name}です。{age}歳です。体重はだいたい{int(weight)}kgです。これからも{name}をよろしくね。')
```
`%`や`str.format()`を使った方法に比べてかなりすっきり書けていることがわかる。
変数を右側でタプルや辞書、`format()`で指定するのではなく、直接埋め込んでいるため可読性が高い。
簡単なコードであればどれを使っても変わりないが、複雑になればなるほどf文字列を使うほうがよさそうだ。


## まとめ
- Pythonで文字列を埋め込む方法をまとめた
- f文字列を使う方法が一番可読性が高いので良さそう
- ちなみに`str.format()`は`Python2.6`、f文字列は`Python3.6`以上でないと使えないので注意
Biopython Tutorial and Cookbook和訳(4.5)

## 4.5  References
[4.4へ](https://qiita.com/chaos44/items/efd8a84d610e70a0408f)

Another common annotation related to a sequence is a reference to a journal or other published work dealing with the sequence. 
**別の配列に対するannotationとしてreferenceがあります。**

We have a fairly simple way of representing a Reference in Biopython – we have a Bio.SeqFeature.
**私たちはとても簡単な方法で参考文献を表せます。 - たとえばBio.SeqFeature**
Reference class that stores the relevant information about a reference as attributes of an object.
**Referenceクラスは参考文献関連の情報をストックできます。**

The attributes include things that you would expect to see in a reference like journal, title and authors. 
**reference属性はジャーナル名、タイトルおよび作者の情報を有しています。**

Additionally, it also can hold the medline_id and pubmed_id and a comment about the reference. 
These are all accessed simply as attributes of the object.
**さらに、medline_id、pubmed_idおよびリファレンスに関するコメントも保持できます。
そしてattributeのようにアクセスしやすいです。**

A reference also has a location object so that it can specify a particular location on the sequence that the reference refers to. 
**またreferenceはlocationも持っているため、参照している文献の配列をlocationで特定することができます。**
For instance, you might have a journal that is dealing with a particular gene located on a BAC, and want to specify that it only refers to this position exactly. 
**たとえば、ある文献は人工染色体のある特定の遺伝子について言及しているのあれば、ちょうどlocationを使ってそのpositionを特定できます。**
The location is a potentially fuzzy location, as described in section 4.3.2.
**4.3.2で紹介したように、locationはfuzzy locationかもしれないです。**

Any reference objects are stored as a list in the SeqRecord object’s annotations dictionary under the key “references”. 
**referenceはリスト型でSeqRecordのannotations辞書型に保存されている。辞書のキーは"references"。**

That’s all there is too it. References are meant to be easy to deal with, and hopefully general enough to cover lots of usage cases.
**それだけのことです。referenceはとても使いやすいので、いんろな役に立つと祈ります。**

[4.6へ](https://qiita.com/chaos44/items/79cabbfe8c006583d038)
DSL element 'android.dataBinding.enabled' is obsolete and has been replaced with 'android.buildFeatures.dataBinding'. の解消

## 問題
Android Studio4.0にバージョンアップしてからコンパイルした際に以下のようなwarningが出ていた。

```
DSL element 'android.dataBinding.enabled' is obsolete and has been replaced with 'android.buildFeatures.dataBinding'.
```
## 解決
原因：データバインディングを有効にするコードブロックが新しくなったため。

```app/build.gradle
android {
    ...
    dataBinding {
            enabled = true
    }
    ...
}
```
↓こちらに変更すれば良い。

```app/build.gradle
android {
    ...
    buildFeatures {
        dataBinding true
    }
    ...
}
```
Laravel APIの使い方メモ

## はじめに
前回、LaravelのフレームワークとRestAPIについてすこしお話しました。
今回は、自分が初めて使ったフレームワークの使い方が間違っていたためそのときの記事を書いていきたいと思います。
この記事は、あくまでも自分の開発では

前回の記事に、ざっくりとしたMVCのことを少し書いているので、もしよろしければこちらもご参考ください
`https://qiita.com/Yami_37/items/49cda10828a23d08dfaa`

## APIの使い方
まず、私がAPIで使うために、はじめに考えていた間違ったMVCの認識ですが
→MVCなのだから、Model、View、Controller、ひとつずつ存在し
　ControllerでViewとAPIのデータ、両方returnしてあげる
ものだと思っていました。がControllerではviewとデータの両方の値を基本返しません。

自分はAPIController、APIModelを作らず、黄色のControllerで

```
return view ( '/hello.blade.php/' ,compact('data'));
```

と記述し、viewとデータ両方を返していました。

下の図で触れていますが、イメージとしましては、黄色のcontrollerではviewのみを返してあげます。
　→APIController（赤）でreturnするものはあくまでも「データ」です。

<img width="833" alt="スクリーンショット 2020-08-13 14.40.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418704/2cfe56d6-1afe-f0c8-d6b5-895346f6ce75.png">

そのために、API用のControllerとModelを作成する必要があります。
View でAPIControllerのindexを使いたい場合の流れとしては

1. routesのwebでRoute::get('URL', 'Controller@index')にし、あくまでも、ただの「controller（黄色）」でAPIを呼び出します。
2. Model（緑）で 「file_get_contents」か「curl」などを使いAPIControllerを実行します
3. APIから帰ってくるデータはあくまでもJsonデータなどにし、純粋にPHPデータ使用したい場合も、Modelでデータ変換をします

ModelでAPIを叩くときは以下のような形で実装をしました。
file_get_contentsでgetする場合

```
public function getApiController(){
      $url = //任意のAPIURL
       $get_api_index = file_get_contents($url);
       // jsondataをPHPのデータに変換
       $get_api_index = json_decode($get_api_index, true);
       $data = $get_api_index["//受け取りたいデータ"];
       return $data;
   }
```

curlでputする場合は

```
public function putApiController(Request $request){
        $url = //任意のAPIURL
        $curl = curl_init($url);
        
        $data = $request->toArray(); //配列にしたい場合
 
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT'); // ※
        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data)); // ※
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($curl);
        curl_close($curl);
         
        $data = json_decode($response);// 配列からオブジェクトに変換
        return $data;
    }
```

※余談 `$response_code = curl_getinfo( $curl, CURLINFO_HTTP_CODE );`
エラーが発生したかどうかを確認できる（正常なときは200がかえってくるはず）
ラズパイ3にNode-RED環境を構築する

# 目的
　部屋の温度がどのように変化しているのかラズパイとセンサを使用して計測します。
　最初にNode-REDの環境を整えます。

# Node-REDとは
 JavaScriptをベースにしたビジュアルプログラミング言語で、各機能(ノード)をつなぎ合わせていき、
入力→処理→出力の流れを作っていきます。
ノードにセンサやMQTTブローカーのノードが用意されているので、IoT機器の制御が容易なことです。

# 準備
 1.ラズパイ(Raspbianがインストール済み)
 2.Node.jsがインストール済み

# インストール
 npmコマンドを使用して、Node-REDをインストールする。
>$sudo npm install -g --unsafe-perm node-red

## 実行する
 node-redコマンドで実行できます。
ラズパイはメモリ搭載量が少ないので、最大使用量を制限します。
> $node-red--max-old-space-size=128

## Node-REDの環境にアクセスします。
 Webブラウザ上でプログラミングできるため、下記のサイトにアクセスします。
 >http://localhost:1880

## 終了する
 Ctrl + Cで終了します。

## 自動起動させる設定
 PM2を利用してラズパイ起動時、Node-Redを起動させます。

## インストール
 >$sudo npm install -g pm2

#PM2経由でNode-REDを起動する
>$pm2 start /usr/bin/node-red --node-args="--max-old-space-size=128" -- -v

#起動時に実行することをPM2に指示する
>$pm2 save
>$pm2 startup systemd

#再起動
>$reboot

#参考資料
 https://nodered.jp/docs/getting-started/local
 https://nodered.jp/docs/faq/starting-node-red-on-boot
[Java]ビルドしたwarファイルのJDKバージョンを確認する

(Javaの初心者による、メモ書きです)

JavaのwarファイルがJDKのバージョンいくつでビルドされたものか確認したい時があります。
そんな時には、以下のコマンドで確認することが出来ます。
まずは、warファイルを解凍します。

Tomcatのドキュメントルートでwarファイルが解凍されていればその中のクラスファイルを参照します。
ローカルに存在するwarファイルの場合は、拡張子をzipに変更し、zipファイルを解凍します。

example.war -> example.zip

解凍後、どれでも良いのでクラスファイルが存在するディレクトリへcdコマンドで移動します。

```
javap -v [クラスファイル名]
```
※クラスファイル名には、拡張子".java"は含めません。

実行結果の中に

```
major version: 52
```

のように出力された場合、その値から44を引きます。

52 - 44 = 8

ということで、JDK バージョン8で、ビルドされたものということが分かります。
【Python】Django の管理者サイトの URL を変更する

#はじめに
管理者URLの変更は、セキュリティ対策の１つ(みたいです）。

`~/admin/` では簡単に管理者サイトのログイン画面に到達できてしまいます。
URLの変更は、簡単かつ割と効果的な対策です。

##変更してみる
至って簡単。

```python:urls.py
urlpatterns = [
    # path('admin/', admin.site.urls), # デフォルトは admin
    path('admin-custom-url/', admin.site.urls),
]
```

##終わり
簡単で当たり前なことかもしれませんが、以上です。
これも備忘録ってことで！

セキュリティ対策は入念に行いたい、そう思う今日この頃です。
ESP32レーザー彫刻機試運転

NEJEのレーザーモジュールはドライバ内蔵であった。
（ドライバ買っちゃったよ・・・）

レーザー側のコネクタ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664748/93cb0b85-697f-d5c0-1035-fa7c8781b810.png)

TTLをgrbl_ESP32の3.3VPWMに接続すれば制御可能。
12VとGNDもgrbl_ESP32に繋いでおいて大きめ（2A以上）の電源を使えばOK。

ちなみに、5VPWMはspindle enable信号がないと動かないので
下記の変更が必要。
config.h
// #define SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED // Default enabled. Comment to disable.
（コメントアウトする）
Laser modeはスピンドル回転数が0なので、spindle enable信号が出ない。
spindle enable信号がないとレベルシフタが動作しない。
（5VPWMは外付けレーザードライバを接続するときに必要）

今後はコントローラをケースに入れて配線を綺麗にする予定
論文読み

#はじめに
論文読みの**毎日投稿**をお盆明けから行います．
まず，対象とする論文の学術的な**領域**を説明します．．
また，投稿の**テンプレート**を定義します．

#対象の学術領域
先日の投稿のように対象とする領域は以下です．

- Human-Computer Interaction
- Multimodal Interaction

機械学習や深層学習の基礎技術に関しては，他の**賢い**方々がまとめてくださるはずです．
本投稿では，そのような最新の学習アルゴリズムを取り上げる予定はありません．
(たまに書きますが...)
それらのデータハンドリング技術を活用して，ヒトの心理や言動を解析した結果，
実現可能な事例をとりあげます．
インタラクションの対象は限定せず，以下の組み合わせを取り上げます．

- Human-Agent Interaction
- Human-Robot Interaction
- Human-Human Interaction
- Agent-Agent Interaction

#テンプレート


変に考えずに，落合陽一先生の[テンプレート(スライド番号48,65)](https://www.slideshare.net/Ochyai/1-ftma15)に沿って記述します．
項目は以下です．
> 「どんなもの？」
「先行研究と比べてどこがすごい？」
「技術や手法のキモはどこ？」
「どうやって有効だと検証した？」
「議論はある？」
「次に読むべき論文は？」

あくまでも**備忘録的な位置付け**で投稿して行きます．
【iOS】Pythonista3でGIFアニメのコマごとの表示時間を変更する。

# はじめに
以前、[GIFアニメでハマった記事](https://qiita.com/maboy/items/17816eda284d1fefd5e5)を書く際に[GIFフォーマットの詳細](http://www.tohoho-web.com/wwwgif.htm#ImageBlock)という素晴らしい記事が見つけました。
GIFファイルの中の画像にはそれぞれディレイタイムが2バイトで設定されており、0.01秒単位で設定できるようです。

# 目標は【Graphic Control Extension】
GIFファイルの中には画像データがあるのは当然ですが、画像データの前には**Graphic Control Extension**という8バイトのブロックがあるそうです。
### Graphic Control Extension
- Extension Introducer(1B) = 0x21　　 <= 印 1
- Graphic Control Label(1B) = 0xf9　　<= 印 2
- Block Size(1B) = 0x04　　　　　　　<= 印 3
- R(3b),DM(3b),UIF(1b),TCF(1b)
- Delay Time(2B)　　　　　　　　　　<= ここがディレイタイム
- Transparent Color Index(1B)
- Block Terminator(1B) = 0x00

# バイナリエディタで確認
ディレイタイムを1秒にセットしたGIFアニメをバイナリエディタで確認してみました。

![5A681C6A-B727-43D3-BDCA-E817CD2029F7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280129/8cae55b5-1002-066a-2989-bf3a2b9dce23.png)
ちゃんと印1～3`0x21f904`に続いてディレイタイム`0x6400`があります。
**1秒**で設定してるので**0.01**で割ると**100**なので、`100 = 0x0064`となり、リトルエンディアンで格納すると`0x6400`で間違いありません。
この値をゴニョゴニョすれば**コマごとの表示時間を変更**できるということですね。

# やってみよう

```python:ChangeDelay.py
# GIFファイルをバイナリデータとして開く。
FileName = 'test.gif'
with open(FileName,'rb') as f:
	Bin = f.read()

# Graphic Control Extentionを探して位置とディレイ値をListに記録する。
GCE = b'\x21\xf9\x04'
DelayList = []
point = 0
while point < len(Bin):
	start = Bin.find(GCE,point)
	if start<0:break
	delay = int.from_bytes(Bin[start+4:start+6],byteorder="little")
	DelayList.append([start+4,delay])
	point = start+1

# 最初の1枚を1秒に、半分以降を5倍の長さに変更する。
DelayList[0][1]=100
for i in range(1,len(DelayList)//2):
	DelayList[-i][1]*=5

# バイナリデータを書き換える。
for point,delay in DelayList:
	Bin = Bin[:point] + delay.to_bytes(2,byteorder="little") + Bin[point+2:]
	

# バイナリデータをGIFとして保存。
with open('temp.gif','wb') as f:
	f.write(Bin)
```

### Before
20枚の画像全てが0.05秒に設定。
![90E284C4-F734-4E82-B99E-6F4636142A32.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280129/b2be46b7-a6ca-c034-3a8c-bca06caeef4f.gif)

### After
最初の1枚を1秒にして、半分以降を5倍に書き換えました。
![DEA4F364-7E69-4607-BA68-2711AC552EDF.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280129/f805cb6d-8cd7-47d0-5ee6-e464f143be14.gif)
github-readme-statsをGitHub以外で使うと素敵

## 先に結論だけ

[![ReadMe Card](https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats)](https://github.com/anuraghazra/github-readme-stats)

GitHub Readme Statsを使うと ~~Qiitaや~~ Blogにもリポジトリカードが貼り付けられます。素敵です。

:::note info
2021/11/15追記
Qiitaがリンクカード機能をサポートしました。Qiitaの記事でリンクを装飾する場合、特別な処理は不要です。
:::

https://qiita.com/release-notes#%E8%A8%98%E4%BA%8B%E3%83%9A%E3%83%BC%E3%82%B8%E5%86%85%E3%81%AEurl%E3%82%92%E3%82%AB%E3%83%BC%E3%83%89%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%A7%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F

## GitHub Readme Statsとは

### GitHubプロフィール

GitHubプロフィールとは、ユーザーのプロフィールページ（https://github.com /【ユーザーネーム】）に自由に略歴を追加する機能です。ユーザー名と同名のパブリックリポジトリを作成し、READMEファイルを設置します。そのREADMEファイルはプロフィールページに自動的に表示されます。

> If you add a README file to the root of a public repository with the same name as your username, that README will automatically appear on your profile page. You can edit your profile README with GitHub Flavored Markdown to create a personalized section on your profile.

[GitHub : プロフィールについて](https://docs.github.com/ja/github/setting-up-and-managing-your-github-profile/about-your-profile)

参考記事 : [GitHub profile(readme.md)の最新情報まとめ](https://qiita.com/syui/items/67038ea6b7f7a42bbdd8)

### GitHub Readme Stats

[github-readme-stats](https://github.com/anuraghazra/github-readme-stats)は、このGitHubプロフィールを装飾するサービスです。GitHubアカウントのさまざまな情報を分析し、プロフィールカードを生成します。生成されたカードはWebAPIからSVG画像として呼び出せます。

### GitHub Extra Pins

GitHub Readme Statsには[GitHub Extra Pins](https://github.com/anuraghazra/github-readme-stats#github-extra-pins)というAPIがあります。このAPIはリポジトリの言語、スター数やフォーク数などの詳細を表示します。このAPIは、GitHubプロフィール内でオススメのリポジトリを目立たせることを目的としています。

## GitHub以外のサービスからも呼び出せる

GitHub Readme StatsはGitHubに限らず、オンラインであればどこからでも呼び出せます。

### MarkDown

Qiitaのようにマークダウンエディターのあるサービスであれば、[利用例](https://github.com/anuraghazra/github-readme-stats#usage)にある書式そのままで記事中にリポジトリカードを追加できます。
 
```md
[![ReadMe Card](https://github-readme-stats.vercel.app/api/pin/?username=<ユーザー名>&repo=<リポジトリ名>)](https://github.com/<リポジトリのURL>)
```

[![ReadMe Card](https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats)](https://github.com/anuraghazra/github-readme-stats)

### html

htmlタグの利用が許可されているサービスなら、imgタグのsrc属性にAPIエンドポイントを指定すればSVG画像が読み込めます。


```html
<img src="https://github-readme-stats.vercel.app/api/pin/?username=<ユーザー名>&repo=<リポジトリ名>">
```

<img src="https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats">

## リポジトリカードの効果

GitHub Extra Pinsのカードは、読者にリポジトリを瞬時に伝えられます。読者が高速でページをスクロールしていても、カードがあればそこでスクロールを止めてくれる可能性が高まります。みなさんが自身のリポジトリを多くの人に知ってもらいたい場合、この視認性の高さは強力な武器になります。


以上、ありがとうございました。

## 参考記事

[GitHub Readme Stats を利用してGitHubプロフィールをカッコよくする](https://qiita.com/zizi4n5/items/f8076cb25bbf64a9bc1c)
Mauticのフォーム結果メールにコンタクトのポイント、ページURLをのせる

Mauticのフォーム結果メールに
・コンタクトのポイント数
・コンタクトページのURL
をのせたい場合。

ポイント数は
 {contactfield=points}
でとれる。

コンタクトID が
 {contactfield=id}
で取れるので、URLのパラメータにして
コンタクトページのリンクにできる。

![2020-08-13_143606.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490937/fc2262a1-7b60-d6c9-dc9f-18f54b5329b9.jpeg)


※なぜか公式ドキュメントのページに載っていない？
参考）https://docs.mautic.org/en/setup/variables
belongsToManyの引数

#用途
多対多の関係を持たせるためのメソッド
#引数に何を入れるか
usersとrolesが多対多の関係を持っている
Userのモデルに記載するbelongsToManyの書き方

```
belongsToMany('User側の外部キーがあるテーブルがあるクラス名',
'User側の外部キーがあるテーブル名',
'リレーションを定義しているモデル(User)の外部キー名',
'結合するモデルの外部キー名')
```
Next.js + Docker でホットリロードが効かない

# 問題
Next.jsアプリをDockerを使用して、devモードで立ち上げた際に、ホットリロードが実行されない

# 解決法
- `CHOKIDAR_USEPOLLING=true`を実行環境の環境変数に追加する
- docker-composeを使用していれば`environment`で渡してあげれば良い

CreateReactAppではトラブルシューティングに乗っています
https://create-react-app.dev/docs/troubleshooting/
Flutter　Intlパッケージ DateFormatの日付を日本語にする

#Intlパッケージを使う
公式ドキュメントは[こちら](https://pub.dev/packages/intl#-installing-tab-)

```yaml:pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  intl: ^0.16.1
```

これで保存すれば勝手に入れてくれる。

#DateFormatの日付を日本語にする
デフォルトでは英語なので、これを日本語にする！

```dart:main.dart
import 'package:flutter/material.dart';
import 'package:intl/date_symbol_data_local.dart'; // 追加
import './transaction.dart';
import 'package:intl/intl.dart'; // 追加

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    // 初期化のためのメソッドを追加
    initializeDateFormatting('ja');

    return MaterialApp(
      title: 'Flutter App',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
      // 省略
@override
  Widget build(BuildContext context) {
   return Scaffold(
       appBar: AppBar(
         title: Text('Flutter App'),
       ),
       body: Column(
         // 省略
           Text(
             DateFormat.yMMMd('ja').format(tx.date),
             style: TextStyle(color: Colors.grey),
           )
        // 省略
      )
   }
}
```

<img width="191" alt="スクリーンショット 2020-08-13 14.37.13.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/7518f7b8-0994-066d-46b3-f18491db6e42.jpeg">
こんな感じで日本語になる。

```dart
DateFormat.yMMMd('ja').format(tx.date),
```

`tx.date`の部分はご自身のコード内で使うDateTimeクラスの値を入れてね！
【SwiftUIパターン】Environment Modifiers

# 名前
**Environment Modifiers**[^1]

# コンテキスト
SwiftUIでは`.environment<V>(_ keyPath: WritableKeyPath<EnvironmentValues, V>, _ value: V) -> some View`[^2]というAPIがView Modifiersとして用意されており、これはシステム・自作を問わずEnvironmentValue[^3]を注入するための便利なAPIです。

例えば、あるコンテナビューの中身を全て利用不可にしたい場合は、以下のように記述すればコンテナ以下のヒエラルキー全てに環境値を注入し、利用不可と出来ます。

```swift
Container {
    ViewA()
    ViewB()
}
.environment(\.isEnabled, false)
```

# 問題
環境値を多く利用するViewにおいて、このAPIだけだと以下のように同じ記述が何度も続き、直感的ではなくなってしまう問題があります。

```swift
Text("abc")
    .environment(KeyPathA, value1)
    .environment(KeyPathB, value2)
    .environment(KeyPathC, value3)
    .environment(KeyPathD, value4)
    .environment(KeyPathE, value5)
```

そこで、**頻出のものにはシンタックスシュガーを与えたい**です。

# 解決法
`Environment Modifiers`パターンを利用して、環境値注入のシンタックスシュガーを提供します。

例えば、標準のコンポーネントを見ても、[Text](https://developer.apple.com/documentation/swiftui/text)の`font(Font?) -> Text`というAPIは`.environment`のシンタックスシュガー[^4]です。

```swift:environment
Text("abc")
    .environment(\.font, .body)
```

```swift:糖衣構文.swift
Text("abc")
    .font(.body)
```

## Environment Modifiers実装例
Viewのextensionにメソッドを足すだけの簡単な実装方法です。この時、`some View`を返却値とします。

```swift
extension View {
    func accessibilityEnabled(_ enabled: Bool) -> some View {
        self.environment(\.accessibilityEnabled, enabled)
    }
}
```

## Environment Modifiers + 自作キー実装例
EnvironmentKeyから自作をする場合には以下のように実装します。この例では、SwiftUIの現状のAPIに不足しているfirstResponderについての環境値を注入することとしています。

```swift

struct FirstResponderKey : EnvironmentKey {
    static var defaultValue: Bool = false
}

extension EnvironmentValues {
    var firstResponder : Bool {
        get {
            return self[FirstResponderKey.self]
        }
        set {
            self[FirstResponderKey.self] = newValue
        }
    }
}

extension View {
    func firstResponder(_ value: Bool) -> some View {
        self.environment(\.firstResponder, value)
    }
}

// 利用箇所でのサンプル
struct YourClientView : View {
    @Environment(\.firstResponder)
    private var firstResponder: Bool
    
    var body: some View { ... }
}
```

# 関係するパターン
今のところ思いついて無いです。

# Contribution
名前は勝手に付けており「もっとこの名前の方が端的に概念を表せているのはないでしょうか？」や「このようなパターンとして記述した方が良いのではないでしょうか？」などの議論は歓迎していますので、どうぞよろしくお願いします。

[^1]: 命名は、以下の記事から借りてきました。https://www.hackingwithswift.com/books/ios-swiftui/environment-modifiers

[^2]: https://developer.apple.com/documentation/swiftui/link/environment(_:_:)?changes=latest_beta

[^3]: https://developer.apple.com/documentation/swiftui/environmentvalues

[^4]: 内部実装を見たわけでは無いので、推測です
WordPressをnginx使ってサブディレクトリで公開する

基本は [WordPress | NGINX](https://www.nginx.com/resources/wiki/start/topics/recipes/wordpress/)
 に書いてある設定をすれば良い。
対象のサブディレクトリのlocationでtry_filesを追加する。


大事なのは、サブディレクトリのtry_filesの書き方で、こうやって書く。
**`=404` を入れないこと。**

```
location /wordpress {
        try_files $uri $uri/ /wordpress /index.php?$args;
}
```


最後に `=404` を入れてしまうと、not foundが出続けます。
この書き方はNGです。

```
location /wordpress {
        try_files $uri $uri/ /wordpress /index.php?$args =404;
}
```
DockerfileでローカルPCの環境変数を利用する。。。ことはできないっぽい

っぽいのだけど、`docker-compose.yml`に書くことはできる

## 利用方法

- `AWS_ACCESS_KEY_ID: "${AWS_ACCESS_KEY_ID}"`のように書く
- ローカルの環境変数を定義しておく

```bash

export AWS_ACCESS_KEY_ID=AAA
```

## 書き方

```docker-compose.yml
version: '3' # composeファイルのバーション指定                                                    
services:
  server: # service名
    build: ./server/ # ビルドに使用するDockerfileがあるディレクトリ指定
    environment: 
      AWS_ACCESS_KEY_ID: "${AWS_ACCESS_KEY_ID}"
      AWS_SECRET_ACCESS_KEY: "${AWS_SECRET_ACCESS_KEY}"
    ports: 
      - "8080:8080"
    tty: true # コンテナの起動永続化
    volumes:
      - .:/go/src/work # マウントディレクトリ指定
```

## 確認
```
yuta:~ $ docker exec -it a9f8b66d9a6f echo $AWS_ACCESS_KEY_ID
AAA
```
markdown-pdfをつかってmarkdownからpdfを生成

# 目的

Markdownで書かれた文章をpdfに変換したい




#  [markdown-pdf](https://github.com/alanshaw/markdown-pdf)

##インストローラーの準備

Homebrew を使ったことがなければターミナルに以下を打ち込んでください（詳細は[Homebrewのインストール](https://qiita.com/zaburo/items/29fe23c1ceb6056109fd)）

```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```
yarnを使ってインストールすることにしたのでhomebrewを使ってyarnのインストール。



```
yarn global add markdown-pdf
```

npmを使ってインストールすることもできるそうです。

##markdown-pdfインストール

```
brew install yarn
```
これでmarkdown-pdfがインストールできます。


##pdfに変換
markdownファイル(sample.md)があるディレクトリで以下を実行してpdfを生成

```
markdown-pdf sample.md
```
これで実行ディレクトリに、`sample.pdf`が生成されます。
JavaScriptの制御構文(3)〜for命令〜

# はじめに

こんにちは。
今日は、昨日に引き続き、繰り返し処理についての投稿です！
昨日は、while/do...while命令のまとめでしたが、今日は、for命令です！

# for命令
指定回数だけ、ループを処理する命令にfor命令があります。それではまず、書き方を見てみましょう！

```
for (初期化式; 継続条件式; 増減式) {
	ループ実行する処理
}
```
上記のように、for命令では、
* 初期化式で、まず変数を初期化する。最初に格納する変数の値を決める。
* 継続条件式では、どこまで、ループを続けるかを指定する。
* 増減式で、ループを繰り返すにあたり、変数を加算していくのか、減算していくのかを決める。
このようにして、ループの回数を指定して、ループを実行していきます。
次の例を見てください。

例)

```
for (x = 0; x <= 5; x++) {
	console.log(x)
}

// 結果
// 0
// 1
// 2
// 3
// 4
// 5
```
上記では、
* 初期化式で、変数x=0にして初期化。
* 継続条件式では、変数xが5以下の間、ループが継続するように指定。
つまり、変数xが0(初期化式で指定した値)から5(5以下であるため、5を含む)の間ループが継続することを意味します。
* 増減式では、変数xを1ずつ加算していくことを指定。(0→1→2→3→4→5)

また、カンマを使って、初期化式、継続条件式、増減式を複数指定することも可能です。

すいません、今日は次の項目との兼ね合いもあって、簡単に、for命令の説明だけにさせて頂きます！
不備等ございましたら、コメントにお願い致します！

## 参考文献

山田祥寛著『[改訂新版]JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで』(2018)
※第1刷は、2016年。
オブジェクト指向はゲームづくりに向かない その３


その１：https://qiita.com/mas-yo/items/43101d2e5ef073a1f3f5
その２：https://qiita.com/mas-yo/items/f802b5a6a6b3f47eed71


**オブジェクト指向はゲームづくりに向かない**のその３です。

これまで、オブジェクト指向の「継承」の仕組みと、「オブジェクトをクラスで表す」仕組みが、ゲームづくりにとっては柔軟性が低く、複雑なコードになりがちで、バグを生みやすいことを示して来ました。

では、この問題を解決するためにはどうしたら良いでしょうか？

### Entity Component System

そこで筆者が提案したいのが、Entity Component System (以下ECS)による設計です。

ECSというと、UnityのECSを想起する人が多いかも知れませんが、ここでは、一般的なECSによる設計の話をします。
また、UnityのECSでは、どちらかというと実行速度にフォーカスが当たった説明がなされがちですが、ここではECSの設計の柔軟さ、メンテナンス性の良さについて、主に話題にします。

ECSについての予備知識として、[Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3%E3%83%BB%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%83%BB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0)や、["Entities, components and systems” by Mark Jordan](https://link.medium.com/SSROjZaPh8)を軽く読んでおいた方がいいかもしれません。


では、その１で示した、見下ろし型のアクションゲームをECSで実装するとどうなるか、見ていきたいと思います。
同じ流れで、設計を進めてみます。

### 開発初期

まず開発の初期段階では、プレイヤーと敵がいて、動かして攻撃ができる、程度を作ることになったとしましょう。
エンティティ、コンポーネント、システムの構成を図にしてみました。（クラス設計図だとイメージがつきにくいので、動作時のメモリの状態を描いています）

![ecs1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227302/5e155402-bbdd-f636-ad3c-e1208d3547b2.png)


水色は各種コンポーネントのインスタンス、黄緑は、システムを表す関数です。

各コンポーネントにはエンティティIDが割り振られています（図の紫色の◯）。エンティティは、プレイヤー、敵などのキャラ（オブジェクト指向で言うオブジェクト）を表し、生成される度にユニークなIDが割り当てられます。

ECSでは、プログラム上にPlayer,Enemyといったクラスはありません。
この図で言えば、InputとPositionを持つエンティティは、プレイヤーとして振る舞う、AIとPositionを持つエンティティは、敵として振る舞う、という事になります。

コンポーネントは単なるデータで、機能を持ちません。様々なゲームロジックはシステムの方で記述します。
各システムの動作を見てみましょう。

- Inputシステム

Inputシステムは、Inputコンポーネントを更新するためのシステムです。
OS等の環境からキー入力を取得し、Inputコンポーネントの「進みたい方向」のデータをセットします。

- AI システム

AIシステムは、AIコンポーネントを更新するためのシステムです。
ここでは、AIは単に「進みたい方向」だけをデータとして持っています。
AIシステムは、Positionコンポーネント（のリスト）から、敵の位置を見つけ出し、自分の位置との差分を計算することで、「進みたい方向」をセットします。

※本当は、`MoveIntent` コンポーネント（進みたい方向を表すコンポーネント）を１つ作った方が良いと思いますが、ここでは簡単のために、Input,AIがそれぞれ進みたい方向を持つことにしています。

- Velocityシステム

InputまたはAIの情報を元に、そのフレームでの速度を決定します。
将来的に、コリジョンの計算もここで行うことを想定しています。


- Positionシステム

Velocityの情報を元に、Positionを更新します。


一応ここまでで、プレイヤーと敵キャラが動く仕組みまでできました。

上の図を、システムとコンポーネントの関係に着目して図に描いてみると、こうなります。

![ecs2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227302/23433ceb-50ef-efdd-ef60-01ef4358c854.png)


システムは図の上から順番に呼ばれます。こうして見ると、各コンポーネントが何に依存して変化しているか、データが上から順番に変化しながら伝搬している様子がわかると思います。

さて、ここまでで移動の処理はできたのですが、攻撃してそれがヒットする様にするのは、さらに実装が必要になります。
新たに `Animator`コンポーネント、`AttackCollider`コンポーネント、`DefenseCollider`コンポーネントを追加します。

![ecs3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227302/dadb7578-953f-a412-8ff2-4e3c8498f60d.png)

攻撃の当たり判定はアニメーションに依存するので、Animatorコンポーネントでアニメーションのフレーム値を管理し、それに連動してコライダが変化するようになっています。

ここでは省略しますが、DefenseColliderの「ヒットしているフラグ」が立っていたら、別のシステム（`Health`システム的なもの）で、ダメージ計算とHPの減算などを行います。

ここまでで、土台の実装は完了です。


### １ヶ月後

さて、開発が始まって１ヶ月が経ちました。ここで企画から「空を飛ぶ敵を作りたい」という要望が来たとします。
空を飛ぶ敵の要件は

- 障害物の上を通れる
- プレイヤーの物理攻撃は当たらない
- アイテムをドロップする際は、周囲の通れる場所にドロップする。

だったとします。

次の実装に移りたいところですが、長くなってしまったので、その４で・・・
計算ドリルアプリの開発①　１＋１を答えさせるアプリ

私には小学1年生の息子がいます。勉強嫌い、ゲーム大好きな息子なので、計算アプリなんかがあると少しは勉強してくれるかなぁと思い、作ってみようと思います。

# はじめに
### 開発環境
- OS:Windows 10（1903)
- 開発ソフト：Visual Studio 2019 Community
- プラットフォーム：Xamarin.Forms
- 開発言語：C#

### 環境の準備
以下を参照ください。
[Xamarin.FormsでAndroidアプリ開発](https://qiita.com/yasu006/items/1c29af89bce513245d6a)

# 超簡単なアプリから。１＝１を答えさせるアプリ
### Mainpage.xamlの修正点
以下のコードを追加します。

```ruby
<Label Text="１＋１＝？"/>
<Entry x:Name="answer" Placeholder="こたえをいれてね" Keyboard="Numeric" />
<Button Text="かいとう" Pressed="OnButtonPressed" />
<Label x:Name="message" Text="" />
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672017/3c1a4994-02c6-f444-a30a-6c513d024392.png)

少し解説します。

- <の後の文字
項目の種類を表します。
    - **Label**：単純にテキストを表示する項目です。
    - **Entry**：入力項目です。
    - **Button**：タップできるボタンです。
- その後の文字
項目のオプションになります。
    - **Text**：画面に表示させる文字になります。
    - **x:Name**：コードで使う変数になります。例えば一番下のx:Name="message"のLabelでは、message.textに""（空白）が入ることになります。例えばコードで```message.txt = "せいかい"```と記述すると、画面に「せいかい」と表示されるようになります。
    - **Placeholder**：Entry（入力）の際に、入力箇所に薄く表示させる文字列になります。
    - **Keyboard**：入力時のキーボードの種類を選択できます。今回**numeric**としているので、数字のキーボードが表示されるようになります。他にも**Default**(既定)、**Email**(メールアドレス)、**Telephone**(電話番号)、**Text**(テキスト)、**Url**(Webアドレス)などがあります。
    - **Pressed**：タップされたときに呼び出すクラスを定義するものです。

実際の画面はこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672017/ef71b5b5-e35d-2251-5e76-136015301ef8.png)


### MainPage.xaml.csのコード
以下のコードを入れます。

```ruby
private void OnButtonPressed(object sender, EventArgs e)
{
    if (answer.Text == "2")
    {
        message.Text = "せいかい、すごいね！";
    }
    else
    {
        message.Text = "ぶぶぶぶぶぶぶぶぶっぶーーーーーーーーーーー";
    }
}
```
単純なコードなので解説するまでもないかもですが、Mainpage.xamlのx:name="answer"で設定したEntry項目から回答された文字を読み込み、正解（２）である場合とそれ以外の場合で表示させるテキスト文字を場合分けしています。
少し注意点としては、Text属性は文字列となりますので、```answer.Text == 2```だと文字列と数値の比較になりエラーになります。"2"とすることで文字列と文字列の比較となりエラーになりません。


# いざ実行
「こたえをいれてね」をタップすると、数字の入力画面が出てきます。2を入れて決定マークをタップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672017/1a10a72e-e580-3d2a-aae9-44fec979a4e6.png)

「こたえる」をタップすると、せいかいの文字が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672017/2e85364e-6378-5730-7b80-5b12634e143e.png)

ちなみに2以外の文字を入れると、不正解の文字になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672017/4fc27e7b-be3e-e2ba-b559-adb0510eb683.png)
DBにてデータ登録時に入力必須ではないカラムの処理の仕方

#1 想定ケース
PHPでメンバーがログインしてメッセージを投稿するという機能を実装すると想定。投稿データはpostsというDBに保存します。
『よくわかるPHPの教科書 【PHP7対応版】 』（マイナビ出版）p267ページで躓いたことによる学びをメモします。

##1-1 投稿を保管するデータベース

| カラム      |位置付け |設定|
|:-----------------|:-------------------|:------------------|
|id|ID|INT、プライマリーキー、オートインクリメント|
|message|ユーザーが投稿したメッセージ|TEXT|
|member_id|ユーザーID|INT|
|**reply_post_id**|**投稿が別の投稿への返信だった場合、その別の投稿のID**|INT|
|created|投稿日時|DATETIME|

reply_post_idは、投稿が返信だった場合のみ発生するので、これだけ必須項目ではないという状況です。そのようなカラムをどう処理するかという記事です。

##1-2 投稿をDBに登録するPHPのコード

```php:index.php
if (!empty($_POST)) {
  if ($_POST['message'] !='') {
    $message = $db->prepare('INSERT INTO posts SET member_id=?, message=?, created=NOW()');
    $message->execute(array(
      $member['id'],
      $_POST['message']
    ));
    header('Location: index.php'); exit();
  }
```
#2 問題
投稿が返信ではない場合、つまり通常の投稿の場合、上記のコードではエラーが起きて投稿がDBに保存されません。
試しにphpMyAdminで同じSQL　→ INSERT INTO posts SET member_id=?, message=?, created=NOW(); を実行すると、下記メッセージが出ます。
>MySQL said:
>\#1364 - Field 'reply_post_id' doesn't have a default value

このことから「reply_post_idが空ですよ〜」というエラーが発生していると推定できます。


#3 解決に向けて
##3-1 ３つの解決策
(1) SQLでreply_post_idに適当に値を入れる（下記コードご参照）

```php:index.php
$message = $db->prepare('INSERT INTO posts SET member_id=?, message=?, reply_post_id=0, created=NOW()');
```

(2) DBの設定でデフォルト値をNoneではなくAs defined : にして適当にデフォルト値を入れておく。（0とか）

(3) DBの設定で、Nullにチェックを入れておく。（デフォルト値をNULLにすることと同義。）

##3-2 最善策は？
reply_post_idは、返信する場合にのみ、返信先のポストのidを入れる項目です。つまり返信でない通常の投稿の時は、値が必要ありません。よって、このケースでは３を選択するのがベストという結論に至りました。
0などの意味のない値をDBに入れることは混乱にも繋がるのでなるべく避けた方がいいそうです。例えば、他の人がそれを見た時に「0って何？どういう意味？」と混乱させることになりかねないからです。

#最後に
初めてのqiita投稿になります。もしご指摘などあれば頂戴できますと幸いです。
ありがとうございます。
Line BOTを触ったときのメモ

# line bot

## 概要
LineBotを触ることがあったので、その時のメモ
LineBot側の設定は、省略
とりあえず、環境づくり

LineBotは、Lineからの通信を受ける必要があったため、
サーバをネット上に公開が必要
それはできないので、ngrokを利用

## 環境
* OS: centos
* フレーム: Laravel

## centos 初期設定
```
$ yum install epel-release
$ rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
$ yum install -y wget bzip2-devel gcc gcc-c++ git autoconf vim rpmdevtools
$ ln -s /usr/lib64/libssl.so /usr/lib/libssl.so
$ yum update -y
```
#### php install
```
$ yum install --enablerepo=remi,remi-php71 php php-devel php-mbstring php-pdo php-gd php-xml php-mcrypt php-fpm
$ curl -sS https://getcomposer.org/installer | php
$ mv composer.phar /usr/local/bin/composer
$ cp /etc/php.ini /etc/php.ini.org
$ vi /etc/php.ini
---------------------------------
date.timezone = "Asia/Tokyo"
mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
mbstring.http_input = UTF-8
mbstring.http_output = pass
mbstring.encoding_translation = On
mbstring.detect_order = auto
mbstring.substitute_character = none
---------------------------------


$ cp /etc/php-fpm.d/www.conf /etc/php-fpm.d/www.conf.org
$ vi /etc/php-fpm.d/www.conf
---------------------------------
user = nginx
group = nginx
---------------------------------
```

### nginx install

```
$ vi /etc/yum.repos.d/nginx.repo
---------------------------------
[nginx]

name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1
----------------------------------


$ yum install nginx -y
$ systemctl enable nginx
$ systemctl start nginx

```

### nginx laravel setup
```
server {
    listen       80;
    server_name  localhost;

    access_log  /var/log/nginx/linebot_access.log;
    error_log   /var/log/nginx/linebot_error.log;

    root /usr/share/nginx/linebot/projectname/public;

    location / {
        index  index.php index.html index.htm;
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
```

### ngrok install
```
$ cd /tmp
$ wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
$ unzip ngrok-stable-linux-amd64.zip
$ mv ngrok /usr/local/bin/
$ rm ngrok-stable-linux-amd64.zip
```
Sikuli開発で気を付け(てい)ること

# さいしょに
個人的にSikuliはあまり好きでない。
それでもコレを使わなければいけなくなる…ということが多々ある。

Uipathを導入する資金がない少額案件だったり。
自分トコで使うからOSS使おうぜという方針だったり。
前の開発者が何を思ったのかSikuliで開発していたり…！だ。

もしかすると
これは「Sikuli使うなら素Pythonでいいやん」という偏見のある記述かもしれないが、
決して「Sikuliは使えないヤツだ！」と嘆いているわけではない。
注意して使えば何だって「自分が書いたように動く」ものなのだ。

# Sikuli開発の注意点
## 端末に依存しやすい
sikuliは「画像認識型」と呼ばれるRPAツール。
ディスプレイの解像度が違う…とか、背景画像が違う…とかちょっとした違いですぐに動かなくなる。
透過やマスクをすることもできるようにはなったが心もとない。
OSのバージョンアップや、端末の個別な設定でフォントが変わったりしても動かなくなることも不安要素なのだ。

とはいえ、sikuliにもtypeコマンドという「キーボード操作」で端末を動かす機能が存在する。

IEを起動するにしても

```py
doubleClick("IEの画像")
```

でなく

```py
type('r', Key.WIN)
type('iexplore.exe')
type(Key.ENTER)
```
と書いた方が端末の依存はなくなるだろう。
結局そうやって書くなら素でPython書くのと同じじゃね？と思ってしまう。

## Python3に対応していない
sikuliの言語はJythonという「JavaVM上で動くPython」だ。
「普通のPythonと何が違うか？」はあまり気にせずに組めると思って良い。

このJython。
Python3には対応していないのだ。
なんなんsikuliしぬのん…？Jythonしぬのん…？

Python2とPython3との違いというと
print関数の使い方が変わったとか、
数値の取り扱いが変わった…ということしか思いつかないので、参考の記事を。

[Python2からPython3.0での変更点 - Qiita](https://qiita.com/cstoku/items/353fd4b0fd9ed17dc152)

因みにsikuliではJRubyという言語(JavaVM上で動くRuby)も利用が可能だが…サンプルですらあまり見たことはない。

## 日本語入力が面倒
日本語入力には`paste`コマンドを利用するのだが、

```py
# typeコマンドと間違えがち
type('日本語')

# 文字化けさせがち
paste('日本語')
```

…というミスを多々する。
久しぶりに触ると確実に`type`コマンドは打ってるだろう。
正しくはUTF-8への文字コード指定を加えた書き方になる。

```py
paste(u'日本語')
```
よく考えると何気に一番間違えている部分かもしれない。

## レコーディング機能など無い
レコーディング機能というとExcelにある「マクロの保存」のように、
自動化したい手順を操作することで、自動的に生成される機能のこと。

Uipathであればこういう機能があるのだが、
さすが無料というべきかそのような便利機能はsikuliには用意されていない。
いやいや、こんなの許容範囲である…と言いたいのだが、
Uipathを触った後だとどうしても比較をしてしまう。

## 新しいsikuliXだとコマンドのリストがなくなったらしい
…なんで？まじでなんで？

コマンドリスト…というのはGUIで命令を選択できる便利機能。
素PythonよりもRPAツールを使う時の強みだと思っているのだが…
コレがなくなるとは。。

私は一歩手前である1.1.3のバージョンまでしか使っていなかったので全く知らなかったがこちらの記事によると次のバージョンでは無効化されているらしい。
[Sikuri 1.1.4でコマンドバーが表示されない。 - Qiita](https://qiita.com/keyaki80/items/9e5dc5c1839a07d5ebbf)

~~うーん。続報がないので今の2.0.4で復活しているのかどうかがわからん…
次の開発でSikuli使うことはわかってるから、新しいの入れてみるかーという感じ。
前述の日本語問題とかコマンドリストあっても間違えてたからあんまり変わらん…と言われればそれまでかもしれない。~~
**追記(2020/08/19)**
続報が見つからないもので、2.0.4をインストールした。
コマンドリストはなくなっていた…日本語問題とかどうでもよくなるぐらいめちゃくちゃ不便になった。泣きたい。

# おわりに
日曜プログラマでない限り、何等かの制約は必ずついてくる。
あれができない！これができない！
と嘆いて「利用しない」という選択肢を取るのは簡単だが、
過去の遺物が好みでないからサックリ捨て去るのは必ずしも良いわけではないし、
新しいものを生み出す際の引き出しは多い方が良いだろう。

それぞれの見出しこそネガティブだが解決方法は用意されている。
sikuliでできないのはレコーディング機能ぐらいだろう。
そう。注意して使えば何だって「自分が書いたように動く」ものなのだ。
Dockerでmysqlに接続できない(GO/gin/GORM)

# 状況
Dockerで簡単なSPAアプリケーションの作成中にDBサーバとして作成したMySQLコンテナにバックエンドサーバ(GO/gin)がアクセスする際に

```console
panic: dial tcp 127.0.0.1:3306: connect: connection refused
```

というエラーが発生する。
以下にエラーが発生したコンテナの情報とソースコードを記載し、最後に解決策を示す。

## コンテナの設定

### ネットワーク
```console
$ docker network create app-nw
```

### DBコンテナ
```console
# コンテナを作成して起動
$ docker run --name app-db --network app-nw -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql
# 作成したMySQLコンテナに入りテーブルとレコードを作成
$ docker exec -it app-db bash
$ mysql uroot proot
mysql > create database shop;
mysql > use shop;
mysql > create table Product (
    -> ID int NOT NULL PRIMARY KEY,
    -> Name varchar(50) NOT NULL,
    -> Author varchar(50) NOT NULL
    -> );
mysql > insert into Product values (1, 'banana', 'tanaka');
# 確認用
mysql> select * from Product;
+----+--------+--------+
| ID | Name   | Author |
+----+--------+--------+
|  1 | banana | tanaka |
+----+--------+--------+
1 row in set (0.00 sec)
mysql > exit;
$ exit
```

### バックエンドコンテナ
```console
# コンテナを作成して起動
$ docker run --name app-webapi --network app-nw -p 8080:8080 -it ubuntu /bin/bash
# 必要なパッケージを導入
$ apt update
$ apt install -y wget
$ apt install -y git
$ wget https://golang.org/dl/go1.15.linux-amd64.tar.gz
$ tar -C /usr/local -xaf go1.15.linux-amd64.tar.gz
$ export PATH=$PATH:/usr/local/go/bin
$ go version
# インストールできていればバージョンが表示される
go version go1.15 linux/amd64
$ go get github.com/gin-gonic/gin
$ go get github.com/go-sql-driver/mysql
$ go get github.com/jinzhu/gorm
```

#### ソースコード
main.go

```go
package main

import (
  "fmt"
  "github.com/jinzhu/gorm"
  _ "github.com/jinzhu/gorm/dialects/mysql"
)

type Product struct {
  ID int `gorm:"primary_key;not null"`
  Name string `gorm:"type:varchar(50);packanot null"`
  Author string `gorm:"type:varchar(50);packanot null"`
}

func connect() *gorm.DB {
  DBMS := "mysql"
  USER := "root"
  PASS := "root"
  PROTOCOL := "tcp(localhost:3306)"
  DBNAME := "shop"
  CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME
  db, err := gorm.Open(DBMS, CONNECT)

  if err != nil {
    panic(err.Error())
  }

  db.Set("gorm:table_options", "ENGINE=InnoDB")
  db.SingularTable(true)
  db.AutoMigrate(&Product{})

  fmt.Println("db connected: ", &db)
  return db
}

func getAllProduct() [] Product {
  db := connect()
  var products []Product
  db.Find(&products)
  defer db.Close()

  return products
}

func main() {
  results := getAllProduct()
  fmt.Println(results)
}
```

## 実行結果
```console
# /appにmain.goを作成して実行する
$ go run main.go
panic: dial tcp 127.0.0.1:3306: connect: connection refused
```

# 解決策
main.goのconnect関数を以下のように修正する。

```go
func connect() *gorm.DB {
  DBMS := "mysql"
  USER := "root"
  PASS := "root"
  PROTOCOL := "tcp(app-db:3306)"
  DBNAME := "shop"
  CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME
  db, err := gorm.Open(DBMS, CONNECT)
}
```

## 解説

dockerでgo(gin/gorm)サーバからDBコンテナを指定する場合は`localhost`や`127.0.0.1`ではなく`<コンテナ名>`を指定する。
今回はコンテナ名が`app-db`なので

```go
PROTOCOL := "tcp(app-db:3306)"
```

とすれば良い。