OmniAICreator/Qiita-1.07M huggingface dataset:
nginxのBASIC認証

# nginxサーバを立ててBASIC認証を行う
## 実行環境
(GCPのVM上で行いました)
ubuntu: 18.04
nginx: 1.19.1
## 実装
以前とnginxのデフォルトのconfファイルが変更されている模様。
どの記事を真似しても上手くいかず、手間取ってしまったので記しておく。
### nginxのインストール
```
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install nginx
```
### 認証用usernameとpasswordの設定
.htpasswdファイルを/etc/nginx/以下に配置。(通常はここ)  
二行目は、htpasswdコマンドを使うためにパッケージのインストール
そして、登録したいusernameとpasswordを設定する。

```
$ sudo touch /etc/nginx/.htpasswd
$ sudo apt-get install apache2-utils
$ sudo htpasswd -c -b /etc/nginx/.htpasswd [USERNAME] [PASSWORD]
```
ちなみに、```htpasswd```コマンドでは、-cで新しく.htpasswdファイルを生成するので、2回目以降にユーザを追加する際には外す。

### confファイル

/etc/nginx/conf.d以下の```*.conf```がincludeされる設定になっているはずなので、拡張子の前の名前はなんでも良い。
ここでは```hoge.conf```としておく。
- 80番ポートで接続を待ち受ける
- rootで指定したディレクトリ以下のページを表示
- 表示したいhtmlファイルは、indexラベルを貼って登録しておく(←個人的忘却ポイント)
- ```location /```以下の```auth_basic```は認証のダイアログの設定
- ```auth_basic_user_file```では認証情報の設定ファイルを指定。
 
```
/etc/nginx/conf.d$ cat hoge.conf 
server {
    listen       80 default_server;
    server_name  0.0.0.0;
    root         /var/www/html;
    index index.html index.htm index.nginx-debian.html;
    location / {
            auth_basic "Please Login";
            auth_basic_user_file /etc/nginx/.htpasswd; 
    }
}
```
### confファイルの確認
以下のコマンドで、confファイルの文法の確認をする。
下の二行のような表示が出ればOK:)

```
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```

### 読み込み
今行った設定を読み込ませて表示させる。

```
$ sudo nginx -s reload
```
上手くいかない場合は、

```/etc/nginx/nginx.conf``` から、 ```/etc/nginx/sites-enabled/``` をincludeする設定を消すことを試してみて欲しい。

今度はログイン試行の回数制限なんかも設けてみようと思います。
パスワードリストにあるパスワードは登録できないようにしたりしてみたい:fire:
最近のrbenvの問題点

最近のrbenvの問題点

$ rbenv -v
rbenv 1.1.2-34-g0843745
８月２日〜１０日間に更新がなければ、全てこのバージョンと思われる

古いMacOSXでいろいろと試行錯誤中におきたこと。
１．openssl や curl の問題かは不明だが、rbenvが行うruby 2.5.8のダウンロードに失敗する。
２．ダウンロード失敗にエラー表示が不足している。この為、１の時に原因がopensslかcurlかcert.pemがユーザーには全く不明。

ダウンロード出来れば何でもいいという話になる。しかし

３．iterm2上からコマンドで、curl -KO または-LOで
https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.8.tar.gz
のダウンロードには成功する。訳が分からないよ。

以下はMacOSX El Capitan 10.11でおきたこと。
４．openssl 1.1.1gがインストール済みでパスが通っていても.rbenv下に別途インストールする。
５．rbenv install 2.5.8でダウンロード成功する。
この時、
ruby 2.0.0と
$ ruby -ropenssl -e "p OpenSSL::X509::DEFAULT_CERT_FILE"
"/System/Library/OpenSSL/cert.pem"
のままで
/usr/local/bin/opensslの1.1.1g
/usr/local/bin/curlの7.71.1
の組み合わせで成功するのはどういうことなのか？
curlで通信していると思われるがwget？
古いcurlが使われている？

```curl7.30.0
$ /usr/bin/curl --version
curl 7.30.0 (x86_64-apple-darwin13.0) libcurl/7.30.0 SecureTransport zlib/1.2.5
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IPv6 Largefile NTLM NTLM_WB SSL libz
```

６，これはユーザー側の問題だが、

```
export PATH="$HOME/.rbenv/bin:$PATH"
```

が公式だと不要？ネットの解説だと必要と書かれている事例が多く、不要なガイドもある。
最新版（rbenv 1.1.2）はbash_profine(zshenv)に追加しないと動かない。

以下のコマンドを行う。

```
$ echo "$(rbenv init -)"
export PATH="/Users/xxxxxxx/.rbenv/shims:${PATH}"
```

pbenvもパス追加をしている。これもrbenvのプログラム側で行われるべきでは？

参考１．重要かもしれない（2015年の記事）
[rbenv + ruby-build はどうやって動いているのか - takatoshiono's blog](https://takatoshiono.hatenablog.com/entry/2015/01/09/012040)

homebrew と rbenvで大きくディレクトリが異なる。
本来はprefix指定やインストール後のリンクを張ることで複数ディレクトリでも問題がないはずだがhomebrew と rbenv共に色々とオカシイのでは？

結論
上記問題が解決しない限りrbenvを使わずに、当分はrubyソースビルドしてパス切り替えがベストと考える

参考２
[rbenvは何をしているのか？ - ザリガニが見ていた...。](https://zariganitosh.hatenablog.jp/entry/20141101/what_does_rbenv)
[SQLServer]TCP/IP有効化について

# はじめに
SQL ServerのDBに対して別アプリケーション（Windowバッチ、SSIS etc...）からアクセスする場合、SQLServerのTCP/IP設定を有効化する必要がある。
※SQL Server 2016では、デフォルトで無効化されている。2014など他バージョンも同様のはず。
ここでは、SQLServerのTCP/IPを有効化する手順を説明する。

★SQLServerに接続できねぇ。ウーン！って悩んでいる人の原因は、私の経験上は半分ぐらい、コレが原因。

# 前提
SQL Server 2016 Developerで確認
（2012 2014 など、他バージョンもほぼ同じはず）

# 手順
1. SQLServer構成マネージャーを起動する。
Windows+S ⇒ SQLServerManager13.msc と入力して起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217757/13395c28-5275-cd37-8c47-8852eb31733a.png)

※13 の部分は、SQLServerのバージョンによって異なる模様

1. TCP/IPの設定を有効化
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217757/3876d903-b47b-4c5b-ce54-5dbeef426fa0.png)


1. SQL Serverのサービス再起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217757/92f64484-0a28-3764-9f90-0643f58e9ced.png)


# SQLServer構成マネージャーが起動しない場合の対応

構成マネージャーが起動しない場合は、以下を試そう。
[SQL Server 2008 で SQL Server 構成マネージャを開く際にエラー メッセージ "WMI プロバイダに接続できません。権限がないかサーバーにアクセスできません" が表示される](https://support.microsoft.com/ja-jp/help/956013/error-message-when-you-open-sql-server-configuration-manager-in-sql-se)
※sqlmgmproviderxpsp2up.mof　の格納先は、SQLServerバージョンにより異なる。
初回のgit initしたときのエラー（解決済）

#起きたエラー

GitHubでレポジトリを作成後、初回コミットとして以下のコマンドを実行した。

```
git branch
echo "# project名" >> README.md
git init
git add README.md
git commit -m "first commit"
```

実行すると、以下のエラーコードが発生（一部抜粋）。


```
*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: empty ident name (for project) not allowed
```

#解決方法

まだまだ、黒い画面での作業に抵抗あり、あたふたしていましたが、
冷静に読んでみると、ヒントがありました。

```
Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"
```

gitは、私が誰だかわかっていなかったようで、
ヒントのとおり、自分のメールアドレスとユーザー名をコマンドたたく。

その後、再び、初回のinitのコマンドを実行したら問題なく初回コミットができました。
WindowsバッチでSQL ServerのDBフルバックアップファイルをサクッと採取する

# はじめに
Windowsバッチで、SQL Serverのフルバックアップを採取する方法について説明する。

# 前提
- 検証環境：Windows10 Home  SQL Server 2016 Developer
- バッチファイルと同一サーバー(localhost)でSQL Server稼働

# 処理概要
- Windows認証でDB（DB名：SANDBOX1）に接続
- フルバックアップのファイルを採取し、D:\SQLServerBackup\DB1.bak　に出力

# バックアップ処理Windowsバッチ作成
以下のようなバッチを作成する。

```SQLSVDBbackup.bat
SET PORT=1433
SET DBSV=localhost
SET INSTANCE=MSSQLSERVER
SET DBNAME=SANDBOX1
REM バックアップ出力先
SET BKUP_DIR=D:\SQLServerBackup

REM バックアップファイル名
SET BKUP_FILE_NAME=DB1.bak

REM フルバックアップ
sqlcmd -S %DBSV%\%INSTANCE%,%PORT% -Q "BACKUP DATABASE %DBNAME% TO DISK='%BKUP_DIR%\%BKUP_FILE_NAME%' WITH INIT, COMPRESSION"
REM バックアップ生成失敗時
IF NOT EXIST %BKUP_DIR%\%BKUP_FILE_NAME% GOTO BKUP_ERR

GOTO END

REM エラー処理
:BKUP_ERR
  ECHO バックアップに失敗
  EXIT /B 9

REM 正常終了
:END
  EXIT /B 0
```
以下、実行結果抜粋

```
D:\SQLServerBackup>sqlcmd -S localhost\MSSQLSERVER,1433 -Q "BACKUP DATABASE SANDBOX1 TO DISK='D:\SQLServerBackup\DB1.bak' WITH INIT, COMPRESSION"
データベース 'SANDBOX1' の 384 ページ、ファイル 1 のファイル 'SANDBOX1' を処理しました。
データベース 'SANDBOX1' の 2 ページ、ファイル 1 のファイル 'SANDBOX1_log' を処理しました。
BACKUP DATABASE により 386 ページが 0.052 秒間で正常に処理されました (57.851 MB/秒)。
```

### 実行結果確認
以下のようにDB1.bak　ファイルができていれば成功。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217757/37c9f688-10d4-5ffc-72f3-db080fc5a418.png)


