OmniAICreator/Qiita-1.07M huggingface dataset:
Chrome の Headless モード (Golang)

```go:chrome_headless.go
// ---------------------------------------------------------------
//
//	chrome_headless.go
//
//					Sep/26/2018
// ---------------------------------------------------------------
package main

import (
	"github.com/sclevine/agouti"
	"fmt"
	"os"
	"log"
	"io/ioutil"
	"time"
)

// ---------------------------------------------------------------
func main() {
	fmt.Fprintf (os.Stderr,"*** 開始 ***\n")

	url := "https://ekzemplaro.org/storytelling"

	driver := agouti.ChromeDriver(
		agouti.ChromeOptions("args", []string{
		"--headless",
		}),
		agouti.Debug,
		)

	err := driver.Start() 
	if err != nil {
		log.Printf("Failed to start driver: %v", err)
	}

	page, err := driver.NewPage(agouti.Browser("chrome"))
	if err != nil {
		log.Printf("Failed to open page: %v", err)
	}

	err = page.Navigate(url)
	if err != nil {
		log.Printf("Failed to navigate: %v", err)
	}

	fmt.Printf(page.Title())
	fmt.Printf("\n")

	html, err := page.HTML()
	fmt.Printf (html)
	fmt.Printf("\n")

	time.Sleep(100 * time.Millisecond)

	out_filename := "tmp001.html"
	ioutil.WriteFile (out_filename,[]byte(html),0666)

	fmt.Fprintf (os.Stderr,"*** 終了 ***\n")
}

// ---------------------------------------------------------------
```

```text:Makefile
chrome_headless: chrome_headless.go
	go build chrome_headless.go
clean:
	rm -f chrome_headless
```

コンパイル

```text
$ make
go build chrome_headless.go
```

実行方法

```bash
export PATH=/opt/chromedriver:$PATH
./chrome_headless
```
sqlplusでutf8

## Sqlplus でutf8のファイルを実行

Sqlplus でutf8のファイルを実行すると文字化けしてしまう

NLS_LANGの設定をするという情報は多かったがそれだけではうまくいかなかった。
chcpの設定を追加するとりあえず、うまくいった。


```bat

pushd %~dp0

chcp 65001

SET NLS_LANG=Japanese_Japan.AL32UTF8

sqlplus <username>[/<password>][@<connect_identifier>] 


@utf8のファイル.sql


```
別ページにsubmit

##やりたい事
・angularで作ったページから、新規タブで別ページにsubmitする
※外部サービスを別タブで開き、ログイン画面をスキップしたい

##課題
・普通にcomponent側からsubmitさせると、Not Foundになる
　→Cannot POST /***/newtab...という感じのエラー

##対応
・submitをリンクとして設定

```html
<form name="gdlogin" action={{actionUrl}} method="POST">
  <input type="hidden" name="sessionid" value={{sessionId}} />
  <a href="javascript:gdlogin.submit()" id="outserve">ｶﾞﾝﾀﾞｧｧｧｧﾑ!!</a>
</form>
```

・jqueryで叩く

```ts
$('#gdlogin')[0].click();
```

参考にさせてもらった記事→[jQueryでリンクをクリックさせたい時](https://qiita.com/yukiyukki/items/06295041ed366eb5a682)

##例

###リンク元

```html:link.html
<a href="/newtab" target="_blank">別タブ</a>
```

###リンク先コンポーネント

```ts:newtab.component.ts

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';

declare var $;

@Component({
  selector: 'app-newtab',
  templateUrl: './newtab.component.html',
  styleUrls: ['./newtab.component.css']
})
export class NewtabComponent implements OnInit {
  public baseurl = 'http://***/outserve/';
  public actionUrl = '';
  public sessionId = '';

  constructor(private http: HttpClient) {}

  ngOnInit() {
    // 外部サービスからセッションIDを取得する(ほんとはこんなんハードコードしない)
    const userId = 'Setsuna';
    const password = 'GN-001';

    const url =
      this.baseurl +
      'api/login.php?UserId=' +
      userId +
      '&Password=' +
      password;

    this.http.get(url).subscribe(
      res => {
        // 取得結果をformに設定
        const parsedJSON = JSON.parse(JSON.stringify(res));
        this.actionUrl = this.baseurl + 'login.php';
        this.sessionId = parsedJSON.sessionid;
        
        // 本当はこうしたかったけどエラーになる
        // document['gdlogin'].submit();

        // jqueryで叩く
        $('#gdlogin')[0].click();
      },
      err => {
        console.log('見つけたぞ、世界の歪みを！' + err);
      }
    );
  }
}

```

```html:newtab.html

<body>
  <form name="gdlogin" action={{actionUrl}} method="POST">
    <input type="hidden" name="sessionid" value={{sessionId}} />
    <a href="javascript:gdlogin.submit()" id="outserve">ｶﾞﾝﾀﾞｧｧｧｧﾑ!!</a>
  </form>
</body>
```
全テーブルの件数確認

### 全テーブルの件数確認

たくさんのテーブルのデータ件数をいちいちCOUNT(*)で取得していられない。
テーブル名を抜き出して、Excelなんかに式を入力して

> SELECT COUNT(*) FROM TABLE_NAME;

なんかを書き出してコピペしてみたりしていたけど、
そもそもそれぞれに細かい件数が知りたいわけじゃない。
データ移行などの前にどのテーブルにどのくらいのデータがあるのか、おおよその件数を知りたいくらいの場合にはシステムテーブルで統計情報を取得した時点の件数を持っている。
日次に夜間に統計情報を取っていたりするならこれで十分な場合も多い。


```sql

SELECT
 ROW_NUMBER() OVER(ORDER BY A.TABLE_NAME) AS NO
,A.TABLE_NAME
,B.COMMENTS
,A.NUM_ROWS
,A.AVG_ROW_LEN
,A.SAMPLE_SIZE
,A.LAST_ANALYZED
,SYSDATE
FROM ALL_TAB_STATISTICS A,ALL_TAB_COMMENTS B
WHERE A.TABLE_NAME = B.TABLE_NAME
AND A.OWNER = B.OWNER
ORDER BY A.TABLE_NAME

```


でもやっぱりちゃんと細かい件数が必要な場合もある。
って場合はここにいいのがあった。
http://d.hatena.ne.jp/yohei-a/20101112/1289587201

これを参考に両方出してみる

```sql
SELECT
 ROW_NUMBER() OVER(ORDER BY A.TABLE_NAME) AS NO
,A.TABLE_NAME
,B.COMMENTS
,TO_NUMBER(
     EXTRACTVALUE(
     XMLTYPE(
      DBMS_XMLGEN.GETXML('SELECT COUNT(*) C FROM '||A.OWNER||'.'||A.TABLE_NAME))
     ,'/ROWSET/ROW/C')) AS COUNT
,A.NUM_ROWS
,A.AVG_ROW_LEN
,A.SAMPLE_SIZE
,A.LAST_ANALYZED
,SYSDATE
FROM ALL_TAB_STATISTICS A,ALL_TAB_COMMENTS B
WHERE A.TABLE_NAME = B.TABLE_NAME
AND A.OWNER = B.OWNER
ORDER BY A.TABLE_NAME

```


でも結局全テーブルにCount(*)やっているわけで、件数が多いテーブルがいくつもあるとかなり時間がかかってしまう。
その場合は、その場で統計情報を取り直してから前のSQLでやったほうがいいかもしれない。


```sql:統計情報更新

DBMS_STATS.GATHER_SCHEMA_STATS (
	 OWNNAME => USER
	,OPTIONS => 'GATHER AUTO'
)

```
SESを4年やっておもったこと

アウトプット残したいと思ってQiita始めたもののネタに乏しいので 
とりあえず金融・証券系SEとしてだいたい4年働いて思ったことをつらつら綴ります。

#経歴
- 都内在住　院卒4年目　３０さい。
- だいたい２ヶ月～１年ぐらいでプロジェクトを転々としてる常駐SE
- とりあえず使えるスキル：Java,JavaScript,HTML5,CSS3　
- 目下勉強中:Python,Ruby,Golang,React
  
#SIerってどうなん？
金融証券メインでやってきたんで全部が全部とは思いませんが、いいとこわるいとこ挙げてみます。
###いいところ
* **研修はしっかりしてる**  
文系・未経験OKってのもあって研修はまあ役に立ちました。基本情報くらいはあれだけでとれるんじゃないかな。
* **お給料いい**  
初任給はよかったです。まあ基本給はそんなでもないけど。手当で盛るパターンのやつです。
* **残業少ない**  
業界柄か残業は少なめ。1,2次受けが多いってのもあるんでしょう。僕はMaxで30hくらい。普段は5~10hくらい。  
* **有給とれる**  
これは会社がよかったのかな？チームで常駐のおかげか結構とれました。

###わるいところ
* **スキル身につかない**  
どうしても枯れた技術を使いがち。Java6とかいまだに使ってたりする。  
フレームワークも謎の独自フレームワーク使ってる。  
一番きつかったのはWindowsのバッチファイル(*.bat)を延々書かされたこと。  
もっとモダンな開発したい。
* **Excel使いすぎ問題**  
設計書とかドキュメント類やたらめったらExcel使うよね。  
コーディングよりExcelいじってる時間のが長い。関数めっちゃ覚えた。
* **時間 > 成果**  
これはSIerというかSESの問題かも。アウトプットをどれだけ出すかよりも月160時間働いてるかってのが大事。  
なんもしないけど一日8時間を20日 > 頑張ってアウトプット出して5日くらい休む  
時間をお金で売る仕事ですね。  
最悪なのは客の都合でやることないとき。やることないのに会社いきたくないです。
* **意識低い**  
↑のせいか基本的に仕事は降ってくるせいかスキルを上げようみたいな風潮はない。  
アウトプット出してる人とかいるんかなあ。  
客先への貢献度云々みたいなとこは意識高い。  
ただこれに関しては僕もその一人だったんでなんとも言いづらい。

**SIerは悪い文明**

#転職したい
このままいても胸張ってエンジニアと言えそうもないんで転職したい。

###なにしたいん？  
* **自社開発**
バリッバリのウォーターフローで降りてくる仕事こなすだけみたいなのが続いたんでもうちょい能動的に仕事したい。
自社じゃなくてもできるかもだけどSESに対する忌避感が思ったより強い。
時間じゃなくて成果を売りたいし、プロダクトを成長させていくってのに魅力を感じる。
あとはやっぱりユーザーの反応をみながら開発するってのはモチベーションあがる。

* **スキルアップ**
現状スキルが高いとはとてもじゃないけど言えないんでガッツリコーディングやれるような環境に身を置きたい。
レベル高いエンジニアがいるような環境に身を置きたい。


###なにするん？
* **とりあえずアウトプットを作りたい**
↑みたいなことを思い出したのが最近なんで見せられるようなものが何もない。これはまずい。。。
週1でQiitaに投稿くらいはしてみる。Gitにコミットもがんばる。

* **勉強会とか参加する**
スキルアップにもつながるし、エンジニアのつながりを作りたい。

* **普通に転職活動**
エージェント登録とか転職サイト登録とか。
これはもう始めてる。

#最後に
ここまで読んでいただきありがとうございました。
Azure Container Instancesを既存vNetにデプロイする

Ignite 2018でContainer Instancesが既存vNetにデプロイできるようになったので試してみます。
これができると、ExpressRouteで接続されたvNetで利用できるので、セキュアな環境でコンテナを利用することができます。

執筆時点では、West US、West Europeの2リージョンでしか利用できません。

# vNet作成
まずはテスト用にvNetを作成します。今回は以下のパラメータで作ります。

* 場所
    * 米国西部
* アドレス空間
    * 192.168.0.0/24
* サブネット名
    * container
* サブネットCIDR
    * 192.168.0.0/27
* サービスエンドポイント
    * 無効

# Container InstancesとvNetを統合する
* 作成したvNetのサブネットを選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/180335/c94d3ddb-7dd9-fd6b-99d6-8231bf1ef99f.png)