# トラブルシューティング
接続情報もろもろが正しいのに、実行時に以下のエラーが発生する場合、TCP/IPが無効化されている可能性が高い。
SQL Server構成マネージャーの設定を見直すこと。

```
Sqlcmd: エラー: Microsoft ODBC Driver 13 for SQL Server: TCP Provider: 待ち操作がタイムアウトになりました。
Sqlcmd: エラー: Microsoft ODBC Driver 13 for SQL Server: Login timeout expired。
Sqlcmd: エラー: Microsoft ODBC Driver 13 for SQL Server: A network-related or instance-specific error has occurred while establishing a connection to SQL Server. Server is not found or not accessible. Check if instance name is correct and if SQL Server is configured to allow remote connections. For more information see SQL Server Books Online.。
```

# 補足
- 当サンプルはフルバックアップファイルを採取するのみ。差分バックアップを採取する場合は必要な処理を実装すること。
- 日次バックアップしたい場合は、当batファイルをタスクスケジューラーなどで毎日実行できるようにしてやればOK。
- 当バッチはサンプルとして同一サーバーにbakファイルを出力しているが、ファイルサーバー等にコピー・リネームする処理など必要に応じて実装すること。
【Ruby】条件分岐内で標準出力を使う方法


アルゴリズム問題を解くときのようにgetsを使って標準入力を入れようとしたところ以下のようなエラーになった

```
$ ruby enc_main.rb new
Traceback (most recent call last):
        2: from enc_main.rb:12:in `<main>'
        1: from enc_main.rb:12:in `gets'
enc_main.rb:12:in `gets': No such file or directory @ rb_sysopen - new (Errno::ENOENT)
```

対処方法

以下のコードに$stdinを使ったgetsメソッドを使うと解消した。

```
if ARGV[0] == "new"
  puts "What's Name?"
  name = $stdin.gets

```


参考にしたドキュメント

[$stdin (Ruby 2.7.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/method/Kernel/v/stdin.html)
[Rubyでstdinを使う方法を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン](https://techacademy.jp/magazine/30075)
numpyでdequeみたいな使い方をする場合どう書くと速いのか

# やりたいこと

numpy.ndarrayでdequeみたいなことがしたい場合、単純にnp.append(x, y)とnp.delete(x, 0)とするのが速いのか、それともdequeを使ってからndarrayにしたほうがいいのかというのを検証します。

```python:遅そうだと思われる疑惑のコード
x = np.append(x, 1)
x = np.delete(x, 0)
```
最後に1という値を追加して先頭を削除しています。

numpyはarray作成時に固定長の領域を確保するみたいなので長さを変えるとなんだか遅そうです。今回の検証はFIFO【先入先出法 / First-In First-Out / 先入れ先出し】の話しみたいですが、先頭を読み出さず全体を読む場合を想定してます。つまりバッファーのような使い方の場合の検証となっています。

追加するごとにnumpy.mean()やnumpy.std()を使いたいので、最後はnumpy.ndarrayになるように条件を限定しました。単純に配列を作るだけならdequeをそのまま使ったほうが速いですが、それだとnumpyのmean()やstd()をそのままつかえないのです。

今回はループごとにnumpyの関数を使うことを仮定して、変換コストも込みで比べてみたいと思います。

# 代替候補

## numpy.roll()を使う

    x = np.roll(x, -1)
    x[-1] = 1

もっとも素朴にdequeのようにひとつだけずらして一番うしろに代入します。

## appendしてdeleteする

    x = np.append(x, 1)
    x = np.delete(x, 0)

やりたいことそのままです。これが遅そうなので今回検証しています。

## 一つ前にコピーして最後に代入する

    x[0:-1] = x[1:]
    x[-1] = 1

スライスは速そうなので検証してみます。rollと同じようなことやってるように見えますが、微妙に違います。

## dequeを使って操作してからnumpy.ndarrayに変換する

    d.append(1)
    x = np.array(d)

ここでdはd=deque(maxlen)で生成したdequeです。maxlenを指定すると勝手に先頭が消えます。単純にappendするだけだとdequeが圧倒的に速いんですが今回は一回ごとにnumpy.arrayに変換する必要があります。


# 検証コード

それではどれが一番早いのか検証です。検証に使ったコードはこちら。

```python
import time
import numpy as np
from collections import deque

# バッファーの長さ
xlen = 1000
# シフトする回数
n = 100000

x = np.zeros(xlen)

s = time.time()
for i in range(n):
    x = np.roll(x, -1)
    x[-1] = 1

print(time.time() - s)

s = time.time()
for i in range(n):
    x = np.append(x, 1)
    x = np.delete(x, 0)

print(time.time() - s)

s = time.time()
for i in range(n):
    x[0:-1] = x[1:]
    x[-1] = 1

print(time.time() - s)

# dequeの宣言と初期化
d = deque(maxlen=xlen)
for i in range(xlen):
	d.append(1)

s = time.time()
for i in range(n):
    d.append(1)
    x = np.array(d)

print(time.time() - s)

```


# 検証結果

python3.8で実行しました。シフト操作回数は10000回で測定しました。長さはアレイの長さxlenのことです。

| 方法       |       長さ１００の場合 |    長さ１００００の場合    |
|:-----------------|------------------:|------------------:|
| numpy.roll()を使う             |              2.58s |        3.28s        |
| appendしてdeleteする           |            1.79s |       2.78s       |
| **一つ前にコピーして最後に代入する**             |              **0.100s** |        **0.366s**        |
| dequeを使って操作してからnumpy.ndarrayに変換する               |                1.52s |         88.0s         |

最も速いのは**スライスでコピーして最後に代入**するという結果になりました。
疑惑のコードも間違った選択ではなさそうです。
dequeも配列が短いときにはnp.array()がそれほど遅くないのでいいのかもしれないです。
長くなるとnp.array()の時間がとてつもなくかかるのでやばいです。

何かの参考になれば幸いです。
rails db:migrate:resetでのエラー

#プログラミングの勉強日記
2020年8月10日　Progate Lv.226
[rails db:migrateでのエラー](https://qiita.com/mzmz__02/items/c3b86f49ffeef19f74e1)という記事でマイグレーションファイルを操作するときにエラーが起きて、`rails db:migrate:reset`で対処すると述べたが、この`rails db:migrate:reset`を使おうとするとエラーが出たのでこれの対処をする。

#エラー内容
　Rails自体のバグ(?)で、Windowsでは自分がアクセスしてるファイルを削除できないことが問題になっているみたい、、

```terminal:ターミナル
$ rails db:migrate:reset
C:/Ruby26-x64/lib/ruby/2.6.0/x64-mingw32/etc.so: warning: already initialized constant Struct::Passwd
le::VERSION
C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/forwardable-1.3.1/lib/forwardable/version.rb:3: warning: 
previous definition of VERSION was here
C:/Ruby26-x64/lib/ruby/2.6.0/forwardable.rb:117: warning: already initialized constant Forwardable::FORWARDABLE_VERSION
C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/forwardable-1.3.1/lib/forwardable/version.rb:4: warning: 
previous definition of FORWARDABLE_VERSION was here
DEPRECATION WARNING: Single arity template handlers are deprecated. Template handlers must      
now accept two parameters, the view object and the source for the view object.
Change:
  >> Coffee::Rails::TemplateHandler.call(template)
To:
  >> Coffee::Rails::TemplateHandler.call(template, source)
 (called from <top (required)> at C:/Users/Owner/mysite/ruby/travel/Rakefile:6)
Permission denied @ apply2files - C:/Users/Owner/mysite/ruby/travel/db/development.sqlite3      
Couldn't drop database 'db/development.sqlite3'
rails aborted!
Errno::EACCES: Permission denied @ apply2files - C:/Users/Owner/mysite/ruby/travel/db/development.sqlite3
bin/rails:4:in `require'
bin/rails:4:in `<main>'
Tasks: TOP => db:drop:_unsafe
(See full trace by running task with --trace)
```

#解決方法（結論）
　`db/development.sqlite3`を手動で削除したらデータベースをリセットすることができた。

```:ターミナル
$ rm db/development.sqlite3
$ bin/rails db:setup
```

#対処法


##1.rails db:resetをする
　`rails db:migrate:reset`でデータベースのリセットとmigrateの実行を同時に行うと失敗する。なので、マイグレーションファイル内の実行する順番に問題がある可能性があり、`rails db:reset`と`rails db:migrate`を分けて実行すると解決する。

```:ターミナル
$ rails db:reset

$ rails db:migrate
```

　私はこれでは解決しなかった。

##2. rails db:resetの代わりに以下のコマンドを(これで解決！)

```:ターミナル
$ rm db/development.sqlite3
$ bin/rails db:setup
```


##3. rails db:migrate:resetの代わりに以下のコマンドを

```:ターミナル
$ rm db/development.sqlite3
$ bin/rails db:create db:migrate
```

#rails db:resetとrails db:migration:resetの違い

rails db:reset：`db/schema.rb`を元にデータベース作成する`db/migrate/〇〇.rb`は使わない。
rails db:migrate:reset：データベースを削除した後に`db/migrate/〇〇.rb`を古い順から実行する。

#参考文献
[db:migrate:reset でエラーが出ます](https://teratail.com/questions/67393)
[rails db:migrate:resetできなかったのでrails db:resetした](https://qiita.com/mom0tomo/items/a252ff8a42eea00f81b1)
$thisとは

#$thisとは
PHPでスコープ外で定義された変数を利用するための擬似変数
#thisがある時とない時の違い
```
class numbers{

  public $number = 'one';

  public function saynumber(){
    $number = 'two';

    echo $number;//出力結果はtwo
    echo $this->number;//出力結果はone
  }
}
```
【GCP】GKEの「Service と ingress」を使ってみた

BeyondCorp Remote Access を利用するにあたり、GKEingressを作成することになりました。
コンテナについてはそこまで深い知識はなく、いろいろ調べていたのですが、、

クラスタを作成して、ingressを割り当てるのをコマンドで実行していく必要がありそうでした。
https://kubernetes.io/ja/docs/concepts/services-networking/ingress/
https://qiita.com/Esfahan/items/f7d13d7e80848e9b6963

KubernetesはリソースにServiceやIngressをわりあてることができ、
IngressはL7のロードバランサになります。
リソースに割り当てるのは同じですが、まったくServiceとIngressはまったくの別物として扱われている。

で、実際にGCPのコンソール画面をみたら、「Service と ingress」という項目があった！
ネットで調べてる時点では、この機能についてどこも書いてなかった。
※Googleの公式ドキュメントにもなく、他のブログとかにもない状況・・・（8/11現在）

正しい使い方かはわかりませんが、「Service と ingress」を使って、ingressを作成するところまでをまとめてみました。

#手順
コンソールにログイン、PJを作成するのは定番なので飛ばします。

Kubenetes Engineを選択

Service と ingressを選択

1回めはAPIを有効にする要旨次があるはず。なので、ここで有効化する

クラスタを作成をクリック

テスト用なら、内容にこだわる必要はないので、デフォルトの状態で作成
※画面右の「最初のクラスタ」の内容に沿って作成するのもOK

クラスタ画面にうつるので、作成されるまでまつ
※VMインスタンス、インスタンスグループ、L7ロードバランサも自動で作成されます。

「Service と ingress」に移動

画面上のクラスタですべて表示するように選択

作成したクラスタ名と一致する行で、種類が「ノードポート」となっている行を選択

「INGERSS」を作成をクリック

L7ロードバランサの作成画面になります

Backend congigurationにはデフォルトのバックエンドが選択されている。
※他のバックエンドは選択できません

Host and path rulesは特に変更しない

Frontend configurationはHTTPSとかにしたければ、設定変更する

作成をクリック、完了

#まとめ
作成はできるのですが、細かい使い方がまだまだわかりません。
そもそもBeyondCorp Remote Accessはこれを使うことで、実現できるのかも不明。
引き続き調べていこうと思います。
Railsでワクワク個人開発 　第一回:仕様書とDB設計をしてみる

# 個人開発をやっていくぞ
　以前の記事でRubyをつかってひととおりのロジックを組むことはできるようになった。そういうわけで、こんどはRailsでなにかをつくってみることにした。何かしらのウェブサービスをつくろう。

# ざっくりとした仕様書を書く

　なにはともあれ、仕様書チックなものが必要だった。自分のやりたいことを明確にしておきたい。わたしが作りたいのは **「わいわい観察日記」** である。観葉植物の成長記録をみんなでシェアできるようにしたい。そのうち、IoTプロダクトとデータを連携していろいろやりとりできるようにしたい。

https://github.com/kyokucho1989/waiwai-kantatsu-nikki

```
# ワイワイ観察日記

## これはなにか
　植物を観察する日記をシェアするウェブサービス
　（室内の植物限定）

## ベネフィットはなにか
　栽培記録をシェアすることで、栽培するモチベーションを保つことができる

## ユーザーの想定
- さいきん植物を家で育て始めた人
- 観葉植物がすきなひと

## マネタイズ
- 広告配置（植物のタネとか？）
- 部品販売

## どうやってコンテンツを増やしておくか
- 初期ユーザーはコンテンツ0のサービスに粛々と投稿してくれるのか？→否
- 開発者自らちょっとずつ投稿しておく

## つける予定の機能
### ベータ版（最低限）
- ログイン機能
- 植物の登録
- 温度・湿度の記録

### ver 1.1
- 写真投稿（スマホ/PCから）
- バッジ機能　
　毎日投稿などでバッジがもらえる

- 自分の記録へコメント投稿

### ver 1.2
- 他のユーザーの記録へコメント投稿

### ver 2.0
- IoTデバイスからのデータ送信
　soracom GPSマルチユニット

 https://soracom.jp/products/kit/gps_multiunit/
```

　まずは小さく始めるのが大事だ。最低限の機能ができたらリリースしてしまって、あとから大きくやっていこう。

# DB設計をする

　今度はDBというものを設計する必要が出てきた。データの種類や関連性をまとめないといけない。詳しくはよくわからないけど、はじめのうちにやっておくといいらしい。

https://github.com/kyokucho1989/waiwai-kantatsu-nikki/blob/master/db-design.md

　まだ実装する予定のないデータも一応書くことにした。そうするとしっくりくる。重要なのはUserとPlantの関係だ。一人のユーザーが複数のPlantを持てる。ユーザー同士でPlantを共有することはできない。（それしたら面倒臭そう）

　こんなときは一対多の関連付けを行うらしい。モデルを作ったら、`app/models`の`user.rb` `plant.rb`へ追記する。

`plant.rb`

```ruby
class Plant < ApplicationRecord
  belongs_to :user
end
```

`user.rb`

```ruby
class User < ApplicationRecord
  has_many :plants
end
```

# ちょっとずつ機能を実装するぞ

　個人開発をはじめてみると、モチベーション管理が非常に難しそうだなと気づいた。これをやりぬくには、目標を細切れにしてステップアップしていくしかない。githubのissue機能を使うことにした。「ここを変更したい！」「これだけやりたい！」という感情をissueに記録し、issueを1個ずつつぶしていく。

　私は忘れっぽい生き物なので、なるべくQiitaへもこまめに投稿して、個人開発の思い出を残していきたい。

　つぎはユーザーのログイン機能の実装、ネストされたリソースの作成でつまったことを書くぞ。

# githubはこちらです
 https://github.com/kyokucho1989/waiwai-kantatsu-nikki
メモ: BDD記法

* https://www.picklesdoc.com/
* https://github.com/tpope/vim-cucumber
* [Free Online Gherkin Editor | AssertThat](https://www.assertthat.com/online-gherkin-editor#erlang-dark)


## 例

* https://blog.eiel.info/blog/2013/02/12/gherkin/

```sh
# language: ja
@blog
フィーチャ: ブログを書く
  ブログを書くには本人のやる気と書く時間が必要です。
  アウトプットは次のインプットに繋がるので積極的に行なうべきです。

  # これはコメントでタグの後にはかけない
  # @ではじまるのはタグ
  @good
  シナリオ: ブログが書ける
    ブログが書ける場合はやる気と時間があるのです。

    # ネタがないとかけないです。
    前提 ネタがある
    # 時間がないとかけないです
    かつ 納期に終われていない
    # 先輩とかいないですけど
    もし 先輩にブログを書けと言われた
    # オチがない
    ならば ブログが書けている

  @bad
  シナリオ: デスマ中はブログが書けない
     デスマ中ダトソレドコロジャナインダ!!

     前提 ネタがある
     かつ デスマ中
     もし 先輩にブログを書けと言われた
     ならば ブログが書けていない