* 「サブネットの委任」に[Microsoft.ContainerInstance/containerGroups]を選択し、保存する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/180335/d112b964-e703-5ed4-50fd-7e152a7cf731.png)

# コンテナをデプロイする
* Cloud Shell（Bash）を起動します。
* 今回は公式のチュートリアルでも使われているイメージ「microsoft/aci-helloworld」を使います。

```
az container create --resource-group [YOUR RESOURCE GROUP] --name container-test --image microsoft/aci-helloworld --vnet-name container-vnet --subnet container
```

* 結果がJSONで返ってくればOKです。（このサンプルアプリで起動まで大体2分くらい掛かりました。vNetのほうが起動まで時間が掛かるようです）

# 動作確認
* 作成されたコンテナーインスタンスの概要ページを開くと、IPアドレスがvNetのプライベートIPになっていることが分かります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/180335/94661398-0b8f-65a1-2fbc-9120d709ff8c.png)

* あとは別のSubnetを作って、VM立ててIEで接続してみます。
* Private IPで接続できていることが確認できます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/180335/7670ea6c-b40c-67ec-f229-a45daefeb8b2.png)

# まとめ
まだ日本リージョンにきてないので、ExpressRoute接続先vNetでの利用は難しそうですが、かなり使えると思いました。
ACI専用のサブネットにしないといけないので注意が必要です。
ExpressRoute接続先vNetに使ってないサブネット領域があれば、ACI専用サブネットとしてできそうですね。
もしサブネットを追加できない場合は、アドレス空間を追加してACI専用サブネットを作ればいけそうな気がする。
【OpenCV】imshow()のウィンドウの「位置固定&サイズが小さい&スケールできない」&ウィンドウが寄ってしまう時の対処法【Python3】

# 事象
VS Code上でOpenCVのimshow()を実行して画像を表示させて確認しようと実行すると、下図のような状況に陥ってしまいました。
<img width="1680" alt="【OpenCV】VS Codeで実行したimshowのウィンドウのサイズが小さい時の対処法.png" src="https://qiita-image-store.s3.amazonaws.com/0/205347/683367ad-285c-7637-1e45-bff659fbbb49.png">

# 動作環境
Python 3.7.0
VS Code: August 2018 (version 1.27)
opencv-python: 3.4.3.18

# 現象
* ウィンドウの位置が固定されてしまう。
* ウィンドウサイズが小さい。
* ウィンドウがスケールできない。
* キー入力すると表示させたウィンドウが固まる。

# 解決法
解決法は2Stepです。

まず前提として、imshow()を使用した画像表示のテンプレとして、

```
img = cv2.imread(IMAGE_PATH)
cv2.imshow('ウィンドウ名', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
```
このように書くかと思います。
waitKey()を呼ばないと、そもそも画像が表示されませんね？

### Step1
まずウィンドウの位置とサイズの件。imshow()で生成されるウィンドウにはデフォルトで```cv2.WINDOW_AUTOSIZE```というフラグが設定されているそうです。

そこで```cv2.namedWindow()```というメソッドがあるのですが、これに先ほどのフラグを```cv2.WINDOW_NORMAL```に指定すると、基本的にはサイズが変更可能になり、同時にウィンドウの位置固定も解除され、スケールも可能になります。

#### 使い方
```cv2.namedWindow('img', cv2.WINDOW_NORMAL)```


### Step2
はい、なっていない皆さんはこちらです。
これは画像を2つ以上表示させようとした人のみ起こっている可能性があるのですが、waitKey(0)で待機中にキー入力をすると、このように左に…
<img width="1680" alt="ウィンドウ左寄り.png" src="https://qiita-image-store.s3.amazonaws.com/0/205347/f9ba9327-1a11-d669-4226-808fee31d9bd.png">




<img width="211" alt="ウィンドウ左寄り_拡大.png" src="https://qiita-image-store.s3.amazonaws.com/0/205347/77b6d445-2999-5510-c98d-4e0ea73c324d.png">
###**なにしとんのwwwwwwwwwwwwwwwwwwwww**

はい。このように、なにしとんのになります。
これは```imshow()```を複数箇所で記述しており、その各所で```cv2.waitKey(0)```を記述している場合に起こります。
その場合、ソースコードの一番最後の```cv2.waitKey(0)```以外は不要なので削除しましょう。

以上。
iOSアプリのArchive→Export→Deploygateにuploadを自動化

# 自動化したかった作業
iOSアプリのよくある配布フローとして、Archiveから、development（adhocではない）で署名したipaを作成し、Deploygateにアップロードして、配布しているのですが、この作業のビルド待ち時間と、ちょっとした手作業に萎えていました。

# bashで自動化する
今回はbashスクリプトを作成しました。

## 必要なツール
+ Xcode Command Line Tools
+ deploygate command line tool

## スクリプトを用意

```create-ipa.sh
#!/bin/bash

# 作業ディレクトリ作成
mkdir build

# CleanしてArchive作成
xcodebuild -workspace hogehoge.xcworkspace \
    -scheme hogehoge \
    -configuration Release \
    clean archive \
    -archivePath ./build/build

# Exportしてipa作成
xcodebuild -exportArchive \
-archivePath ./build/build.xcarchive \
-exportPath ./build \
-exportOptionsPlist exportOptions.plist

# Deploygateにupload
if (( $# >  0   )); then 
   dg deploy ./build/iotwest-ios.ipa --message "$1"
else
   dg deploy ./build/iotwest-ios.ipa
fi
```
## Exportでのオプションファイルを用意
```exportOptions.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>compileBitcode</key>
	<false/>
	<key>method</key>
	<string>development</string>
	<key>signingStyle</key>
	<string>automatic</string>
	<key>stripSwiftSymbols</key>
	<true/>
	<key>teamID</key>
	<string>XXXXXXXX</string>
	<key>thinning</key>
	<string>&lt;none&gt;</string>
</dict>
</plist>
```
## 各ファイルの詳細は以下を参照してください
+ https://qiita.com/rsahara/items/024d9907af2c051f3d44
+ https://docs.deploygate.com/docs/cli
+ https://github.com/DeployGate/deploygate-cli

## ファイル構成
詳細は省きますが、以下のファイルを同じフォルダに配置します。
create-ipa.sh、exportOptions.plist、hogehoge.xcworkspace 

## bash実行
あとはターミナルからスクリプトを実行するだけ

```
 ./create-ipa.sh test
# testはメッセージです
```