```


## 記法

* https://www.slideshare.net/shinyanakajima37/gherkin-95343623

```sql
## Gherkin記法 

 AS：として 
 GIVEN：前提 
 WHEN：もし 
 THEN：ならば 
 AND：かつ 
 BUT：しかし
 
 
### 例

AS 管理者
Give プレイヤー１がグーを提示
AND プレイヤー２がチョキを提示
When 勝負履歴画面を表示
Then プレイヤー１の勝利が表示

(BDD（振る舞い駆動開発）で使用されている記法)
```

## 例

* https://tech.raksul.com/2017/10/11/running-tdd-with-bdd-style-stories/

```go:もともと
題名：ドライバーは、プッシュ通知、メールの新着通知ON/OFF、ONの時間設定をすることができる

詳細：
・設定ページ上でプッシュ通知のON/OFF設定ができる
・設定ページ上でメール通知のON/OFF設定ができる
・ONの場合は00:00～00:00で30分間隔で通知設定を行うことができる
・OFFになっていても、案件は従来どおり開示される
・XXXXXXの場合は、XXXXXXを優先する (企業秘密❤）
```

```SQL:BDDで書くと
題名：ドライバーは、プッシュ通知、メールの新着通知ON/OFF、ONの時間設定をすることができる

AS ドライバーとして
GIVEN ログインしている AND 案件一覧を表示しているとき
WHEN 設定画面の⚙アイコンをタップすると
THEN 設定内容が表示されデフォルト値が設定されている（ON）
like
| プッシュ通知 | *ON*/OFF |
| 通知時間設定 | ON/*OFF* |
| 通知時間設定 | 00:00 ~ 00:00 |
| メール通知 | *ON*/OFF |
```

## 日本語で書くと

* https://www.ey-office.com/blog_archive/2018/04/24/end-to-end-test-language/

```
フィーチャ: ショッピングカートに商品を追加したり、数量を変更したり、削除したりする
  シナリオ: 商品をカートに入れてショッピングカートを表示
    前提 商品"プリンセスコットン"のページを表示している

    もし "2"番目の注文欄に"2"と入力する
    かつ "買い物かごへ入れる"ボタンをクリックする
    かつ "お買い物内容"リンクをクリックする
    ならば "お買い物内容"と表示されていること
    かつ "合計"表示欄に"￥40,000"と表示されていること
```


## [Gauge](https://gauge.org/) (ゲージ)

* ドキュメントとしての充実度はCucumberより高い
* https://plasmic.space/tech/2018/08/gauge_low_maintenance_test_automation/

```sh
# Search specification
  Tags: search, admin
  The admin user must be able to search for available products on the search page
  
   * User must be logged in as "admin"
   * Open the product search page
  
  ## Successful search
  Tags: successful
  For an existing product name, the search result will contain the product name
    
   * Search for product "Die Hard"
   * "Die hard" should ahow up in the search results
    
  ## Unsuccessful search
  On an unknown product name search the search results will be empty
    
   * Search for product "unknown"
   * The search results will be empty
```

## テストファースト

* https://www.slideshare.net/shuji_w6e/ss-15246933

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/51aa3aba-4839-89fc-722c-c0dbd66d3a1b.png)
A Simple Framework for Contrastive Learning of Visual Representations のメモ

https://arxiv.org/pdf/2002.05709.pdf

Ting Chen, Simon Kornblith, Mohammad Norouzi, Geoffrey Hinton 

- SimCLRという教師なし学習手法を提案
- Contribution は3つ
 - augmentation の組み合わせが大事だということを示す
 - representation そのものから対比ロスを取らず、それを非線形変換したものに対して対比ロスをとる事が重要だということを示す
 - 対比学習には大きいバッチサイズと訓練ステップ数が必要だということを示す。


- Augumentation は リサイズしてクロップ、カラーディストーション、ガウシアンブラー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412142/6aeb5210-501a-8259-6bab-c94c87f197e3.png)

- 左右のネットワークは全く同じ。MoCoのようなモーメンタムエンコーダは使っていない。モーメンタムエンコーダのメリットは、過去のエンコードを流用できるということなのだろうから、メモリバンクを用いない場合には意味がないということか？

- 4.2 に gを入れることの利点が議論されている。gをid変換、線形変換、非線形変換として実験すると、非線形変換とした場合がid変換の場合に比べて10%以上よく、線形変換の場合よりも3%よいと。これは、ｚのレベルでは対比ロスが取られるため、下流タスクで有用な情報が欠落するためだろう、とのこと。その一つ手前のhには情報が残っている。

- negative example を明に取らず、ミニバッチ内の他のサンプルをネガティブとして扱う。これだとあまり大きく取れないので不利なのではないか。いや、だからバッチサイズが重要とか言ってるのか。やたら大きくしてるっぽい。。

 - バッチサイズは8Kまで大きくしている 5.2
 - エポック数が小さいうちはバッチサイズによる差が大きいが、エポック数をおおきくしていくと差は小さくなる。ざっくり2048ぐらいで十分っぽい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412142/80f37e61-c2be-ec31-7086-cbe7f5a3bca9.png)

- Augmentation としては、色々やっているが、結局ランダムクロップとカラージッタがドミナントだということらしい。
 - 下流タスクは一環して物体識別
FFmpegを利用して１枚の画像と音声ファイルから動画を作成する

## はじめに

FFmpegを利用して１枚の画像と音声ファイルから動画を作成します。

## FFmpegのダウンロード

公式サイトからプログラムを入手します
https://ffmpeg.org/

## FFmpegのコマンド

FFmpegで１枚の画像と音声ファイルから動画を作成するコマンドです

```
ffmpeg -loop 1 -i sample.jpg -i sample.mp3 -vcodec libx264 -acodec aac -ab 160k -ac 2 -ar 48000 -pix_fmt yuv420p -shortest output.mp4
```

### コマンドオプションの説明

|コマンド|説明|
|:-:|:-:|
|-loop|1で静止画を繰り返す|
|-i|入力ファイル。画像を先に|
|-vcodec|動画コーデック|
|-acodec|音声コーデック|
|-ab|音声ビットレート|
|-ac|音声チャンネル数|
|-ar|音声サンプリングレート|
|-pix_fmt|yuv420p|
|-shortest|入力の短い方(音声)に動画時間を合わす|
|output.mp4|出力ファイル名|


## 最小オプションのコマンド

```
ffmpeg -loop 1 -i sample.jpg -i sample.mp3 -pix_fmt yuv420p -shortest output.mp4
```
-rは25、-abと-acと-arは入力通りになる

## Webで動かす

[ffmpeg.wasm](https://github.com/ffmpegwasm/ffmpeg.wasm)を使用してWebで動かす。
夢のような話ですが、ブラウザ上でエンコードします。

```html
<form id="form">
  音声<input id="audio" type="file" required><br>
  画像<input id="image" type="file" required><br>
  <button id="button">音声と画像から動画を作成する</button>
</form>
<video id="video" controls></video>

<script>
form.onsubmit = function(event){
    event.preventDefault()
    button.disabled = true

    ffmpeg('-y', '-loop', 1, '-i', image.files[0], '-i', audio.files[0], '-pix_fmt', 'yuv420p', '-shortest', 'out.mp4')
    .then( mp4 => video.src = URL.createObjectURL(mp4) )
    .finally( () => button.disabled = false )
}

async function ffmpeg(...command){ // https://github.com/ffmpegwasm/ffmpeg.wasm
    await import('https://unpkg.com/@ffmpeg/ffmpeg@0.9.6/dist/ffmpeg.min.js')
    const ffmpeg = FFmpeg.createFFmpeg({logger: e => console.log(e.message)})

    if (!ffmpeg.isLoaded()){
        await ffmpeg.load()
    }

    for(var [i,v] of command.entries()){
        if(v instanceof Blob){
            ffmpeg.FS('writeFile', String(i), new Uint8Array(await v.arrayBuffer()))
            v = i
        }
        command[i] = String(v)
    }

    await ffmpeg.run(...command)

    return new File([ffmpeg.FS('readFile', v).buffer], v)
}
</script>
```
きちんと動作するが、エンコードが遅くて実用性に欠ける。
コマンドを工夫するのだろうが分からない。試しに「-r 1」とすると動画時間が狂う

上記のコードですが、少し作り込んでFFmpegのラッピング関数``ffmpeg``を作っている。

- コマンドを1つ1つ引数に渡す。入力ファイルは直接渡し、出力ファイル名を最後に渡す
- この関数は非同期であり、成功時はFileオブジェクトが返る

## バッチファイルで動かす

音声＋画像ファイルをBATファイルにD&Dし、起動させることもできる。

```音声と画像から動画作成.bat
@echo off
rem https://qiita.com/economist/items/bb325e8d23e0b3521c65

ffmpeg -loop 1 -i %1 -i %2 -pix_fmt yuv420p -shortest "%~dpn2.mp4"

pause
```

**注意する点として、先に音声ファイルを選択する必要がある**
音声ファイルを選択→画像ファイルを選択→両方一緒にBATファイルにD&D

出力ファイル名は音声ファイルで決まる。画像ファイルに合わせたい場合は**%~dpn1.mp4**
AtCoder Grand Contest 047 参戦記

# AtCoder Grand Contest 047 参戦記

レーティング1200以上の人しかレーティングに関係ないんだから、0完でも問題あるまいと思っていたが、パフォ915で憤死した. 以前に0完したときはパフォ339だったのでそれに比べればマシだけど.

## [AGC047A - Integer Product](https://atcoder.jp/contests/agc047/tasks/agc047_a)

突破できず. Twitter で 10<sup>9</sup> を掛けて、2と5が何個含まれるかを調べて云々と言っている人がいて、その人の説明は分からない部分があったものの閃いた. ようするに10進数なので、2と5が足りればいいのだと. 入力例で出てくる 2.4 だが、当然10倍すれば整数になるが、1.25倍でも整数になる. 要するに 2<sup>2</sup>×3×5<sup>-1</sup> なので 5<sup>-1</sup> さえ打ち消してもらえれば、2<sup>-2</sup> までは大丈夫なのである. これが分かれば後は A<sub>i</sub> 毎に2と5が何乗なのかを求めて、組み合わせ毎に2と5の乗数の合計がそれぞれ0以上であれば整数であると分かる. 2と5の組み合わせの総数はそこまで多くなく、*O*(<i>N</i><sup>2</sup>) でも間に合う.

```python
def conv(s):
    if s.find('.') == -1:
        s += '.'
    s = s.rstrip('0')
    t = len(s) - s.find('.') - 1
    a = int(s.replace('.', ''))
    if a == 0:
        return (0, 0)
    x, y = -t, -t
    while a % 5 == 0:
        x += 1
        a //= 5
    while a % 2 == 0:
        y += 1
        a //= 2
    return (x, y)


N, *A = open(0).read().split()
N = int(N)

d = {}
for a in A:
    t = conv(a)
    d.setdefault(t, 0)
    d[t] += 1

result = 0
xs = list(d.keys())
for i in range(len(xs)):
    x, y = xs[i]
    t = d[xs[i]]
    if x >= 0 and y >= 0:
        result += t * (t - 1) // 2
    for j in range(i + 1, len(xs)):
        m, n = xs[j]
        if x + m >= 0 and y + n >= 0:
            result += t * d[xs[j]]
print(result)
```
WordPressのThe Events Calendar プラグインの住所の並び方を変更

<?php ?>ブロックの順番を変えるだけ。ついでに国名表示は消す。


```address.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
        die( '-1' );
}

$venue_id = get_the_ID();

$full_region = tribe_get_full_region( $venue_id );

?>
<span class="tribe-address">

<!-- 郵便番号 -->
<?php
// This location's postal code.
if ( tribe_get_zip( $venue_id ) ) : ?>
        <span class="tribe-postal-code"><?php echo tribe_get_zip( $venue_id ); ?></span>
<?php endif; ?>

<!-- 都道府県 -->
<?php
// This location's abbreviated region. Full region name in the element title.
if ( tribe_get_region( $venue_id ) ) : ?>
        <abbr class="tribe-region tribe-events-abbr" title="<?php esc_attr_e( $full_region ); ?>"><?php echo tribe_get_region( $venue_id ); ?></abbr>
<?php endif; ?>

<!-- 市町村区 -->
<?php
// This locations's city.
if ( tribe_get_city( $venue_id ) ) :
        if ( tribe_get_address( $venue_id ) ) : ?>
                <br>
        <?php endif; ?>
        <span class="tribe-locality"><?php echo tribe_get_city( $venue_id ); ?></span><span class="tribe-delimiter">,</span>
<?php endif; ?>

<!-- 市町村区よりあと -->
<?php
// This location's street address.
if ( tribe_get_address( $venue_id ) ) : ?>
<span class="tribe-street-address"><?php echo tribe_get_address( $venue_id ); ?></span>
        <?php if ( ! tribe_is_venue() ) : ?>
                <br>
        <?php endif; ?>
<?php endif; ?>


<!-- 国は表示しない
<?php
// This location's country.
if ( tribe_get_country( $venue_id ) ) : ?>
        <span class="tribe-country-name"><?php echo tribe_get_country( $venue_id ); ?></span>
<?php endif; ?>
 -->
</span>
```
ツイッターカードでQiitaのタイトルが更新されない件について

Q.　Qiitaで書いた記事をツイートする際、一度ツイートしてから記事のタイトルを更新したけどそれがツイッターカードに反映されない。

A.　OGP画像の更新というものが必要らしいので手順を下記に示す。

①このサイトにアクセス→https://cards-dev.twitter.com/validator
②Card URLに更新したい記事のURLを貼り付け
③「Preview card」を押す
④Twitter リロード/アプリ再起動
appleの Server to Server Notifications に関する注意点

# Apple の Server-to-Serve Notification の仕様への不安

実際に調査して実装し、本番環境で受け取った通知の内容を確認して思うことは、appleのin-app purchaseに関わる仕様が理解しにくいということです。
今回は私が実際に直面した問題に関して、後のためにメモしておきます。

## 仕様の違う `environment` パラメーター

Server-to-Server Notifications はルート直下とunified_receipt直下にenvironmentというパラメータを返します。
このパラメーターは、本番環境では入る値が違います。
それぞれの説明は以下です。

[ルート直下](https://developer.apple.com/documentation/appstoreservernotifications/responsebody)

```
The environment for which the receipt was generated.
Possible values: Sandbox, PROD
```

[unified_receipt直下](https://developer.apple.com/documentation/appstoreservernotifications/unified_receipt)

```
The environment for which the receipt was generated.
Possible values: Sandbox, Production
```

**ルート直下は`PROD`を返し、unified_receipt直下は`Production`を返します。**

## 開発環境では `DID_FAIL_TO_RENEW` のテストが不可能

開発環境で通知が来る Notification Type は以下の物のみです。

- INITIAL_BUY（テストアカウント毎に一度だけ）
- DID_CHANGE_RENEWAL_PREF
- DID_CHANGE_RENEWAL_STATUS
- DID_RECOVER
- INTERACTIVE_RENEWAL

**課金に失敗してサブスクリプションの自動更新に失敗する際の通知である `DID_FAIL_TO_RENEW` は、課金が失敗するようにする設定画面が存在しないため、開発環境ではテストができません。**

(iOS14からテストができるようになるとのことですが、2020-08-10現在まだリリースされていません。)

この部分は推測で実装するしかなく、**本番環境で想定通りのパラメーターが渡っているかを、ログを仕込んで様子をみる必要があります。**


## サブスクリプションの自動更新時に通知は来ない（将来的には来るようになります）

**現時点では、サブスクリプションの自動更新時に通知は来ません。**
自動更新されたかどうかは verifyReceipt のAPIでサブスクリプションステータスをPollingしてくれと言っています。([ここの34:30あたり](https://developer.apple.com/videos/play/wwdc2019/302/))

**iOS14からは `DID_RENEW ` 通知が追加されます**ので、StatusPollingをする必要性は理論上は無くなります。
**が、引き続き（念のため）StatusPollingは実装しておいてくれと言っています。**

## 「サブスクリプションを解約する」という状態は存在しない。 `original_transaction_id` は引き継がれる。

appleではサブスクリプションの解約という状態は存在せず**「自動更新の停止」という状態を「解約」と表現しています**。

そのため、サブスクリプションを一意に識別する`original_transaction_id`は、サブスクリプションを「解約」しても、再度サブスクリプションを購入した場合、同じ値が引き継がれます。
「解約→再加入」ではなく「停止→再開」という意味合いになります。
（ちなみにgoogleでは「解約→再加入」という仕様なので、サブスクリプションの識別子はそれぞれ違う物が振られます。）

## 継続課金失敗時の挙動。２ヶ月間の課金リトライと、自動更新の停止。

自動更新の停止は以下の２パターンで起き得ます。
1. ユーザーが画面から設定する、意図的な解約
2. 継続時の課金失敗を原因とする、ユーザーの意図していない解約

この2番目について、課金のリトライを１度目の失敗と同時刻に、２ヶ月間行います。

ユーザーの支払い方法が更新されていれば、更新後のリトライ時点で`DID_RECOVER`通知と共にサブスクリプションが再開されます。

**2ヶ月間の内に支払い方法が更新されない場合、１度目の失敗から２ヶ月経過した日に、`DID_CHANGE_RENEWAL_STATUS` の通知と共に、「自動更新を停止」します。
「自動解約」という状態は存在しません。**

## `original_transaction_id` が変わる場合は、「購入履歴を復元」した場合

「購入履歴を復元」した場合は `original_transaction_id` が変わります。
正確に言えば、**復元をするとreceipt履歴が2つに割れます。復元によってできた履歴には`original_transaction_id`が新たに振られ今後更新されます。復元前の履歴は更新が止まります。**

# この記事について、今後
上記は、挙動の把握に間違いがあるかもしれませんので、実際の挙動はご確認ください。
気づいた点は引き続き追記していきます。
[Ruby]Macでpumaがインストールできない[Railsとか]

pumaが原因でRailsがインストールできないんだなこれが。
sqliteがなくてインストールできないのはbrewからsqliteを入れれば解決するんだけど

macOS Catalina 10.15.6
ruby 2.6.5
gem 3.0.3
puma 4.3.5

似たような質問にxCodeがインストールされていないのでは？なんて回答もあったけど
手元ではそれで解決せず。

<details><summary>エラーメッセージ（クリックで展開）</summary><div>


```
gem install puma -v '4.3.5' --source 'https://rubygems.org/'
Building native extensions. This could take a while...
ERROR:  Error installing puma:
	ERROR: Failed to build gem native extension.

    current directory: /Users/rin.nakashima/.anyenv/envs/rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11