処理が完了したら、Deploygateにuploadされました〜。
![deploygate.png](https://qiita-image-store.s3.amazonaws.com/0/103548/d204881b-e624-2cd4-85ae-66fd5afd33bb.png)

これで毎回の手作業から解放されました。

ありがとうございました！
Firebase+Nuxt.jsでTwitter認証する (つもりが勘違いでうまくいかなかった話)

## tl;dr

API Keyの入力欄にAccess Tokenを入れたことに気づかず数日を無駄にした。
おわり。

以下のあれこれは、上記キーの取り違えに気づくまでの間にやった意味不明な作業のメモで、役に立たないです。どんなミスをしたのかを書いています。

----

Qiita見てても分だの秒だの爆速だのでサクッとうまくいった記事ばっかなので、間抜けな記録が混じってもいいだろうと思って。

- Firebaseにのっけたい。便利なツールが色々あるので使いたい
- Nuxt.jsでWebアプリを書いてる
- 認証をTwitterのやつ使おう
（Google認証とか色々あるけどまずはTwitter)

余談ですがTwitter避けようぜキー発行厳しくなるし的な話ちょいちょ見かけますけど、個人的には厳しかったことは一度もない。
開発者アカウントの発行完了は秒でしたし、その後も特段困るような何かには遭遇してません。

## API Keyを間違えてる場合

> code:"auth/internal-error"

のエラーが返ってきます。他のケースでも多分出るけれども。

## FirebaseのAuthentication

Twitter側のコールバックURLに設定しろという謎のurlだが、これはFirebase側で引っ掛けて勝手に持っていく。
黙ってTwitter側のアプリ設定（Settings→Application Details
→Callback URLs）に入力したら、以降は忘れてよい。
自分のアプリ→Twitter→Firebase→自分のアプリ
と遷移するんだわな。
自前でやるときは自分のとこにコールバックさせるところを、ユーザ情報しまいこんだりする都合でワンクッション挟んでるだけだと（よくわかってなかった）。

```
https://myproject-id.firebaseapp.com/__/auth/handler
```

こんなん。
nuxt.js使ってるとアンスコで始まるurlって変数として使ったりするので、

- こんな奇妙なページ用意せんとあかんのか？
- でもそんなページ用意してる記事見かけないなー
- はっ もしかしてこの辺が面倒で誰も記事書いてないの？
- なんかGoogle認証だけで済ませてる記事はお茶濁してるの！？

という変な飛躍をし、nuxt.jsのrouterにextendRoutesして謎ページ作ったりすることで時間を浪費。

```nuxt.config.js（無駄）
  router: {
    extendRoutes(routes, resolve) {
        routes.push({
            name: 'auth_handler',
            path: '/__/auth/handler',
            component: resolve(__dirname, 'pages/Info/Hoge.vue')
        })
    }
  }
```
上記のミスをするのは私が人類で最後です。
こんなことはせんでよく、ただPopupだかRedirectだか指定して叩けばいいだけだった。

最初から最後まで、たんに初手でApiKeyを取り違えたとかいうミスですべてが上手くいっておらず、それに気づかないまま迷走しただけの話でした。
express + knex で作った API のテストを mocha + chai で書いた

express + knex の構築は書かず、 mocha + chai の記事になります。

## 導入

npm もしくは yarn でインストールすれば即実行できる。

`npm i -D mocha chai supertest`

```
const request = require("supertest")(require("../../app"))
const expect = require("chai").expect
const assert = require("chai").assert
const security = require("../security")

    describe("Authorization", () => {
        it("should return 200", async () => {
            return request
                .put(`/auth_test`)
                .set(
                    "Authorization",
                    await security.generateJWT()
                )
                .expect(200)
        })
    })
```

# よかったところ

## 柔軟な仕様

API でも Repository でも直接叩くこともできるので導入が早く、簡潔に検証を行える。

## テストを書く負担が軽い

`expect(customer).to.be.a("object")`
`expect(customer.id).to.be.equal(1)`

英文に近くてすぐに理解できる文法なので、テストフレームワークで消耗しなくて済む。

## 心理的負担の軽減

お恥ずかしながら、包括的にテストを書いたのは今回が初めてなので mocha + chai についてというよりもテストフレームワークについて。
テストがあることによって心理的負担がかなり減った。
テストによって動作を定義しながら構築していけるのはつよい。

## `describe` をネストすることでテストを構造化できる

API を使用するケース分けしてテストすることができるので思考の整理にもつながった。
1つのテストの中で複数の検証するのではなく、1つのテストで1つの検証という風に作るほうがテスト結果を見やすくていいのではと思っている。

```
  Customer
    POST /customer/register
      first registration
        ✓ should return 200 (2629ms)
        ✓ should register customer (1113ms)
        ✓ should register customer name (1113ms)
        ✓ should register customer email (1113ms)
        ✓ should add customer to group (1113ms)
      duplicate registration
        ✓ should return 400 (2629ms)
        ✓ should not register (1113ms)
```

# つまづいたところ

ここからは、つまづいたところを書いていく。
基本的なところが多いと思います。

## API がタイムアウトする問題

解決：mocha のタイムアウト設定を変更する

```
mocha --timeout 9000
```

## 前のテストのデータ変更が残る問題

解決：テスト実行前に毎回 `knex seed:run` を実行する

指定するファイルパスは `package.json` がある地点からです。

```js
    beforeEach(async () => {
        await knex.seed.run({directory: "./seeds/test"})
    })
```

## オートインクリメントがリセットされない問題

解決： seed ファイルでオートインクリメントをリセットする

```

    await knex.raw('ALTER TABLE customers AUTO_INCREMENT = 1');
    await knex('customers').insert([
        {
            name: "test"
        }
    ])
```
Thymeleaf：th:eachで出力するときに区切り文字を付けて出力する

## はじめに
Thymeleafでサクッとできるのに久々にやると忘れがちなのでメモしておく。

### やりたいこと
Listなどのコレクションに格納された情報をthymeleafで出力する際、読点「、」や斜線「／」のような区切り文字を付けて出力させたい。

```:リストのイメージ
{
	"Fruits": [
		{
			"name": "りんご"
		},
		{
			"name": "みかん"
		},
		{
			"name": "バナナ"
		}
	]
}
```

``` :出力結果
りんご、みかん、バナナ
```

## やり方

### ステップ１　とりあえず出力

``` html:とりあえず出力
<th:block th:each="fruit:${fruits}">
  <span th:text="${fruit.name}"></span>
</th:block>

```
``` :出力結果
りんごみかんバナナ
```

### ステップ２　読点を表示する

``` html:
<th:block th:each="fruit:${fruits}">
  <span th:text="${fruit.name}"></span>
  <span>、</span>
</th:block>
```
もちろんこれだと、バナナの後ろに読点が出てしまいます。

``` :出力結果
りんご、みかん、バナナ、
```

### ステップ３ ステータス変数のlastパラメータを利用して条件分岐
``` html:
<th:block th:each="fruit, iterStat:${fruits}"> <!-- ステータス変数はカンマ区切りで2つ目の引数として受け取れる -->
  <span th:text="${fruit.name}"></span>
  <span th:unless="${iterStat.last}">、</span><!-- last変数はループの最後でtrueを返します -->
</th:block>
```
これで、ループの最後だけ「、」を表示しないようにできます:relaxed:

``` :出力結果
りんご、みかん、バナナ
```