/Users/rin.nakashima/.anyenv/envs/rbenv/versions/2.6.5/bin/ruby -I /Users/rin.nakashima/.anyenv/envs/rbenv/versions/2.6.5/lib/ruby/2.6.0 -r ./siteconf20200810-80454-doo97b.rb extconf.rb
checking for BIO_read() in -lcrypto... yes
checking for SSL_CTX_new() in -lssl... yes
checking for openssl/bio.h... yes
checking for DTLS_method() in openssl/ssl.h... yes
checking for TLS_server_method() in openssl/ssl.h... yes
checking for SSL_CTX_set_min_proto_version in openssl/ssl.h... yes
creating Makefile

current directory: /Users/rin.nakashima/.anyenv/envs/rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11
make "DESTDIR=" clean

current directory: /Users/rin.nakashima/.anyenv/envs/rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11
make "DESTDIR="
compiling http11_parser.c
ext/puma_http11/http11_parser.c:44:18: warning: unused variable 'puma_parser_en_main' [-Wunused-const-variable]
static const int puma_parser_en_main = 1;
                 ^
1 warning generated.
compiling io_buffer.c
compiling mini_ssl.c
mini_ssl.c:145:7: warning: unused variable 'min' [-Wunused-variable]
  int min, ssl_options;
      ^
mini_ssl.c:299:40: warning: function 'raise_error' could be declared with attribute 'noreturn' [-Wmissing-noreturn]
void raise_error(SSL* ssl, int result) {
                                       ^
2 warnings generated.
compiling puma_http11.c
puma_http11.c:203:22: error: implicitly declaring library function 'isspace' with type 'int (int)' [-Werror,-Wimplicit-function-declaration]
  while (vlen > 0 && isspace(value[vlen - 1])) vlen--;
                     ^
puma_http11.c:203:22: note: include the header <ctype.h> or explicitly provide a declaration for 'isspace'
1 error generated.
make: *** [puma_http11.o] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/rin.nakashima/.anyenv/envs/rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/puma-4.3.5 for inspection.
Results logged to /Users/rin.nakashima/.anyenv/envs/rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-19/2.6.0/puma-4.3.5/gem_make.out
```
</div></details>

ググってたらissueを見つけまして、Mac側のデフォルトパラメータが変わってgccでのコンパイルがうまくできなくなったらしい。
https://github.com/puma/puma/issues/2304
ワークアラウンドとして以下のように対処せよとのこと

```
gem install puma:4.3.5 -- --with-cflags="-Wno-error=implicit-function-declaration
```
シンプルなRESTFull API を PHPでちゃちゃっと作りたい場合

## how to use
### composer の インストール

```bash
$ docker pull composer
$ alias composer='docker run --rm -it -v $PWD:/app composer'
```

### slim4-api-skeleton のインストールと設定
```bash
$ composer create-project maurobonfietti/slim4-api-skeleton [my-api-name]
$ cd [my-api-name]
$ composer install
```

### 立ち上げと確認
```bash
$ docker-compose up -d --build
$ curl http://localhost:8081/

{"api":"slim4-api-skeleton","version":"0.22.0","timestamp":1596992058}
```

### src/Controller/Home.php
```php
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Helper\JsonResponse;
use Pimple\Psr11\Container;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

final class Home
{
    private const API_NAME = 'slim4-api-skeleton';

    private const API_VERSION = '0.22.0';

    private $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }

    public function getHelp(Request $request, Response $response): Response
    {
        $message = [
            'api' => self::API_NAME,
            'version' => self::API_VERSION,
            'timestamp' => time(),
        ];

        return JsonResponse::withJson($response, json_encode($message), 200);
    }

    public function getStatus(Request $request, Response $response): Response
    {
        $this->container->get('db');
        $status = [
            'status' => [
                'database' => 'OK',
            ],
            'api' => self::API_NAME,
            'version' => self::API_VERSION,
            'timestamp' => time(),
        ];

        return JsonResponse::withJson($response, json_encode($status), 200);
    }
}
```
atomのautocomplete-pythonが動かなかった時の対処法メモ

atomを使ってpythonの環境構築をしていたときに、packegeのautocomplete-pythonがうまく動かず、
調べてもパッと出てこなかったのでとりあえず日本語で残しておこうと思います。

内容はここに書いてあることと同じ。
https://stackoverflow.com/questions/44602603/atom-ide-autocomplete-python-not-working/52023811#52023811?newreg=45250004097448b89124410714d158d6


# 前提
OS：macOS Catalina 10.15.5
pythonバージョン：3.8.5
atom:1.49.0x64
autocomplete-python：1.16.0


# 起こったこと
### 期待していた状態
autocomplete-pythonが正しく動作していれば、
例えばpythonファイルを開いて「i」と打った時に下の画像のような感じでpythonのキーワードが候補として出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539670/a4004e09-acb8-788d-daf6-909149f9b1e7.png)

### 現実
ただ、実際は下の画像のように、autocomplete-plusしか動作していませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539670/3a642843-97c3-52b2-ea47-c7664e56d8bb.png)


# 解決方法
`~/.atom/packages/autocomplete-python/lib/jedi/parser`
配下に、使用しているpythonのバージョンと同じバージョンのgrammar3.x.txtが存在していないとだめなようです。
自分はpython3.8を利用していたので、`grammar3.8.txt`がないとダメなんですが、確認してみると`grammar3.7.txt`までしかありませんでした。

ということで、grammar3.7.txtをコピーして、grammar3.8.txtを作ってあげれば無事動くようになりました。


参考：https://stackoverflow.com/questions/44602603/atom-ide-autocomplete-python-not-working/52023811#52023811?newreg=45250004097448b89124410714d158d6
Udemyのswiftコース（英語のやつ）でiOSアプリ開発を学ぶ　その４

勉強するコースはこれです:point_down:
https://www.udemy.com/course/ios-13-app-development-bootcamp/

##進捗
セクション4の途中まで終了（全部で36セクション）（ひとまずベイビーステップですよね）
サイコロのアプリを作りつつ、その中で変数（variables）と配列（arrays）について学習した。

##感想
配列や変数の基礎については知っているつもりだけど、良いおさらいでした:man_tone1:
今まで自分がしてきた学習は日本語での本や授業の内容だったので、英語で学ぶとまた新鮮な部分がありますね。
「英語だとこう言うのか！」とか「英語だったらこういう風に解説すればいいのか！」とか目から鱗な内容もありました。
すでにswiftに詳しい人でも受講すると英語の勉強になっていいかも。
また、英単語や英語での表現に詳しければ英語で内容を調べやすいので、開発中に分からないところでつまづいたときにこの学習経験が役に立ちそうな気がする。

ジョークは、Angela先生から昇給（a raise）と配列(arrays)をかけたジョークがnice jokeだった！
section 4で出てくるので、このコース始めた人はぜひチェックしてほしい！
笑点だったら座布団1枚もらえるやつでした:thumbsup:笑

##今後の予定
できる範囲でコースを進める。
実際のアプリ開発よりも学習することのほうに時間をかけるかも。
Go言語のhttp.Handle、http.HandleFuncを雑に理解する

# はじめに
最近Goに入門しました。`http.Handle`、`http.HandleFunc`、`http.Handler`、`http.HandlerFunc`についてまとめられている記事は溢れていますが、結局何パターンの書き方があるのかまとまっている記事がなかったので、まとめておきます。対象は、筆者と同じぐらいのGo言語初心者を想定しています。

# 実装
下の5パターンが考えられる全てだと結論付けました。他の方法を知っている方がいらっしゃいましたら教えていただきたいです。

```golang
package main

import "net/http"


type one struct {
}

func (h *one) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("one\n"))
}

func two(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("two\n"))
}

func three(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("three\n"))
}

func main() {
	http.Handle("/one", &one{})

	http.Handle("/two", http.HandlerFunc(two))
	// http.Handle("/two", two) <- これはだめ

	http.HandleFunc("/three", three)

	http.HandleFunc("/four", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("four\n"))
	})

	http.HandleFunc("/five", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("five\n"))
	}))

	http.ListenAndServe(":1991", nil)
}
```

# 解説
(*それぞれのエンドポイントに対応して、1の実装、2の実装のように表現します。)

順序立てれば、それほど難しいものでもないことが分かると思います。

1. エンドポイントを作成する方法は、`http.Handle`と`http.HandleFunc`の二つ。
2. `http.HandlerFunc`は`func(w http.ResponseWriter, r *http.Request)`の別名。**ただし、`ServeHTTP`メソッドが定義されている。**
3. `http.Handle`の第2引数は`Handler`型で、`ServeHTTP`を実装している必要がある。
4. `http.HandleFunc`の第2引数は、結局`http.HandlerFunc`にキャストされる。

この4つを覚えておけば、理解できると思います。まず、1の実装は自分ので定義した`struct`に`ServeHTTP`を実装しているので、問題ないです。2つめの実装ですが、単純な関数を`http.HandlerFunc`型にキャストしているので、`ServeHTTP`が実装され、問題ないです。**逆に言うと、`http.Handle`の第2引数には、単純な`func(w http.ResponseWriter, r *http.Request)`型の関数を渡すとエラーです。**3つめの実装と、4つめの実装は、無名関数かどうかの違いでしかなく、4.で書いているように、`http.HandleFunc`にキャストされるため、通常の関数を渡しても問題ないです。もちろん5つ目の実装のように前もってキャストしても問題ないです。

# まとめ
1. エンドポイントを作成する方法は、`http.Handle`と`http.HandleFunc`の二つがある。
2. `http.Handle`の第2引数は、`Handler`インターフェースを実装した(`ServeHTTP`メソッドが定義されている）ものを渡せば良い。
3. `http.HandleFunc`の第2引数は、`func(w http.ResponseWriter, r *http.Request)`型の関数を渡せば良い。

Go言語は公式のドキュメントがしっかりしているので、良いですね。

# 参考
[Go言語公式ドキュメント](https://golang.org/pkg/net/http/)
AfterEffectsで緑のチラツキが発生した時の対処法

![green.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/a0a08c61-b644-3fac-95f5-4873255af425.gif)
AfterEffectsで動画編集していると、とある動画(↑の動画)、特定のタイミングで必ず**緑のチラツキが発生**するトラブルに遭遇しました。本記事はそれに対する対処法を紹介します。


## エンコードし直すと解決する

結論から書くとエンコードをし直すと緑のチラツキは発生しなくなりました。
調査すると、これといった原因特定ができなそうな感じでしたが、動画をエンコードし直すことで解決したという情報が出てきました。


## ffmpegでエンコード

僕の場合はffmpegを使用しました。

```shell
$ ffmpeg -i input.mp4 output.mp4
```
mp4からmp4を書き出す形になりましたが、これでとりあえず直りました。


## 余談

[たのしいmicrobitコンテスト2020](https://makezine.jp/blog/2020/06/microbitcontest2020.html)に応募しました。応募要件の動画制作で起きたトラブルを本記事の題材にさせてもらいました。
https://twitter.com/ohbashunsuke/status/1292490616006275074




## 環境

- macOS Catalina 10.15.5
- AfterEffects 16.1.0
- ffmpeg 4.3.1
- Pixel3XL(撮影デバイス)


## 参考

- [After effectsについてです](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11194341731)
- [動画書き出し後に緑のチラつきが起きる場合の対処法](https://marcofabrika.com/blog/883)
Metabaseでユーザの都道府県ごとの住所を集計して地図に表示する

## 目的
Metabaseでサービスを利用しているユーザの場所を可視化したいという要望があり、地図に表示させました。

## 概要
Data of Japanの都道府県別日本地図（GeoJSON形式）を参照し、ユーザの属性テーブルの住所項目と紐付けて集計・表示させます。

## 手順

### Mapの追加

1. 管理者アカウントにて、右上の設定メニューからadminを選択します。
2. SettingタブからMapsを選択して`Add a map`を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/1129383a-a822-b679-4b1e-4ae38dda1806.png)

3. 以下の画面にてMapの設定を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/a541f876-ef53-1825-81f1-2fb7493c556a.png)

今回の私の設定は以下の通りです。
identifierを何にするかが重要です。Data of JapanのJSONからは都道府県No.を数値で表した`id`や英字表記の`nam`なども選択できるので、データの項目に合わせて紐付けやすいものを選択して下さい。

| 項目      |       値 |  
|:-----------------|------------------:|
| URL             |              https://raw.githubusercontent.com/dataofjapan/land/master/japan.geojson
| identifier          |            nam_ja |
| display name          |            nam_ja |

### Mapと住所項目の紐付け

私はこのようなSQLを発行しました。
addressはユーザが入力する住所項目のため、`locate`でこの項目内で都道府県の文字列を検索して`nam_ja`と紐付けています。

```sql

SELECT
	CASE WHEN address IS NOT NULL THEN
		SUBSTRING(address, 1, CASE WHEN 
			locate('県', address_1) <> 0 THEN
				locate('県', address_1)
			WHEN 
			locate('府', address_1) <> 0 THEN
				locate('府', address_1)
			WHEN 
			locate('都', address_1) <> 0 THEN
				locate('都', address_1)
			WHEN 
			locate('道', address_1) <> 0 THEN
				locate('道', address_1)
			END)
	ELSE
		'その他'
	END AS map,
	COUNT(*) AS count
FROM
	profiles
WHERE
	address IS NOT NULL
GROUP BY
	map