ステータス変数にはlast以外にもいくつかパラメータがあるので、覚えて使うとハッピーになれるかもしれません。
参考）[Tutorial: Using Thymeleaf (ja)　6.2 繰り返しステータスの保持](https://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf_ja.html#%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%97%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9%E3%81%AE%E4%BF%9D%E6%8C%81)

## おまけ

Tutorial: Using Thymeleaf にも書かれていますが、iterStatは明示的に書く必要がありません。
省略した場合、繰り返し変数（fruit）の後ろにStatを付けた変数名が暗黙的に作成されます。
可読性の兼ね合いで書いたほうがいいかなという気もしますが、こっちのほうがすっきりしますね。

``` html:
<th:block th:each="fruit :${fruits}">
  <span th:text="${fruit.name}"></span>
  <span th:unless="${fruitStat.last}">、</span>
</th:block>
```

おわり
２次元座標に相関があったりなかったりするデータを作る


２次元座標上の点に相関があったりなかったりする列を複数持つデータ群を作りたかった。
python素人なのでもっと良い書き方あるんだろうなと思いつつ。


![output_6_0.png](https://qiita-image-store.s3.amazonaws.com/0/5557/59d9fabd-73d6-6fe1-46a6-483d8023d74a.png)


```python
%matplotlib inline
```


```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
```


```python
np.random.choice(2, 2)
```




    array([0, 1])




```python
ROWS = 500
COLS = 3

np.random.seed(0)
index = list(map(lambda x: 'ATTR_{:03d}'.format(x), range(COLS)))
names = list(map(lambda x: 'F_{:03d}'.format(x), range(ROWS)))
index.insert(0, '_x')
index.insert(1, '_y')
masks = list(map(lambda x: np.random.choice(2, 2), range(COLS)))
ws = list(map(lambda x: np.random.rand(2), range(COLS)))

df = pd.DataFrame()

print('masks=', masks) 
print('ws=', ws) 
a, b = np.random.rand(2)
for i in range(ROWS):
    x, y = np.random.rand(2)
    vs = list(map(lambda a: x*ws[a][0]*masks[a][0] + y*ws[a][1]*masks[a][1]+ np.random.rand(1)[0]/10, range(COLS)))
    vals = [x,y]
    vals.extend(vs)

    
    ddf = pd.Series(vals, index=index, name=names[i])
    df = df.append(ddf)
df.T
```



```python
from pandas.plotting import scatter_matrix

scatter_matrix(df, diagonal='kde', color='k', alpha=0.5)

plt.show()
```
yarn関連のフォルダ

## tl;dr
windows 7
nodist v0.8.8
yarn v1.9.4

yarn global でPATHを通す際によくわからなくなったので

## 確認

```
$ yarn global bin
C:\Program Files (x86)\Nodist\bin\bin

$ yarn global dir
C:\Users\xxx\AppData\Local\Yarn\Data\global
```
yarn global dir の方は直下の```node_modules\.bin``` に```.cmd```ファイルがあり、
そこで```node_modules```のファイルを呼び出している

yarn global bin の方は、
yarn global dirで指定されているフォルダの```node_modules\.bin```以下の、
対応する```.cmd```ファイルを指定している

## 結局
PATHはどちらも通しておいた

## 余談
C:\Users\xxx\AppData\Local\Yarn\bin

以下にも一部の```.cmd```ファイルがあったが、消しても問題なく動いたのでnodist導入前のゴミだと思われる
Azure Public IP Prefixとは

#はじめに

最近ごたごたしていてQiitaの記事が書けていなかった鶴見です。
依然としてパブリッククラウド(AWS,Azure)に関するお仕事しています。

それにしてもIgniteで発表された機能やサービスの数はスゴイですね。
いつもは2,3個しか更新のないAzure Updateのページが一気に50個近く更新されていました。
いやはや、おそるべし。

そんな更新の中で色々時になるものはあったのですが、今回は**Public IP Prefix**について取り上げてみたいと思います。

#Public IPについて
まずは、おさらいとしてAzureのPublic IPに関して書いていきます。
Public IPはAzure上のリソースをインターネットから到達可能にするためのエンドポイントです。
つまり、**インターネット経由で到達可能なIPアドレス**です。
このPublic IPを仮想マシンのNICに紐づけることによって、仮想マシンへ外部から接続が可能になります。

Public IPは基本的に動的なIPアドレスとなっており、仮想マシンを停止すると解放され、次回起動時には別のIPアドレスが割り当てられます。
永続して**同じIPを使用したい場合は静的設定をする**ことによって実現可能です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/181154/6fc0e0ed-fc18-2e10-9ad6-75c29d64cea2.png)
↑Public IPの構成画面から変更可能

#Public IP Prefixとは
ではIgniteで発表されたPublic IP Prefixとは何なのでしょう。

英語版しかございませんが既にドキュメントが更新されています。
https://docs.microsoft.com/ja-jp/azure/virtual-network/public-ip-address-prefix

ざっくりとまとめると
**プレフィックスで指定した範囲分のIPアドレスをリージョンごとのIPアドレス帯から予約する**
機能になります。

Azureはリージョンごとに使用されるPublic IPアドレス帯があります。(以下のリンクに記載)
https://www.microsoft.com/download/details.aspx?id=41653

Public IP Prefixはプレフィックス長を指定することによってその分だけPublic IPアドレスを確保するサービスです。

#実装方法

以下は実際の画面になります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/181154/12ed0fa8-42bd-cfe1-2409-b818bd059117.png)
Public IP Prefixの画面から【追加】を押すと作成ウィザードが出てきます。
入れる情報はサブスクリプション、リソースグループ、リージョン、名前、そしてプレフィックス長です。
プレフィックス長は最大で/24まで選択可能です。
またリージョンに関してはWest Central US,West US,West US 2,Central US,North Europe,West Europe,Southeast Asiaに限定されています。
その後、必要に応じてタグを着けて、【作成】を押せば完了です。

作成されたリソースは以下のようになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/181154/3515e646-0c3a-8ba0-b30a-6a13619c4d23.png)
今回は13.64.32.80/28が予約されたようです。どこの範囲のIPかは指定できませんが、ある程度Public IP帯をまとめて任意に仮想マシンにIPアドレスを割り振れることによって様々な運用が楽になるかと思います。

実際に予約したIPアドレスを使用する際には、まずPublic IPを作成する必要があります。
(あくまでも上の状態だと予約しただけでIPアドレスが作成されたわけではないため)
現状、この作業はコマンドラインでしか行えません。
以下はその例になります。

```powershell
#PublicIpPrefixの情報取得
$pipp = Get-AzureRmPublicIpPrefix -ResourceGroupName "PublicIPs" -Name "Myprefix"

#PublicIpPrefixをベースに新しいPublicIPを作成
$New-AzureRmPublicIpAddress -ResourceGroupName "PublicIPs" -Name "testpip1" -Location "westus" `
 -Sku Standard -AllocationMethod Static -PublicIpPrefix $pipp

```

上記の様にPublic IPを作成することで、以下のようにポータルでも確認することが出来ます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/181154/dedd7f0b-d84c-97d6-8592-7d93863e09b0.png)
厳密なIPまでは指定できなかったので、若番から作られていくみたいですね。
後は、他のPublicIPと同様に紐づけるだけで完了です。

#終わりに
確かに便利だとは思うのですが、個人的には上手いユースケースが思い当たらないというのが正直な感想になります。
自分のつけたいIPを付けられるメリットは確かにあるとは思いますが、どうなんでしょうね。
あと、色んな人がこぞって/24とかで作成したら、枯渇するんじゃないかとも思いました。
そこは完全に早いもの順になるんですかね？
リージョンごとのPublic IPアドレス帯は変更されると聞いたことありますが、その際はどうなるんでしょうね。
謎が謎を呼びます。

しかし、IPアドレスの運用に柔軟性が増したのは確かなので、今後どんどん機能を追加してくれればと思います。
(いずれはAWSのIPアドレス持ち込みみたいなところまで)

ではでは、お読みいただきありがとうございました。
WordPressプラグイン　便利

•	Admin Menu Editor（管理画面のメニュー管理）
•	ARI Adminer（カスタマイズ時にDBのデータをみるため）
•	Category Order and Taxonomy Terms Order（タクソノミー並び替え）
•	Custom Post Type Widgets（カスタム投稿を表示したい）
•	Duplicate Post（投稿の複製）
•	Enable Media Replace（メディアの差し替えができるようになる）
•	TinyMCE Advanced（投稿の編集機能を充実させる）
•	TinyMCE テンプレート
•	User Role Editor（ユーザー権限の管理）
•	WP Multibyte Patch （日本語版WordPressのマルチバイト文字取り扱い不具合修正）
•	WP Taxonomy Import（タクソノミーの登録がかんたんにできる）
         →カスタマイズした管理者も利用可能になるように権限を変更する
PPT文書の画像を置き換える

この資料では、Spire.Presentationを使用してPPTドキュメントのイメージを置き換える方法について説明します。
ツール：[Spire.Presentation for .NET](https://www.e-iceblue.com/Introduce/presentation-for-net-introduce.html); Visual Studio
元の文書は次のとおりです:
![1.jpg](https://qiita-image-store.s3.amazonaws.com/0/278784/fcce82bd-819c-04c9-3e98-45634e56b879.jpeg)
**方法、ステップ**
ステップ1:  Spire.Presentation for .NETをダウンロードしてインストールし、プロジェクトにSpire.Presentation.dllファイルを参照します。
ステップ2: Visual Studioにコードを挿入する：

```ruby:C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Spire.Presentation;
using Spire.Presentation.Drawing;
using System.Drawing;

namespace Replace_Image3
{
    class Program
    {
        static void Main(string[] args)
        {
            //プレゼンテーションインスタンスを作成する
            Presentation ppt = new Presentation();
            //PowerPointドキュメントを読み込む
            ppt.LoadFromFile("テスト.pptx");

            //最初のスライドを取得する
            ISlide slide = ppt.Slides[0];

            //指定したイメージを置き換える新しいイメージを追加する
            IImageData image = ppt.Images.Append(Image.FromFile("ピクチャ.jpg"));

            //スライド内の図形を横断する
            foreach (IShape shape in slide.Shapes)
            {
                //図形が写真かどうかを判断する
                if (shape is SlidePicture)
                {
                    //画像のタイトルを決定する
                    if (shape.AlternativeTitle == "イメージ1")
                    {
                        //「イメージ1」というタイトルの画像を新しい画像に置き換えます
                        (shape as SlidePicture).PictureFill.Picture.EmbedImage = image;
                    }
                }
            }

            //ファイルを保存する
            ppt.SaveToFile("結果.pptx", FileFormat.Pptx2013);

        }
    }
}

```
コードをデバッグして実行した後、生成されたドキュメントは図のようになります：
![2.jpg](https://qiita-image-store.s3.amazonaws.com/0/278784/dd1263a3-907f-4904-5929-7dc92b012787.jpeg)
Motif Window Manager (MWM) on CentOS 7 チートシート

```bash
## パッケージインストール
sudo yum -y epel-release
sudo rm -frv /var/cache/yum
sudo yum -y install ansible git tigervnc-server

## SSH パス無し秘密鍵生成: Playbook 実行時に必要。
ssh-keygen -q -t ed25519 -N "" -f ~/.ssh/id_ed25519
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
echo "StrictHostKeyChecking no" | tee ~/.ssh/config
chmod -v 0600 ~/.ssh/authorized_keys ~/.ssh/config

## Playbook ダウンロード
cd; pwd
mkdir -v roles
cd roles; pwd
git clone https://github.com/sb3f-ryo-sato/ansible-role-legacy-desktop.git

## 環境構築
cd ansible-role-legacy-desktop/installer; pwd
ansible-playbook setup-legacy-desktop.yml -i hosts.yml

## 設定ファイル初期化
cd; pwd
cp -aiv ~/.bashrc ~/.bashrc.`date +%Y%m%d`
cp -afv /etc/skel/.bashrc .
cp -afv /etc/skel/.Xresources .
```

利用方法は [VNC 利用手順まとめ](https://qiita.com/ryo-sato/items/7cf2da401dd13dd4f36d) を参照すること。

どっとはらい。
PHPのバージョンについて考える

PHP5.6のセキュリティサポートが2018/12/31までで終了するらしい。
ちなみにPHP7.0も2018/12/03にセキュリティサポートが終了。

公式サイトのバージョン情報
http://jp2.php.net/supported-versions.php
![スクリーンショット 2018-09-26 13.50.29.png](https://qiita-image-store.s3.amazonaws.com/0/169308/a7b7ae22-c992-900d-b4ff-bbd6bf7abc30.png)

OSが提供するセキュリティパッチを当ててくれるホスティングサービスもあるので、公式でサポート対象外になってもまだ希望はある。
ということで主要レンタルサーバのPHPのバージョンの対応状況について少し調べてみた。

## さくらインターネット

PHP5.6、7.xに対して、PHPのアップデートに関してのポリシーとスケジュールが公開されている。
2018年7月11日から適用
https://help.sakura.ad.jp/hc/ja/articles/360000115461-PHP%E6%8F%90%E4%BE%9B%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC

マイナーバージョンアップデートは自動で行われるらしいので、PHP7.2を選択する場合は注意が必要。

PHP4.4、5.2、5.3、5.4は提供はされているが、サポートは終了している。

## ロリポップ
PHP5.6、7.1が利用できる。
「サポート対象外です。」と記載があるので、独自でセキュリティパッチを当てるような対応をしているかは微妙。
https://lolipop.jp/manual/hp/cgi/

2017/02/09にPHP5.5終了のお知らせが出ている。
https://lolipop.jp/info/news/5596/

PHP5.5の公式のセキュリティサポートが終了したのは2016/07/21。
およそ7ヶ月放置していたみたいなので、PHP5.6もそんな対応になるんじゃないかな。

## Xサーバー
PHP5.1、5.3、5.4、5.5、5.6、7.xが利用できる。
PHP5.5の利用は推奨されていない。
PHP5.1、5.3、5.4はOSが提供するパッチを当てているが、PHP7.2への移行を推奨している。
PHP５.6もPHP7.2への移行が推奨されている。
https://www.xserver.ne.jp/manual/man_program_php_ver.php

旧仕様のサーバーは、新しいサーバー環境への移行メンテナンス後からPHP7.2を利用できる。

移行スケジュール
https://www.xserver.ne.jp/news_detail.php?view_id=4057

## CPI
PHP5.6、7.0、7.1が利用できる。
https://www.cpi.ad.jp/shared/detail/php.html

---
# 所感
パッチを当てていると明記されているのはXサーバーだけだった。
公式でセキュリティサポートが切れたPHP5.5以下のバージョンをまだ利用している人は、その点を肝に銘じておこう。
PHP5.6のセキュリティサポート終了後、パッチが出るかどうかもわからないので、PHP7.2への移行を考える時期だと感じた。
さくらインターネットの自動マイナーアップデートは、アップデート後に不具合等出ていないか確認するなど注意は必要だが、良い施策だと思う。

## （おまけ）WordPressについて
WordPressは、PHP7.2以上を推奨している。
でもPHP5.2.4以上であれば動く。（但し、セキュリティについては上記の通り）
https://ja.wordpress.org/about/requirements/

以上、全て2018/09/26時点の情報です。
【無駄骨】EC2でVirtualBoxを使ったらダメな話

#目的
仮想OSにさらに仮想OS載せても動くわけない。をやってみた。

#以下やった事
EC2でWindowsOSを作って、その上で作業。
VirtualBoxのインストールメディアをダウンロードして実行
![image.png](https://qiita-image-store.s3.amazonaws.com/0/185989/dc37d60c-2a2e-8bdb-3396-1f04c0529c12.png)
とりあえずインストールできました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/185989/f1d3c19f-4be3-79e9-6ab0-abcb7aef624d.png)

VirtualBoxを開くと、ゲストOSは３２bitのみ可能。。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/185989/aab5981f-2ff8-b1bf-4966-a1c69291b3d8.png)
とりあえず、ゲストOSを作れました、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/185989/00b0df96-3b78-a55f-a72f-0d40a6710a4c.png)
CentOSのインストールメディアを選択して、起動すると・・・
![image.png](https://qiita-image-store.s3.amazonaws.com/0/185989/e5b19eb3-ae5c-0288-b81b-b47b7fa0a74a.png)
はい終わり
![image.png](https://qiita-image-store.s3.amazonaws.com/0/185989/7de5ad28-6d70-410b-b3df-21d4e931367d.png)

#まとめ
という事で、無駄骨ですので以後検討除外しませう。
ちなみに、リモートデスクトップは遮断されますが、インスタンス自体は生きている様子。
再起動すればOS自体は使えるみたいですが、そんなOS気持ち悪いのでとっととTerminateしませう。
Mojaveにcarthageがインストールできないのでどうにかする

クリーンインストールしたMojave(macOS 10.14)にcarthageをインストールしようとしたら2018年9月26日15時（日本時間）の時点ではエラーでインストールできなかった。
# TL;DR
High Sierra用の[bottle](https://homebrew.bintray.com/bottles/carthage-0.30.1.high_sierra.bottle.tar.gz)を使う

# なんで？
Mojave用のbottleが用意されていないのでソースからコンパイルする必要があるけどエラー（詳細は割愛）でコンパイルが通らない。多分

- Mojave用のbottleが用意されていないのでソースからコンパイルする必要がある
- コンパイルエラーになるのでbottleが作成されない

というデッドロックになっているんじゃないかと思う（ちゃんと調査はしてない）。
詳細は[これ](https://github.com/Homebrew/homebrew-core/pull/32403)かな？

# というわけで
エラーを解決するのはすごい人たちに任せて，ユーザはHigh Sierra用のbottleを `/usr/local/Cellar` に配置してlinkするだけ。

```console
user$ curl -fsSL https://homebrew.bintray.com/bottles/carthage-0.30.1.high_sierra.bottle.tar.gz | tar -xzC /usr/local/Cellar 
user$ brew link carthage
```

とりあえず問題なく動いているっぽいので公式に対応されるまではこれでいいと思う。
SCPのファイル転送を途中から再開する

SCPでファイル転送をしていた時に途中でstallしてしまったり、コネクションが途切れてしまった時のための備忘録です。
(Windows未対応)

###rsyncを使う

rsyncを利用することでファイル転送を途中から再開できます。
以下はカレントディレクトリーの`file1`を`user@hostname:~/file1`に通常のssh設定で転送する場合の例です。

```
rsync --partial --progress --rsh=ssh ./file1 user@hostname:~/file1
```

22番ポート以外のポートでsshセッションを実行する場合のは以下のようなコマンドになります。
(10022番ポート利用時のコマンド例です)

```
rsync --partial --progress --rsh=ssh -e "ssh -p 10022" ./file1 user@hostname:~/file1
```

公開鍵認証を利用したsshセッションの場合は以下のようなコマンドになります。
(鍵ファイル~/Downloads/host1_id_rsa利用時のコマンド例です)

```
rsync --partial --progress --rsh=ssh -e "ssh -i ~/Downloads/host1_id_rsa" ./file1 user@hostname:~/file1
```

中断したい場合は`ctrl`+`c`で抜けます。
以上です。
CSS Blend Modesつかってみよう

Photoshopで合成してもらうような要素と要素の合成だったり、
画像と色だったりの合成がCSSでもできます。べんり。

## mix-blend-mode と background-blend-mode

平たく言うと、
- `mix-blend-mode` → img画像
- `background-blend-mode` →　背景画像を使いたい場合

### ブラウザ対応状況

mix-blend-mode
![スクリーンショット 2018-09-26 13.57.38.png](https://qiita-image-store.s3.amazonaws.com/0/30278/31f24d6b-77b4-26ea-852d-80558cc65a6a.png)

background-blend-mode
![スクリーンショット 2018-09-26 13.55.38.png](https://qiita-image-store.s3.amazonaws.com/0/30278/c0b7ada7-1d23-13d1-8a09-d64955ccb376.png)

IE,Edgeテメーはゆるさねぇ

## mix-blend-mode

画像と画像、色と画像を合成したい時に使えます。

```html
<div class="bg">
  <img src="hoge.jpg">
  <img src="moge.jpg">