ORDER BY count DESC
```

## 結果
このような形で表示することが出来ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/47592de4-99f9-d898-2ee2-fb392843f3d6.png)


## 参考にした記事
[metabaseで日本の地図を表示する](https://qiita.com/okegawa/items/c6ce11873e9b97ded3ef)
【iOS】Xcodeでのデバイスのスクリーンショットの撮り方

#Xcodeでのスクリーンショットの撮り方
**1:まずXcodeのメニューのWindowをタップします。**
<img width="816" alt="スクリーンショット 2020-08-10 1.07.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357475/5bdf1d33-5566-194d-9387-0550be99e347.png">

**2:次にDevices and Simulatorsをタップします。**
<img width="485" alt="スクリーンショット 2020-08-10 1.08.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357475/2d9696bb-c90f-16fc-35a8-0418b772d0ca.png">

**3:次に下記画像のTake ScreenShotをタップすると、デスクトップに画像が格納されます。**
<img width="797" alt="スクリーンショット 2020-08-10 1.17.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357475/e145a5af-a8db-4642-ccc5-9431b9f404a5.png">
StandAloneモードでの表情設定（Amaneさん編）【iFacialMocap】

▼こちらのモデルを使用する場合の記入例です。
https://take2mbh.booth.pm/items/2223325

Angry(怒り)
```Niramu,Brow_Angry01_L,Brow_Angry01_R```

Sorrow（悲しい）
```Brow_Sad01_L,Brow_Sad01_R```

Surprise（驚き）
```Eye_Surprise,Brow_Joy01_L,Brow_Joy01_R,eyeWideLeft,eyeWideRight```

Extra（死んだ目）
```Eye_NoLight```

Love（惚れ顔）
```Eye_uruuru,mph_face_hoho```

Scare（恐怖顔）
```Brow_Sad01_L,Brow_Sad01_R,mph_face_hitai```

Joy（ニッコリ）
```Smile_L,Smile_R,Brow_Joy02_L,Brow_Joy02_R```

Jito（ジト目）
```Jito```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684858/7a878f4a-6259-e51c-acaf-97aec50c8b48.jpeg" width=50%>


<<iFacialMocap設定（StandAlone_Unityモード）
https://qiita.com/take2_mbh/private/1bdcd43ba9b682423706
PostgreSQLのロック解除

  DataSpider開発中で、スクリプト実行途中にトランザクションをコミットする前にエラーが発生したりして、PostgreSQLがロックされることが発生して、解決方法を調べてみました、下記の方法で解決できました。
  1. SQLで自分のプロセスIDを確認する。
　　SELECT l.pid, l.locktype, l.mode, c.relname, d.datname
　　FROM pg_locks l
    LEFT JOIN pg_class c ON l.relation = c.relfilenode
    LEFT JOIN pg_database d ON l.database = d.oid
　　ORDER BY l.pid;
  2. SQLでプロセスを終了する
  　SELECT pg_terminate_backend(手順1で確認したプロセスID)
　　※pg_cancel_backendは効きませんでしたが、pg_terminate_backendでプロセス終了できました。
フレッツ回線 + IPv6 環境で SSH できない

自宅のネット環境を IPv6 対応したら SSH や Git でインターネットに接続できなくなって困った話。

## 現象
「フレッツ回線」「IPv6(※)」「SSH」でインターネットに出ようとした際に、「client_loop: send disconnect: Broken pipe」というエラーが出て接続できない。

※ DS-Lite や MAP-E による IPv4 over IPv6 を設定している場合は IPv4 での SSH 接続でも同様の問題が発生する。

## 原因
フレッツ網は IPv6 DSCP 値によってパケットを drop してしまうらしく、それによって SSH のパケットが届かなかったため。

### DSCP とは
DSCP は IP パケットに含まれる 6bit の値で、パケットの優先度を制御する目的で使われる。[^dscp]

[^dscp]: [QoS - DSCP（Differentiated Services Code Point）とは](https://www.infraexpert.com/study/qos7.htm)

### OpenSSH の DSCP 値
OpenSSH では明示的に設定しなかった場合、対話型セッションでは `af21` 非対話型セッションでは `cs1` が `IPQoS` のデフォルト値として利用される。[^ssh]

明示的に SSH パケットの DSCP 値を設定するには `IPQoS` というオプションを指定する。

[^ssh]: [ssh_config(5) - Linux manual page](https://man7.org/linux/man-pages/man5/ssh_config.5.html)



### フレッツ回線での振る舞い
フレッツ回線の仕様では、IPv6 パケットの DSCP 値によってパケットが drop されることがあるらしい。

[NTT東日本の技術参考資料](https://www.ntt-east.co.jp/gisanshi/) の [IP通信網サービスのインタフェース 第三分冊 (第42版)](https://flets.com/pdf/ip-int-3.pdf) には以下の記載がある。

> 2.4.4 帯域優先に関する仕様
> 契約帯域の範囲で優先クラスを利用したIPv6(IPoE)通信が可能となるサービスにて、当該サービス契約者の端末機器からIP通信網に送信されるIPv6パケットにおいて、RFC2474に規定される優先度の指定が可能です。当該サービス契約者の端末機器からIP通信網に送信されるIPv6パケット(IPoE方式）のトラヒッククラスフィールドの先頭6ビットに、DSCP値として8(001000)を指定することで、優先トラヒックとして転送します。
> **尚、指定された優先度以外が設定されたパケットの転送は保証しません。**

どうやら `cs1` (001000) 以外の DSCP 値ではパケットの転送は保証されない (= drop される可能性がある？) 模様。また、明示的に記載されていないが、おそらく `default` (000000) も大丈夫であろう。

※ ちなみにこれは「フレッツ 光ネクスト編」の記述だが、なぜか「フレッツ 光クロス編」には同様の記述は存在しない。光クロスの場合は drop されないのだろうか？

## 対処方法
IPv6 通信をする端末ごとに対応する方法と、ルータで対応する方法がある。

### 端末ごとに対応
SSH の設定ファイルにて DSCP 値を `cs1` と明示すればよい。

``` :~/.ssh/config
Host *
  IPQoS cs1
```

IPQoS オプションに値をひとつだけ設定した場合は、対話型セッションと非対話型セッションの両方で設定した値が利用されるので、この場合は両方のセッションで `cs1` が使用されることになる。

上述のとおり `cs1` か `0` であれば drop されなさそうだが、どちらが良いのかは正直良くわからない。「`cs1` は非対話型セッションのデフォルト値にも設定されている値だし」という雑な理由で自分は `cs1` を指定しているが、今のところ特に困っていない。

また、類似の記事では IPQoS オプションに `none` を設定しているケースが見られるが、 `none` の場合は「OS のデフォルト値が使用される」らしいので、 `none` よりかは `0` を明示的に指定したほうがよいのではないかと思われる。

### ルータで対応
すべての端末で設定をするのは大変な場合は、ルータでパケットの DSCP 値を書き換えてしまうという方法もある。

ググったところ YAMAHA ルータ [^yamaha] や EdgeRouter [^er-x] では書き換えができるっぽいことがわかった。

[^yamaha]: [IPv6 パケットの DS フィールドの書き換えの設定 - RTpro - ヤマハ](http://www.rtpro.yamaha.co.jp/RT/manual/rt-common/ipv6/ipv6_dscp_supersede.html)

[^er-x]: [EdgeRouter X のファイアウォールでフレッツ光 の IPv6 から SSH が繫がらない問題を解決する – ちとくのホームページ](https://chitoku.jp/computers/edgerouter-x-flets-dscp)
qemu-system-aarch64 の raspi3 エミュレートをシングルコアで動かす

## はじめに

QEMU で自分が書いたベアメタルプログラムを動かしていると、意図せず複数コアが動いてしまい頭を抱えてしまいました。
解決方法が分かったので、とりあえず書き残しておきます。


## 原因と解決法

原因は、 `-kernel` オプションに ELF ファイルを渡していたことでした。
解決法は `-kernel` オプションで渡すバイナリを ELF ファイルではなく `kernel8.img` という名前のイメージファイルにすることです。

ELF ファイルからイメージファイルへの変換は `aarch64-linux-gnu-objcopy` のコマンドでできます。
バイナリファイルを変換し, qemu でバイナリを動かすコマンドは以下の通りです。
なお、イメージ名を `kernel8.img` にする必要があるのか否かは確認できてませんが、実際の Raspberry Pi では 64 bit モードで動かす際にこのファイル名にする必要があるため、それに合わせておいた方がいいと思います。

    $ ## 変換元ファイルの確認 (必須ではない)
    $ file kernel.elf
    kernel.elf: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, with debug_info, not stripped
    $ 
    $ ## ELF--> image 変換
    $ aarch64-linux-gnu-objcopy -O binary kernel.elf kernel8.img
    $ 
    $ ## 変換後ファイルの確認 (必須ではない)
    $ file kernel8.img
    kernel8.img: data
    $
    $ ## QEMU の実行
    $ ~/qemu-system-aarch64 -M raspi3 -nographic -kernel kernel8.img


## (おまけ) 経緯など

[以前書いた記事](https://qiita.com/deep_tkkn/items/c56d75e7612f9eceb29c#elf-%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E3%82%92-qemu-%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B) で意図せず複数コアが動いてしまっているために UART の表示が崩れてしまっていたのですが、これを直したくて今回の話に至ります。

ちなみに、上記の `-kernel` オプションに関する公式のドキュメントは見つけられなかったものですが、Github 上にある下記の Makefile と コミットメッセージを見てこのことに気づけました。

-   mikoto2000/raspberrypi_bare_metal
    -   **Makefile:** <https://github.com/mikoto2000/raspberrypi_bare_metal/blob/master/uart_output/Makefile>
    -   **コミットメッセージ:** <https://qiita.com/deep_tkkn/items/c56d75e7612f9eceb29c#elf-%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E3%82%92-qemu-%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B>


## (おまけ2) 実際の Raspberry Pi の挙動と比べる

そもそも実際の Raspberry Pi は ELF からいきなり起動しませんし、起動時からマルチコアが動くわけでもありません。
今回のように kernel8.img ファイルを渡した時の挙動の方が実際の Raspberry Pi の挙動に近いと思います。
おそらく ELF を渡すのはユーザープログラムなどを試すときに使うのが本来の想定なのかなと思います。


## おわりに

とりあえずこれで実際の Raspberry Pi と同様にシングルコアでブートするようになりました。
今後も少しずつ ARM で遊んでみたいと思います。