</div>
```

```css
.bg img {
  mix-blend-mode: overlay; //値は変えられます。今回はoverlay
}
```

これらが
![スクリーンショット 2018-09-26 16.26.22.png](https://qiita-image-store.s3.amazonaws.com/0/30278/ee34af5b-172f-d975-4a7f-7e994a3497a8.png)

こうなります
![スクリーンショット 2018-09-26 16.26.40.png](https://qiita-image-store.s3.amazonaws.com/0/30278/2b3fad83-09ca-5fda-8c44-bf223f297c2d.png)

実例はこちら
https://codepen.io/komacchi/pen/ZMgQPd


## background-blend-mode

背景画像と背景画像、色と背景画像を合成したい時に使えます。

```html
<div class="bg"></div>
```

```css
.bg{
  background-blend-mode: darken;  // 今回はdarken
  background-image: url('hoge.jpg'), url('moge.jpg');
  background-size: cover;
}
```

これらが
![スクリーンショット 2018-09-26 16.26.22.png](https://qiita-image-store.s3.amazonaws.com/0/30278/ee34af5b-172f-d975-4a7f-7e994a3497a8.png)

こうなります

<img width="472" alt="スクリーンショット 2018-09-26 16.54.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/30278/aefa55b6-a9b7-37fa-c874-478583674a89.png">


実例はこちら
https://codepen.io/komacchi/pen/QVeNEP

## 参考
https://developer.mozilla.org/ja/docs/Web/CSS/mix-blend-mode
https://developer.mozilla.org/ja/docs/Web/CSS/background-blend-mode

べんりだけど
使用上の注意をよく読み用法・用量を守って正しくお使い下さい。

おわり
スプリント期間別スクラムイベント時間早見表

スプリント期間別にスクラムイベントの時間（タイムボックス）を一覧表にしました。
本家スクラムガイドを参考に、単純にスプリント期間に比例させて時間を計算しています。

* [Scrum Guide Downloads \| Scrum Guides](https://www.scrumguides.org/download.html)

|   | 1ヶ月（4週間） | 3週間 | 2週間 | 1週間 |
|:--|:-:|:-:|:-:|:-:|
| スプリントプランニング  | 8h  | 6h | 4h  | 2h  |
| スプリントレビュー  | 4h  | 3h | 2h  | 1h  |
| スプリントレトロスペクティブ  | 3h  | 2.25h | 1.5h  | 0.75h  |

スクラムガイドでは1ヶ月スプリントのときの最大時間が明記されています。
それより短いスプリントではスクラムイベントも短くすることが多いと言われているだけなので、この表の時間はあくまで目安です。
スクラムではタイムボックスを重要視していますので、みなさんのスクラムで採用するタイムボックスの参考にぜひしてください。
Android Database access

# AndroidのDB利用手順

1. __DBヘルパークラスを__用意し、それをNewすることでヘルパーオブジェクトを生成する。
2. アクティビティなどで、ヘルパーオブジェクトから__DB接続オブジェクト（SQLiteDatabaseObject）__を取得する。
3. DB接続オブジェクトを使って__SQLを実行__する。

## HelperClass

### 作成方法

AndroidSDKにはSQLiteOpenHelperがあるが、それを継承して作成しなければならない。

onCreateとonUpgrateとconstructerを記述しないと確実に動作しない、がそれが必要なため、絶対に動かないように設定されいてる。

- __constructer__
- onCreate()
- onUpgrade()

super(4個引数);<-これがないとコンパイルエラーに
と親クラスのコンストラクタを呼び出すCodeを記述する。
４個の引数は以下の通りとなる

#### Context context

コンテキストはこのクラス内で用意できないので、このクラスを使うアクティビティなどからもらう必要がある。
->このDBヘルパークラスのコンストラクタの引数としておく必要があり。

```java:example
public DtabaseHelper(Context context){
  super(context, ....)
}
```

#### String name

使用するデータベース__ファイル名__


#### CursorFactory factory

カーソルのファクトリオブジェクト(所謂ResultSet)

基本的にいじらない事が多いのでNullで良い

#### int version

整数で１始まり

Androidでは内部のDBがバージョン番号とともに、管理されている。
ここで渡す番号より内部の番号が若い（小さい）場合はあ後述の`onUpgrade()`が自動実行される。

ソフトをアップデートをしたタイミングで走らせるもの。__本番運用する際に大事__


### 今日のtips

第二引数のデータベースファイル名と、第四引数のバージョン番号は、この__クラスの定数__として記述しておく。

定数管理をするとやりやすいよね。

```java:example
/**
 * データベースの名前
 */
private static final String DATABASE_NAME = "example.db";

/**
 * バージョン番号
 */
private static final int DATABASE_VERSION = 1;
```

## onCreate()

内部に__データベースが存在しない時（初期状態）に一回だけ実行__されるメソッド。

CREATE TABLE など、初期設定に必要なSQLをここで実行する。引数のdbはDB接続オブジェクトなので、そのメソッドを利用する。

DLL文の実行は execSQL(...) を使用する。

各テーブルの主キーはINTEGER型でカラム名は`_id`とする。

必要なら、AUTOINCREMENT(連番主キー）とする。

#### Tips

カラム名の主キーは`_id`が強制されている。

-> _id だと ○○○_id というふうに文字連結しやすい。

`onCreate()`の実行は一回だけ　一回だけ、　インストール直後に　一回だけ実行される。（アプリをアンインストールすれば問題ない）

### onUpgrade()

以下の、第2、第３引数の違いを利用して、ALTER TABLE などのDB内部の構造を変更する。

引数はonCreate()同様DB接続オブジェクト

第二: oldVersion -> 現在の内部番号

第三: newVersion -> constructorで設定された番号

現在はデータを退避させてテーブルを一から作成させてINSERTを行っているらしい。


## データアクセス

基本手順

AndroidでのDB接続手順は以下の通り

1. ヘルパーオブジェクトを生成する。
2. ヘルパーからDB接続オブジェクトをもらう。
3. データ処理を行う（後述）
4. DB接続オブジェクトを解放する必要がある。(確実に解放しなければならない）

ソースコードのパターンとして以下のようになる。

```java

DatabaseHelper helper = new DatabaseHelper(...); //1
SQLiteDatabase db = helper.getWritableDatabase(); //2

try{
  //dbを使用してデータ処理 3
catch(Exception e){
  //例外処理
}finally{
  db.close();// 4
}
```

## 更新系

INSERT/UPDATE/DELETE文の発行手順は、以下の通り。

### SQL文字列を作成する。

このとき変数によって値が変わるところを`?`と記述する。

`String sqlDelete = "DELETE FORM .... _id = ?" `このような形
 
### ステートメントオブジェクトをもらう

`SQLiteStatement stmt = db.compileStatement(sqlDelete);`

### 変数をバインドする

上記に　→SQL文字列を作成する で記載した？（プレースホルダ）に値を埋め込む。

`stmt.bindLong(数字, 挿入するもの)`  (各種型のmethodがある)

### SQLを実行する

- INSERT: stmt.executeInsert();
- UPDATE/DELETE: stmt.executeUpdateDelete();

## 参照系

SELECT文の発行手順は以下の通り。

### SQL文字列を作成する

更新系と違いバインド変数は使いづらいので、変数は文字列結合する。

### カーソルをループする

CursorはResultSetと同じようなものなので、同じくループする`while(cursor.moveToNext(){}`表現が明らかに１行の場合はifでも可能

### 各行のデータを取得する。

カーソルでループする部分で、各行のデータを取得する。

ただし、ResultSetのように、カラム名では、直接取り出すmethodがないので、一度カラムインデックスを取得して使う。

```java
int idxNote = cursor.getColumnIndex("note");
String note = cursor.getString(idxNote);
```
manページをPDF化する

以下の方法でmanページをPDF化できる。

```sh
$ man -t {pdf化したいマニュアル名} | ps2pdf - {出力pdf名}
// 例
$ man -t git | ps2pdf - git.pdf
```

macの場合、ps2pdfは下記方法でインストールできるはず。

```sh
$ brew install ghostscript
```



## 参考文献
https://gist.github.com/DQNEO/8b3061df9bf687a943f4497417b6cb9b
CM.comのSMS送信APIでSMSを送信してみたら他の機能も発見した

## SMS送信から世界のメッセージサプライヤーへ CM.com

オランダのサッカー１部リーグに所属するBredaNACのオフィシャルスポンサーをしているCM.com
![CM NAC.jpg](https://qiita-image-store.s3.amazonaws.com/0/283578/ecd23d1f-4338-9613-a5fc-683b625f44de.jpeg)

サッカー好きなら一度は目にしたことがあるロゴだろう。
※2023年現在、CM.comはサッカーチームのオフィシャルスポンサーではなく、F1のオランダグランプリのオフィシャルスポンサーになっています。

この会社、実はSMS配信サービスの会社でSMS配信ツールをAPIでもプラットフォームでも提供している。
しかも低コストなので、SMS認証や通知などでガンガン使いたい人にはおすすめ
https://www.cm.com/ja-jp/sms/sms-gateway-api/

価格は日本国内なら1通8.19円


お問い合わせも日本語で対応してくれるので安心

## 利用方法
①CM.comのサイトから問い合わせして、アカウントを作成
②クレジットカードでチャージ（連絡すると後払いにも対応してもらえる）して、SMSゲートウェイのプロダクトトークンを取得
③いざ、開発
![image.png](https://qiita-image-store.s3.amazonaws.com/0/283578/6dc2ca1b-8acf-aa1f-d622-058eebf602b2.png)

　SMSの送信コードもとっても簡単で何より問い合わせなしに、テストや利用開始ができるのが嬉しい。

## コードサンプル

```cs
var request = new {
    messages = new { // プロダクトトークンはここから確認する:gateway.cmtelecom.com
        authentication = new {producttoken = new Guid("ここにプロダクトトークンを入力")},
        msg = new[] { new {
            from = "送信者名をここに入力",//送信者名に関しては下記＊１を確認
            to = new[] { new { number = "<+81ここに電話番号>" }},
                //宛先の電話番号は日本国内だと+81に電話番号の頭の0をとる　例+819011112222
            body = new { type = "AUTO", content = "ここに本文。70文字制限"}
        }}
    }
};
```


```cs
using (var client = new HttpClient())
{
    var content = new StringContent(
        JsonConvert.SerializeObject(request), 
        Encoding.UTF8, 
        "application/json");
            
    var response = client.PostAsync("https://gw.cmtelecom.com/v1.0/message", content).GetAwaiter().GetResult();
    response.EnsureSuccessStatusCode();
}
```

## 注意点
*1　送信者名はアルファベットから始まる任意の文字数字列（auはランダムな数字になるので設定不可能）
電話番号が良い場合には問い合わせをすると無料で対応してくれます

## Github

https://github.com/cmdotcom/text-api-publications/tree/master/Qiita-2018/SmsSample

## 感想
初めてSMS送信APIを使ってみたが、非常に簡単だった。
強いて言えば、080の宛先に送信先の番号に+81+80のように国番号に電話番号の最初の0をのぞいて入力するのを忘れがちなので気をつけたい。

エラーコードなどもう少し細かいリクエストをかける場合には下記仕様書を参照すべし
https://developers.cm.com/messaging/docs

## 2023年1月更新

久しぶりにCM.comのプロダクトを見てみると、かなりAPIでいろいろなことができるようになっていた！
まず、ランディングページを作成する機能があって、それを作ってSMSAPIで実装できる
https://www.cm.com/ja-jp/pages/

あと、Eメール送信ツールの提供もしていて、API連携が可能。
このサービスもいろいろありそうなので今度別に書いてみたい。
https://www.cm.com/ja-jp/email-campaigns/

SMS双方向やWhatsappやインスタグラム、Facebookメッセンジャーの双方向APIもある。
https://www.cm.com/ja-jp/business-messaging-api/

海外にもSMSを送ることができると記載があったので、今度試してみたい。
APIGateway Lambda DynamoDBでサーバーレスのWebアプリを作ってみた感想

#はじめに
ある現場で
リーダー「簡単なWebアプリだからAWSにちゃちゃっと移行しといて」
私「わかりました。PHPとMySQLで作られているようなのでEC2とRDS使いますね」
リーダー「ダメ。APIGatewayとLambda使ってサーバーレスにして。あとDBはDynamoDB」
とよくわからないことを言われました。


APIGatewayもLambdaもDynamoDBもサーバーレスもよく知らない状態から
なんとか本番リリースできたので、感想をまとめておきます。
(2016年時点での話になります。)

#環境について

||移行前|移行後|
|:--|:-:|:-:|
|環境|オンプレミス|AWS|
|言語(サービス)|PHP|APIGateway, Lambda|
|DB|MySQL|DynamoDB|

#APIGatewayについて
- Lambdaにデータが渡らない等の問題が発生した場合、原因究明が大変。ログは出力されるけどわかりにくい。特に本番では大量にログ出力されるため、探すだけでも大変。
- 当時はバグらしきものが結構あった。(Mapping Templatesにミスがあったり、設定更新が反映されてなかったり。でも数日で修正されてた。)
- APIGatewayのキャッシュが便利。というかアクセスが多い場合は必須。
- APIGateway設定のバックアップ、リストアが完全にできなかった。

#Lambda(Node.js)について
- Lambda単体であればローカル環境でも簡単にデバッグ可能。
- APIGatewayと組み合わせて使用する場合は、ローカル環境ではAPIGatewayのモックが必要。
当時は良いフレームワークやライブラリがなかったためモックも自作した。
- 初回起動に時間がかかる。Lambdaだけタイマーで定期的に動かしてみたけど、APIGatewayを通して呼び出すとやっぱり初回は時間がかかってしまう。
- ひとつのLambdaをどれくらいの規模（ひとつのリクエスト、ひとつの機能、ひとつのアプリ等）にすべきか難しい。
- Webアプリとして考えるとバージョン管理が大変。Lambda単位でバージョンをつけるため。


#DynamoDBについて
- 一般的なNoSQLの特徴。（RDBとは異なるテーブル設計が必要。テーブル結合できない。パーティションキーが重要等。）
- 空文字が利用できない。
- ローカル環境でも使用できるので開発中は便利。
- データ取得時の容量制限（1MB）があるので、大量に取得したい場合は複数回呼び出す必要がある。
- アクセスが多いとお金が結構かかる。


#その他
- アクセス数によっては、サーバーレスよりEC2とRDSを使用したほうが、かなり安い。
- テスト環境、本番環境、リリース手順、切り戻し手順等をどう運用するか事前に
しっかり考えておかないとめんどくさいことになる。
- APIGateway経由で定期的にLambdaを呼び出しておけば、すぐにレスポンス可能だが、
スパイクアクセス時にはスケールしきれず、アクセスの取りこぼしがある。
- APIGateway＋Lambdaの組み合わせは開発やデバッグ、設定等が大変なため、大規模なシステムには今のところ向かない。
- WebAPI(マイクロサービス)として利用するのであればAPIGateway＋Lambdaはかなり良いと思う。

#最後に
ほんとはもっと役立つ記事にしたかったのですが、2年前のことなので、かなり忘れてしまいました。
現時点では変わっていることもいろいろありそうなので、やっぱり記事はすぐに書かないとだめですね。
ciでfeature specを動かす

feature specがciで動作しませんでした。そのため全てがpending状態で不安の中開発をしていました。
そろそろ動くようにしないと自分の精神状態がやばくなりそうだったので修正しました。

### capybaraとselenium-webdriveのupdate

バージョンがかなり古くなっていたため更新しました。

```rb
bundle update selenium-webdrive capybara
```
### dockerのimage
nodeやyarnが入っていると書いてあったので

```
- image: circleci/ruby:2.4.2-node-browsers
```
こちらを設定

### エラーが変わった

初めのエラーはformatがないというエラーだったのですが、今度は

```
session not created: Chrome version must be >= 68.0.3440.0
  (Driver info: chromedriver=2.42.591071 (0b695ff80972cc1a65a5cd643186d2ae582cd4ac),platform=Linux 4.4.0-134-generic x86_64)
```
検索するとよく見るエラーに変わりました。chromedriverが2.42なのでchromeのバージョンは68.0.344以上にしてねということです。
最初見たときはバージョンが66も違うじゃんと思いましたがとんでもない勘違いでした。
http://chromedriver.chromium.org/downloads
chromedriver2.42は Chrome v68-70をサポートしていますということだったんですね。相変わらず愚かです。

### chromeを入れてwebdriver固定
2.42にバージョンを固定しつつ新しいchromeを入れるということにしました。今のところ68以上だったら問題ないはずですがここもバージョンが合わなくなってきたらchromedriverをupdateしたらいいのかな？

```
 run:
     name: webdriver version set
     command: bundle exec chromedriver-update 2.42
 run:
     name: install latest chrome
     command: |
         sudo apt-get update
         sudo apt-get install lsb-release libappindicator3-1
         curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
         sudo dpkg -i google-chrome.deb
         sudo sed -i 's|HERE/chrome"|HERE/chrome" --no-sandbox|g' /opt/google/chrome/google-chrome
         rm google-chrome.deb
```
とりあえずtestを実行したいからこのままで
### あとは微調整
manifest.jsonがないとか, 先にcompileしようとか, FactoryBotの書き方が古かったりとかで色々エラーが出ましたがついに動作するようになりました。
とりあえずpendingを解除するか...
Java11：単一ファイルのJavaコードをそのまま実行

Java 11がリリースされました。

Java 11正式版がリリース、本バージョンからOracle JDKのサポートは有償に。OpenJDKで無償の長期サポート提供は現時点で期待薄
https://www.publickey1.jp/blog/18/java_11oracle_jdkopenjdk.html

その中の「単一ファイルのJavaコードをそのまま実行」

JEP 330: Launch Single-File Source-Code Programs
http://openjdk.java.net/jeps/330

を試してみた。

## インストール

試したのはWindows版。
~~http://openjdk.java.net/~~
~~からリンクたどったんだが、、、Oracle JDKへのリンクを踏んでインストールしてしまった。~~
~~OpenJDK 11はいずこへ（後で探す）。~~

以下からダウンロードできる。
https://jdk.java.net/11

とりあえずインストールして、javaバージョンを確認。
Windowsでjava 8からアップデートしたのだが、
環境変数が変わらずjava 8のままだったので、手動でPATHとJAVA_HOMEのパスをjava11に書き換えた。

```shell
$ java -version
openjdk version "11" 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
```

## 単一ファイルのJavaコードをそのまま実行
で、単一のjavaファイル

test.java

```java
class Test {
    public static void main(String[] arg) {
        System.out.println("Hello World");
    }
}
```

コンパイルせずに実行

```shell
$ java test.java
Hello World
```

実行できた。。

もちろんコンパイルして実行も可

```shell
$ javac test.java
$ ls
Test.class  test.java
$ java Test
Hello World
```

あたりまえだけど、
.classファイル使う場合は最初の中間コンパイルがないので、その分実行が早い。
WITH RECURSIVEの使用

先日、teratailの質問に回答するために一生懸命考えたWITH RECURSIVEを使用したSQL。もったいないので、メモとして残しておきたいと思う。

##仕様
+ お客様TBLと変更情報TBLがある。
+ 変更情報TBLには変更の都度データが作成される。このため、お客様TBLのIDを変更情報TBLの旧IDで検索、ヒットした新しいIDをさらに変更情報TBLの旧IDで検索、、、としていくことで最新の変更情報を辿ることができる。
+ お客様TBLを変更情報TBLの最新の情報で更新したい。
+ 変更情報TBLに存在しないIDは更新しない。

##クエリ
```sql
WITH RECURSIVE OKYAKUSAMA AS ( --お客様TBL
 SELECT '0001' AS ID, 1 AS RENNBANN, '0001001' AS CARDNO
 UNION 
 SELECT '0001' AS ID, 3 AS RENNBANN, '0001001' AS CARDNO
 UNION 
 SELECT '0005' AS ID, 4 AS RENNBANN, '0001010' AS CARDNO
)
, HENNKOU AS ( --変更情報TBL
 SELECT '1001' AS ID, 1 AS RENNBANN, '1001003' AS CARDNO, '1001' AS KYUUID, 2 AS KYUURENNBANN, '1001003' AS KYUUCARDNO, TO_TIMESTAMP('2018/08/20 12:00:00', 'YYYY/MM/DD HH24:MI:SS') AS HENKOUBI
 UNION
 SELECT '1001' AS ID, 2 AS RENNBANN, '1001003' AS CARDNO, '0001' AS KYUUID, 3 AS KYUURENNBANN, '0001001' AS KYUUCARDNO, TO_TIMESTAMP('2018/08/01 11:00:00', 'YYYY/MM/DD HH24:MI:SS') AS HENKOUBI
 UNION
 SELECT '1005' AS ID, 5 AS RENNBANN, '1001005' AS CARDNO, '0005' AS KYUUID, 4 AS KYUURENNBANN, '0001010' AS KYUUCARDNO, TO_TIMESTAMP('2018/08/20 13:00:00', 'YYYY/MM/DD HH24:MI:SS') AS HENKOUBI
)
, TAISYO(ID, RENNBANN, CARDNO, MOTOID, MOTORENNBANN, MOTOCARDNO, DEPTH) AS (
 SELECT CHANGES.ID, CHANGES.RENNBANN, CHANGES.CARDNO, CUSTOMER.ID AS MOTOID, CUSTOMER.RENNBANN AS MOTORENNBANN, CUSTOMER.CARDNO AS MOTOCARDNO, 1 AS DEPTH
 FROM OKYAKUSAMA AS CUSTOMER
 INNER JOIN HENNKOU AS CHANGES
  ON CUSTOMER.ID = CHANGES.KYUUID
  AND CUSTOMER.RENNBANN = CHANGES.KYUURENNBANN
  AND CUSTOMER.CARDNO = CHANGES.KYUUCARDNO
 UNION ALL
 SELECT CHANGES.ID, CHANGES.RENNBANN, CHANGES.CARDNO, TAISYO.MOTOID, TAISYO.MOTORENNBANN, TAISYO.MOTOCARDNO, DEPTH + 1
 FROM HENNKOU AS CHANGES, TAISYO
 WHERE TAISYO.ID = CHANGES.KYUUID
  AND TAISYO.RENNBANN = CHANGES.KYUURENNBANN
  AND TAISYO.CARDNO = CHANGES.KYUUCARDNO
)
SELECT SUB_TAISYO.ID, SUB_TAISYO.RENNBANN, SUB_TAISYO.CARDNO 
FROM OKYAKUSAMA, (
  SELECT SUB.*
  FROM (SELECT TAISYO.*, MAX(TAISYO.DEPTH) OVER(PARTITION BY TAISYO.MOTOID, TAISYO.MOTORENNBANN, TAISYO.MOTOCARDNO) MAX_DEPTH FROM TAISYO) SUB
  WHERE SUB.DEPTH = SUB.MAX_DEPTH
 ) SUB_TAISYO
WHERE OKYAKUSAMA.ID = SUB_TAISYO.MOTOID
 AND OKYAKUSAMA.RENNBANN = SUB_TAISYO.MOTORENNBANN
 AND OKYAKUSAMA.CARDNO = SUB_TAISYO.MOTOCARDNO
```

##説明
TAISYOの部分が**WITH RECURSIVE**の構文を使用している部分です。
まず、**非再帰的表現部分（TAISYOのASの後の最初のSELECT句）**でお客様TBLのキーと変更情報TBLの旧キーが同じデータを抽出しています。ここで、お客様情報のキーを元キー(MOTOID, MOTORENNBANN, MOTOCARDNO)として保持しています。さらに、深さを表す**DEPTH**を**1**として定義しています。
**再帰的表現部分（UNION ALLの後の最初のSELECT句）**では、非再帰的表現部分で取得できた結果の変更情報TBLのキーが変更情報TBLの旧キーと同じデータを抽出しており、これを繰り返します。**繰り返すたびDEPTHは加算**されます。
その結果は以下のようになります。

```
ID;RENNBANN;CARDNO;MOTOID;MOTORENNBANN;MOTOCARDNO;DEPTH
"1001";2;"1001003";"0001";3;"0001001";1
"1001";1;"1001003";"0001";3;"0001001";2
"1005";5;"1001005";"0005";4;"0001010";1
```

WITH以降のSELECT句でこの結果からお客様TBLのキーと元キーが同じ、かつ、深さが最大のデータを取得すると更新対象（MOTOIDが0001と0005）とその更新値（**最新の変更情報**）が取得できます。

##最後に
WITH RECURSIVEを使用する場面は多くはなさそうですが、知っていると複雑なクエリを容易に組むことができるかもです。

以下、参考サイト
https://www.postgresql.jp/document/9.5/html/queries-with.html
motionにuvc対応を入れてみた

webcamでの動体認識には以下のオープンソースがあります

* [motion](https://motion-project.github.io) - Cで書かれた軽量なコード。V4Lなどのデバイスが使えます。

* [ZoneMinder](https://zoneminder.com) - 超巨大な実装。onvifというperlのライブラリを使っている。

* OpenCV - 画像処理用のライブラリで、動体認識もできます。

motionをちょっと見てみることにしました。

FreeBSDのportsをビルドしようとしたらエラーになったのでgithubにあった[ソース](https://github.com/Motion-Project/motion)をforkしてcloneしてビルドを試しました。

githubのソースにはconfigureがないので、autoheader/autoconfして作ります。configure.acのpkg-configの記述がエラーになるので、これはコメントアウトしました。

libmicrohttpdとjpegのpkgがあれば以下のようにconfigureしてgmakeでビルドできます。

% ./configure --without-ffmpeg --without-sqlite3

motionはなんとbktrもサポートしていてBSDな開発者もいたようです。bktrは自分がいじった最初のFreeBSDのコードでした。BT878のボードはまだ持っていて、Hammerなマシンに入ってます。

FreeBSDではV4L互換のwebcamdを使って利用できるようなのですが、webcamdが依存がひどくていけてなかったので、なにか他に良い方法がないか考えてみました。

いろいろ探していたらたまたまSAITOU Toshihideさんが書かれたUVCのコードをMLで見つけて、これをがっちゃんこすることにしました。

当初、キャプチャ初めて1フレームとって止めての実装にしていたのですが、あまり効率が良くないので、pthreadで連続してキャプチャーして、フレームが必要な時だけメモリに落とすようにしました。

UVCから送られてくるデータはYUVという1ピクセル16ビットのデータでmotionに変換コードがすでにあったので、それを使って変換しています。

とりあえず動くようになったのでPullReqしたら中の人にlibuvcがいいなみたいな事いわれてます。:(

https://github.com/Motion-Project/motion/pull/804

usbがrootでしかアクセスできない場合はsudoで起動します。

% sudo ./motion -c motion-dist.conf

使い方はmotion-dist.confのwebcontrol_localhostとstream_localhostをoffにするとネットワーク越しに確認できるようになります。ブラウザで8080にアクセスすると以下のような表示になります。

![スクリーンショット 2018-09-26 13.09.28.png](https://qiita-image-store.s3.amazonaws.com/0/104066/85d14f01-a1a5-42b0-23f0-8e1227a3b93c.png)

動くものが入るとコマンドラインに以下のログがでます。

```
[1:Unknown] [NTC] [ALL] motion_detected: Motion detected - starting event 1
[1:Unknown] [NTC] [ALL] mlp_actions: End of event 1
```

confのevent_gapで認識からEndまでの間隔が指定できます。またpicture_outputをonにすると認識中の画像をjpegで保存できます。on_event_startにshスクリプトを指定すると認識開始時に実行されます。

FreeBSD/mipsで動かしたいのですがusbがちょっと辛そうです。。。

ちなみに1フレームが640x480x2で614400バイトで1フレーム/Secでも1msのパケットに614バイトになります。結構大きいです。

FreeBSD/amd64のmotionのpkgは変なコンフィグレーションで依存がたくさん発生してます。よかれと思ってやってるんでしょうが、いけてません。

Linuxでもlibusbが入っていれば使えると思うので、uvc_device_listのwebcamを持っていて、configureを--without-v4lでビルドすれば試せると思います。と思ったんですが、Ubuntuで落ちるみたいです。誰かデバッグしてください。

中の人に複数カメラ対応してくださいと言われたので、bktrのコードなどを参考にいじってみました。cameraディレクティブでconfを分けると複数のカメラが使えるみたいなので、誰か試してくれませんか？
prettierのインデント幅の設定

prettierのインデント幅がデフォルトの「2」のままでWebstromの設定などが反映されずちょっとハマったのでメモ。

[prettierの公式ページ](https://prettier.io/docs/en/configuration.html)に設定ファイルの記述があったので、ここに書いてある通りにプロジェクト内に「prettier.config.js」というjsファイルを作成して以下の設定をして解決した（ファイルの置き場所はwebpackプロジェクト配下なら特にどこでも大丈夫っぽい）。

```javascript
module.exports = {
    tabWidth: 4
};
```

これ以外の設定項目については同じく公式ページの[こちら](https://prettier.io/docs/en/options.html)を参照。