OmniAICreator/Qiita-1.07M huggingface dataset:
プログラマ脳を鍛える数学パズル Q.6「（改造版）コラッツの予想」

引き続き問題を解いていきます。
問題は[プログラマ脳を鍛える数学パズル](https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E8%84%B3%E3%82%92%E9%8D%9B%E3%81%88%E3%82%8B%E6%95%B0%E5%AD%A6%E3%83%91%E3%82%BA%E3%83%AB-%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%A7%E9%AB%98%E9%80%9F%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%8C%E6%9B%B8%E3%81%91%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%AA%E3%82%8B70%E5%95%8F-%E5%A2%97%E4%BA%95-%E6%95%8F%E5%85%8B/dp/479814245X/ref=asap_bc?ie=UTF8)より。
# 今回の問題

>数学の未解決問題の1つに「コラッツの予想」があります。
**コラッツの予想**
>>自然数nについて
・nが偶数の場合、nを2で割る
・nが奇数の場合、nに3をかけて1を足す
という操作を繰り返すとき、初期値がどんな数があっても必ず1に到達する（1→4→2→1のように繰り返す）

>この予想の内容を少し変えて、初期値が偶数の場合、初回のみnに3をかけて1を足すことから始めることとし、「最初の数」に戻るものを考えます。
例えば、2で始めた場合は以下のようになります。
2→7→22→11→（中略）→2
同様に、4で始めると以下のようになります。
4→13→（中略）→4
しかし、6で始めると
6→（中略）→
となり、6に戻ってくることはありません。
**問題**
10000以下の偶数のうち、上記の2や4のような「最初の数に戻る数」がいくつあるか、その個数を求めてください。

# 実装手順
①2から10000までの偶数をループさせて初期値（最初の数）を設定する
②初期値に3をかけて1を足す
③上記で設定した値が初期値に戻るか、1になるまでループさせる
④上記のループ文の中で値が偶数、奇数の場合で処理を分ける
⑤値が初期値と一致した回数を数える
⑥出力する

# 書いたPHPコードと出力結果
```php:q06.php
<?php

// 問題の条件を満たす数字をカウントする変数
$count = 0;

// ①2から10000までの偶数をループさせて初期値を設定する
for ($initial_number = 2; $initial_number <= 10000; $initial_number += 2) {
  // ②初期値に3をかけて1を足す処理
  $original = $initial_number*3+1;
  // ③$originalが初期値に戻るか、1になるかするまでループさせる
  while ($original !== $initial_number && $original !== 1) {
    // ④偶数、奇数の場合で処理を分ける
    if ($original%2 === 0) {
      $original = $original/2;
    } else {
      $original = $original*3+1;
    }

    // ⑤$originalが$initial_numberと一致すれば$countに1を足す
    if ($original === $initial_number) {
      $count = $count + 1;
    }
  }
}

// ⑥結果を出力する
echo $count;

// 結果
34
```
# 今回の学び
・ループ文の使い分け。今まではforeach80%、for20%のくらいの割合で使用していたがwhileが使いやすい場面もある。
・for文の第3引数の設定で、どのくらいの間隔でループ処理するか柔軟に変えられる。
途中でreturnがどうこうとか宣言を先頭でするとか(C#)

[元の記事](https://qiita.com/gengogo5/items/5b038cf0b4034194f63a)はJavaなのでコメントに書くべきではないと思って記事として分けました。

# 必ずメソッドの最後でreturnすることの是非

個人的な意見ですが、僕も必ずメソッドの最後でreturnしようとするのはあまりよろしくないと思います。
言語は違いますが(これはJavaがどうこうって話じゃないと思うので)、例えば

```csharp:Leapyear.cs
public static bool IsLeapYearLast(int year)
{
    bool result = true;

    result &= year % 4 == 0; //4で割り切れる
    result &= year % 100 != 0; //100で割り切れない
    result |= year % 400 == 0; //400で割り切れたら100で割り切れてもよし

    return result;
}

public static bool IsLeapYear(int year)
{
    if (year % 400 == 0) return true; //400で割り切れたら確定
    return year % 4 == 0 && year % 100 != 0; //400で割り切れないので、4で割り切れるかつ100で割り切れない
}
```

というメソッドがあったときに、これらに対しては

* 記事主さんが

> どこでretが書き換えられているかわからない為、読み手はretの状態を記憶したまま、最後のreturnまで読み進めなければいけない。

と言っているように(今回はresultですが)、読み手には優しくないと思います。
```IsLeapYearLast```でif文使ってないのは```bool```で判定して```bool```の```result```に```false```だの```true```だの入れるのは冗長だからです。

* メソッドを最後まで通さなきゃいけないような共通の処理があるなら呼び出し元でやれ
* 変数のスコープは短いほうがいじる期間が短いのでバグが混入しづらくてよい(これは後述の項にもつながる)
 * 見方を変えれば```result```は**関数内でグローバル**とも取れるので、明らかにバグの混入率で言えば……

という僕の**個人的な**見解があります。

# 変数宣言は先頭でする

太古(規格の年代的に)のCの時代は、先頭で変数宣言しないといけなかったのでそれはしょうがないですが、今は現代です。

コメントで触れられている、「後から追加した変数名が被る」「同じ変数名でも役割が～」というのは記事にある

> 説明不足な変数名をつける

の項にもある通りその**変数の役割を表せていない**のが問題なので、そもそもの話被るような変数名が悪いとしか言えません。
現代のIDEには補完機能というものがあります。
メソッドの変数全てを記憶できる人間であれば全ての変数を覚えてからコードレビューができるので問題はありませんし、最初に全部書いてあった方が見やすいというのはわかります。
ただ、

```csharp:GetPerson.cs
public static Person GetPersonFirst(long countryId, long regionId, long personId)
{
    Country country = null;
    Region region = null;
    Person person = null;

    //数行の処理

    country = GetCountry(countryId);
    country.OnSelect();
    region = country.GetRegion(regionId);
    region.OnSelect();
    person = region.getPerson(personId);
    person.OnSelect();

    return person;
}
```

よりかは

```csharp:GetPerson.cs
public static Person GetPerson(long countryId, long regionId, long personId)
{
    //数行の処理

    Country country = GetCountry(countryId);
    country.OnSelect();
    Region region = country.GetRegion(regionId);
    region.OnSelect();
    Person person = region.getPerson(personId);
    person.OnSelect();

    return person;
}
```

とかの方が見やすいですかね。左辺の型情報も必要な時にコードに出現するので。
(~~言語は関係ないのでvarで書けとかC#だと先頭でvar(型推論)使う時にnull代入するとエラーになるとかの見解を挟んではいけない~~)
※数箇所Countryがcontryになってたのを直しました

# 6:12追記

スコープは短いほどいいと言いましたが、例外もあります。
例えば、ConsoleクラスのWriteLineメソッドはstaticでグローバルなメソッドです。
これを無理にスコープというか、アクセスできる範囲を狭めようとすると、プロパティ経由で

```csharp:ConsoleOut.cs
Console.Out.WriteLine();
```

とか書くことになってしまいます。物事には例外というものがあります。
010-Form Submitの違いを理解する

# 結論
## Googleフォームから実行するべき場合とは
- フォーム送信結果をスプレッドシートに __書き出す前に__ 実行したいことがある場合
- 編集用URLを「簡単に」[^6]取得したい場合
- フォーム送信結果をスプレッドシートにリンクさせない場合

[^6]: 取得自体はスプレッドシート側で実行しても簡単です。実行メソッド増やしたくないとかそんな理由（詳細は後述）

## Googleスプレッドシートから実行するべき場合とは
- フォーム送信結果をスプレッドシートに __書き出した後に__ 実行したいことがある場合
- フォーム送信結果を１次元配列で取得したい場合
- フォーム送信結果が挿入された範囲（range）を取得したい場合[^2]

[^2]: 3つ挙げたいがために書きましたが私自身この機能を利用したことはなく、使い道が思いつきません…

# つぶやき
「Googleフォームで送信された内容をGoogle Apps Scriptで遊んでみましょう」というのは、GAS学習でよく見かける最初の一歩です。
GAS紹介サイトなどでも初期からよく取り上げられており、私も以前[フォーム送信時にメールを送信するスクリプト](https://qiita.com/co-ikeya/items/5cdcab6f6491bbe1cd04 "006-初めてのGoogleAppsScriptで何をしたら良いか分からない")について紹介しました。

さてこの「Form Submit」、元々はGoogle スプレッドシートのお家芸でしたが、新しいGoogle フォームがリリースされてからは[Google フォームからでも実行できる](https://developers.google.com/apps-script/guides/triggers/events#google_forms_events "Google Forms events | Event Objects | Apps Script | Google Developers")ことは皆様ご存知のとおり[^1]。

[^1]: Sound Trickerさんが[記事にされてました](https://qiita.com/soundTricker/items/42266e56c0212ce6b997 "I/O 2013のGoogle Apps Script Update その1 Form上のGASとFormApp - Qiita")。

これにより「フォーム側で用意したスクリプト」を使っても同じようなことができるようになったのですが、フォーム入力データを取り出す際のデータの取り出し方が違うため、うっかりしてると[ドツボにはまる](https://qiita.com/mildtech/items/293620c32b88bd7b5eb5 "GASのonFormSubmit()でハマったこと - Qiita")ことになります。私も最初はまりました。

## 「はまり箇所を避ければどっちを使っても良いんじゃない？」
私もそんな風に思っていた時期がありました。
「Scriptを作る際は、以前作成して（動作実績が）あるものをコピーするから気にしたことないよ」と。

でも実際は微妙に動作が違うんですね。
今回はそんなお話です。

# 動作の違いを知っておくべきシチュエーション
## 昔スプレッドシート用に作成したスクリプトをフォーム用に使い回す
「同じForm Submit だから大丈夫だよね」みたいに考えていると値の取り出し方ではまります。
単純に配列指定すれば取り出せるスプレッドシート側トリガーの方が個人的には好きです。
なのですが・・・

## フォーム編集用URLをスプレッドシートに書き出す
私はこれをやろうと思った時にはまりました。

Form Submitをスプレッドシート側から実行した場合、イベントオブジェクト `e` に編集用URLデータはありません。

そのため[getEditReponseUrl()](https://developers.google.com/apps-script/reference/forms/form-response#getEditResponseUrl() "Class FormResponse| Apps Script | Google Developers")を実行するためには
1.  `FormApp.openById(fid).getResponses()` を用いて送信結果をFormResponse[]形式でまるっと取得し
2. 配列の中から対象のデータを捜索し[^3]
3. `getEditResponseUrl()` を実行する

という手順を踏まねばならず「実行メソッド増やすと処理時間が長くなるからイヤ！」という思いもあり[^4]、なんだか面倒くさいなぁと思っていたのです。

[^3]: `getResponses()` で返されるデータは送信時刻の昇順となるためトリガー対象となるデータを引っ張るだけなら配列のlength-1を指定してあげればよく、実はそこまで面倒ではなかったりします。

[^4]: 実際はこの程度であれば実行速度に影響を与えるとは思えないため、もう宗教上の理由みたいになっていますが。

## 編集用URLを「そのデータがスプレッドシート側に書き出された行」に追記する
個人的どハマりポイントその2。

「フォーム編集用URLを取り出すだけならスプレッドシート側のトリガーとして実行する必要ないよね」という発想でフォーム側トリガーを用いてスクリプトを書き始めた、というのが今回（＆次回）のエントリーを投稿しようと思ったきっかけなのですが。

### 1. 実行タイミングにどハマる

スプレッドシート側で設定したForm Submitトリガーは「フォーム送信結果が、リンクされたスプレッドシート側に書き出された __後に__ スクリプトが実行」されます。
そのため手順としては

1. トリガーが実行されたら
2. 編集用URLを取得して
3. シートの最終行のどこかに追記する

で良いのですが、フォーム側でトリガーを実行してしまうと「リンクされたスプレッドシート側に書き出される __前に__スクリプトが実行」されてしまうため

1. トリガーが実行されたら
2. 編集用URLを取得して
3. シートの最終行＝ __一つ前の（新規で送信された）フォーム入力結果を記載した行__のどこかに追記する


となってしまい、おかしなことになってしまいます。

### 2.トリガー条件にどハマる

加えて。

フォーム側で設定されたForm Submitトリガーは

- 「新規で送信された場合」

だけでなく

- 「送信済み結果を編集し、再送信した場合」

も実行されるため、実行トリガーが後者の場合は実行キャンセルが必要になります。

どちらが良いとか悪いという話ではないのですが、うまく使い分けしたいですね。
Excelの薄い本(1)

# ActiveSheet のテーブル名を見つける

テーブルは、ListObject なので、以下の関数で変数Tにテーブル名が入ります。

```vb
   Dim L As ListObject: Set L = ActiveSheet.ListObjects(1)
   Dim T:  T = L.Name
```
テーブルに、"月日"という項目があった場合、Range(T　& "[月日]")で指定できます。
# 構造化参照とRangeの関係について

という事は、Range関数に、構造化参照の文字列を入れるとテーブル内の列を指定して参照できます。
これを利用すると、複数のテーブル参照をキーワードで切り替えることが可能になります。

例として、ロット番号（年－機械ー連番）の機械番号で参照するテーブルを切り替える関数を定義します。 
関数TMIはMI、関数TDIはDIの拡張です。

```vb
Function TMI(R, Optional S = "")
    On Error Resume Next   

    Dim M: M = MM(R)
    Dim K: K = DI(R, M, 2)  ' 機械番号

    If K = 1 Then
        S = CC(MLOT(Range("T01N_"), R), "A")
    ElseIf K = 2 Then
        S = CC(MLOT(Range("T02N_"), R), "B")
    End If
    TMI = S
End Function

Function TDI(A, T, Optional S = "")
    On Error Resume Next

    Dim I: I = Right(A, 1)
    Dim J: J = Val(A)
    
    If I = "A" Then S = DI(Range("T01N_[" & T & "]"), J)
    If I = "B" Then S = DI(Range("T02N_[" & T & "]"), J)
    
    TDI = S
End Function
```

説明があまりにも端折りすぎで判りにくいですね。
ここにない関数は、[基礎編](https://qiita.com/matumoto_onga/items/7adfd4cf48288c477901)、[応用編](https://qiita.com/matumoto_onga/items/a39d701e7f1395499cea)で。
Vagrant環境におけるfirebase認証(9005番フォワーディングではなく認証コード→トークンにて)

firebaseでは、プロジェクト作成後、CLIでやる場合は「firebase login」としてその後ブラウザアクセスで認証を行うのだが、認証がうまく行かなかったときのメモ。

#環境
MacにてVagrant

```
# cat /etc/redhat-release 
CentOS release 6.9 (Final)
# node --version
v8.11.1
# npm --version
5.6.0
# firebase --version
3.18.4
```
#失敗例
```
# firebase login
? Allow Firebase to collect anonymous CLI usage and error reporting information
? Yes

Visit this URL on any device to log in:
https://accounts.google.com/o/oauth2/auth?client_id=5635(以下略)

Waiting for authentication...
```
ここで指定のURLにアクセスすると認証が行われるはずだが、vagrantの裏にいるので無理だった。

![スクリーンショット 2018-04-29 3.05.09.png](https://qiita-image-store.s3.amazonaws.com/0/37393/b1720a4b-f910-e244-79c5-d211a2cb1704.png)

[vagrant + firebase loginでブラウザ認証が失敗する場合の解決方法](https://qiita.com/nishiurahiroki/items/3d42883d2dcaff07b536)

上の記事のように、9005番をフォワードすれば行けるらしいが、別の方法でやった。

#成功例
```
# firebase login:ci --no-localhost

Visit this URL on any device to log in:
https://accounts.google.com/o/oauth2/auth?client_id=5635(以下略)

? Paste authorization code here:
```

![スクリーンショット 2018-04-29 3.06.58.png](https://qiita-image-store.s3.amazonaws.com/0/37393/6ed040d6-86a8-ba94-77f2-7f6c6789591c.png)

アクセスすると上記のように認証のコードが出て、それを入れると成功。トークンでアクセスするようになるらしい。こっちのほうがポートより管理しやすくて好みですね。

```
✔  Success! Use this token to login on a CI server:

1/G(中略)mZYQKrQ

Example: firebase deploy --token "$FIREBASE_TOKEN"
```
【Swift】メモリー対策！使ったタイマーは必ずinvalidate()

# タイマーのメモリ解放を試みる
利用する機会も多いと思われるタイマーですが、こちらのメモリ解放が適切にできていないと処理がかなり重くなったり予期せぬエラー（EXC_BAD_ACCESS）などにハマる可能性があります。僕自身もタイマーが適切に扱えていないがためにそういったことにハマった事があったので簡単な例を用いて説明します。
(※以下のコードはSwift3で検証していますが，Swift4,5でも同様です)

## タイマーを停止する

```swift:NextViewController.swift
timer.invalidate()
```

たかが一行、されど一行。タイマーを停止するときに使うのはinvalidate()ですよね。
実はinvalidate()はタイマーを停止すると同時に使用していたタイマーを破棄しています。（timer=nilをしているイメージ）
タイマーの停止処理というよりかはタイマーの破棄のために使用すると考えるとメモリ解放につながるのも頷けます。

## 悪い例

```swift:NextViewController.swift
override func viewDidLoad() {
    super.viewDidLoad()

    // 0.5秒ごとにstartTimer()を呼ぶタイマー
    var timer: Timer!
    timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(self.startTimer), userInfo: nil, repeats: true)
}

/// 経過時間をカウントして表示
/// 0.5秒ごとに呼び出される
@objc func startTimer() {
    count+=1
    label.text = String(count)
}
```

タイマーをscheduledTimerで呼び出す際にrepeatsの引数をtrueと設定すると、停止処理がない限りタイマーはループし続けてしまいます。そうすると上記の例では、NextViewControllerを閉じようとしてもタイマーは動き続けているため、NextViewControllerのメモリは解放されません。

## 解決策

解決策としてはどこかにタイマーの停止処理を入れる必要があります。
タイマーが使用し終わった後に挿入するのもいいのですが、同じクラス内で複数のタイマーを用いていたり、タイマーの用途が様々であったりするとどのタイミングでタイマーを停止するのか判断が難しいことがあります。
個人的なオススメは**classを破棄する直前**に入れることです。
これだと、classを破棄するタイミングで使用したタイマーを停止、破棄すればよく、統一感があり後々デバッグをするときなんかは楽です。

```swift:NextViewController.swift
/// 画面が閉じる直前に呼ばれる
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
        
    // タイマーを停止する
    if let workingTimer = timer{
        workingTimer.invalidate()
    }
}
```

## 確認方法

viewControllerが適切に破棄されているか判断するにはdeinit()を利用します。
deinitが呼び出されていれば、適切にメモリ解放が行われているということになります。

```swift:NextViewController.swift
/// クラスのインスタンスが破棄されたときに呼ばれる
/// この部分が呼ばれていないとメモリ解放が適切に行われていない可能性が高い
deinit {
    print("NextViewControllerがdeinitされました")
}
```

print文がコンソールで確認できたらメモリ解放完了です。

## まとめ
タイマーをinvalidate()するか否かだけでアプリの安定性は格段に上がるので、常にセットで考えるように心がけるといいと思います。

全体のコードはGitHubにあげてあります。
https://github.com/shu26/zombie
Java staticメソッドと非staticメソッドについて


Javaを触ることになったので、忘れないようにメモ(間違いがありましたら、コメントいただけると嬉しいです)
staticメソッドと非staticメソッドについて良く分かっていない方は、参考程度に・・・

そもそも初心者の方は、おまじないのようにメソッドにstaticをつけてませんか？
私は、意味もわからずとりあえず書いていました！笑
まずは以下の２つのコードを見てください。
#・staticメソッドと非staticメソッド
##１.staticメソッド 


```Java:A.java
class A {
    public static void main(String[] args){
        calc(); //calcメソッドの呼び出し
    }
    
    static void calc(){ //calcはstaticなメソッド
        //計算処理
    }
}
```



##２.非staticメソッド


```Java:A.java
class A {
    public static void main(String[] args){
        calc(); //calcメソッドの呼び出し
    }
    
    void calc(){ //calcは非staticなメソッド
        //計算処理
    }
}
```
どちらのプログラムも、mainメソッドからcalcメソッドの呼び出しを行おうとしています。
しかし、間違ったstaticの使い方をしたプログラムでは、コンパイルの際に
「staticでないメソッドをstaticコンテキストから参照することはできません」
というエラーが出てしまいます。

どうしてこのようなエラーが出てしまうのかというと
**<font color="Red">staticなメソッド(main)から同一クラス(A)内の非staticなメソッド(calc)への直接なアクセスはできない</font>**
ことになっているからです。

では、どうすれば同一クラス内のメソッドを呼ぶことができるかについて説明します。

#・メソッドの呼び出し方法
クラス内のメソッドの呼び出し方法は、主に２つあります。
##１.メソッドにstaticをつけて実行する(staticメソッド)
これは、上で記述した【１.staticメソッド】の通りです。
メソッドにstaticを付けると、クラス内で共用なメソッドになるため、他のメソッドからアクセスが可能になります。

##２.クラスのインスタンスを生成し、インスタンスを通して実行する(非staticメソッド)
言葉だと理解が難しいので、コードでも示します。

```Java:A.java
class A {
    public static void main(String[] args){
        A a = new A(); //aというインスタンスを生成
        a.calc(); //インスタンスaのcalcメソッドの呼び出し
    }
    
    void calc(){ //calcは非staticなメソッド
        //計算処理
    }
}
```
staticなメソッドから同一クラス内の非staticなメソッドへアクセスはできないのではないか？と思った人がいるかもしれません。
この方法は、Aクラスのインスタンスaをmainメソッド内で生成することで、**インスタンスaを通して**calcメソッドを呼び出しています。
そのため、直接アクセスしているわけではなく、**間接的**にアクセスしているため呼び出しが可能になるのです。

#・終わりに
staticメソッドと非staticメソッドについてなんとなくでも分かってもらえたら光栄です。
おそらくJava初心者に対して、メソッドを書く際にstaticを書かせる理由は、mainメソッドから呼び出した時にエラーになるのを防ぐためでしょうね！笑
staticは変数に付けることもあります。static変数に関する記事は、次回書こうと思います。

最後までお読み頂きありがとうございました。なつ。
docker(docker for windows)でMattermost構築した。

 windows10だとdocker導入がらくちんでした。
 Dockerさえ導入できれば、コンテナ起動するだけなので、現環境を汚すことなく導入できます。

 備忘録的なメモ書きとして書き残しときます。

### docekr のインストール(windows10)
windows10の場合は、dockerの導入がとても簡単です。
[docker for windows](https://www.docker.com/docker-windows)
上記リンクからダウンロードしてインストールで完了です。

##### シンボリックリンク作成

* イメージのディスクが` C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks`に
作成されます。私は、SSDが圧迫されるのが嫌な人なのでシンボリックリンクで別ドライブに移動。
* 管理者CMDで下記実行
    * 実際のフォルダをリンク先に移動してシンボリックリンク作成。

```
move "C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks" "F:\Virtual Hard Disks"
c:\> mklink "C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks" "F:\Virtual Hard Disks"
```

##### windows10 以外も一応

* linux(ubuntu)
    * [ここ](http://inaz2.hatenablog.com/entry/2014/10/09/002750) に載ってます、ubuntuだと簡単です。centOS知りません。
    
* [windows 7,8　（docker toolbox）](https://docs.docker.com/toolbox/toolbox_install_windows/)
    * プロキシとか使ってたらめんどくさいです。
    * docker-machine内の`/var/lib/boot2docker/profile`でproxyエクスポート必須　[参考: github issues](https://github.com/docker/toolbox/issues/102)
    * virtualboxでポートフォワードして、ローカル環境からlocalhostで接続できるようにすると他のdockerのようにつかえます。

* [windows server2016](https://store.docker.com/editions/enterprise/docker-ee-server-windows?tab=description)

### mattermostコンテナ起動
びっくりするほど楽です。下記コマンド実行で終わりです。
 
```
docker run --name mattermost-preview -d --publish 8065:8065 mattermost/mattermost-preview
```

* `http://localhost:8065/`にアクセスするとログイン画面が開きます。
    * [クライアントツールはこっち](https://about.mattermost.com/download/)
    * server起動時は`docker start コンテナID`　
        * コンテナ起動時にalwaysオプション付けとく方がいいのかなぁ
    
[mattermost docekrコンテナドキュメント](https://docs.mattermost.com/install/docker-local-machine.html#one-line-docker-install)

たぶん他のOSもドキュメント通りに実行していくだけでコンテナ起動してアクセスできると思います。
すんなりいけてびっくりです。

###　ユーザー招待

* ユーザ追加をするには、管理者がURLを送ります
* 自分のアカウントの三本バーガーのをクリックし、メニューを開きます。
* メニューが開いたら、下記画像の`Get Team Invite Link`をクリックで招待URLをみることができます。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/186510/4ffb036b-b04f-797f-23c4-6a972041aacd.png)



* 取得したURLを招待したい人に送りることで招待できます。

### mattermostの初期設定値
* mattermostの初期設定地は[こちら](http://sig9.hatenablog.com/entry/2017/10/19/000000)



##### 追記(備忘録)
* プロキシ環境下だったら、ローカルプロキシたてると楽です。
* proxomitron使ってローカルプロキシの設定
    * ![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/186510/aa2f54fb-30bb-9f10-0e7f-9ad855d1d458.png)
    * 画像の`proxyURL:8080`部分を右クリックで`Advance Proxy Setting`を開く
    * パスワードを記述して設定完了
hubot デーモン化に使った forever を systemd でOSが再起動しても forever できるようにした

[この前の記事](https://qiita.com/fruitriin/items/078b2795776ec53cefb0)で、hubotでslack botを作りました。

Host OSを再起動すると当然立ち上がってこないので、
今のうちに設定しておきたいなーと思った次第。

作っててスクリプトの更新をするためにはbotを再起動しないといけないわけで、何かいい方法はないかなーと思ったらスクリプトはgit管理、slackからメッセージを受け取って再起動するっていう仕組み作ったよ、 forever っていうツールとセットで使ってねっていうdistを見つけました。
[Hubotの自動更新用スクリプト。 foreverの自動起動機能を利用して利用する想定。 $ /path/to/hubot/bin/bot start](https://gist.github.com/kkurahar/7171350)


[2018 6/6追記]
ちなみにこの記事を公開いたあと、
「デーモン化したいだけならsystemdでできるよ」と教えていただいたので
[hubotをデーモン化するだけならsystemdだけでよかった \- Qiita](https://qiita.com/fruitriin/items/22f4075e2c9cf100d385)
という記事を公開しました。



## hubotをforeverから起動する
それではまず、forever を使って hubot がデーモンとして起動できることを確認します。
foreverがまだインストールされていなければ、 `sudo npm install -g forever` でインストールしましょう。


```
# hubotのディレクトリに移動しておくこと
forever start -c sh bin/hubot -a slack # 起動
forever list # forever がデーモン化しているプロセスの一覧を確認
forever stop bin/hubot # デーモン化を止める
forever list # そして誰もいなくなった 
```

ちなみに forever の -c オプションは起動する実行ファイルを指定するもので、省略すると nodeを使って起動することになります。
Alexaスキルのテスト方法

# 本記事について
Amazon Developerの開発者コンソールがしばらく前に新しくなりました。それに伴い、開発時に行うテストのための設定方法や実施方法が変わっていますので、ここにメモしておきます。
＃[公式マニュアル（日本語版）のベータテストのページ](https://developer.amazon.com/ja/docs/custom-skills/skills-beta-testing-for-alexa-skills.html)は、4/29時点でまだ修正されておらず、特にベータテストの設定で迷子になりました。よくよく見ると、ページの構造自体は変わっていないのでもっと早く見つけられても良かったはず・・・。

# Alexaスキルのテスト方法について
恐らく、以下のような流れが一般的ではないか、と勝手に思っているため、その順で説明します。

1. Lambdaファンクション内の単体テスト
    - ファンクション内の関数などを対象にした単体テスト。
2. Alexaスキル-Lambdaファンクションの結合テスト
    - Alexaシミュレータを利用したテスト。
    - IntentやSlotとの関連付けが正常に行われているかどうかや、Alexaスキルの発話を確認。
3. Amazon Echo実機テスト（ベータテスト）
    - Amazon Echoを紐づけているアカウントを限定して公開し、実機でテスト。
    - 音声認識の精度や、ビルトインIntentの動作などを確認。

# 1. Lambdaファンクション内の単体テスト

適切にモジュール化し、Alexaスキルからの呼び出しに依存しない部分はこの段階でテストしましょう。実施方法については、特筆することはなく、各種のランタイムで一般的に実施されている方法で問題ないと思います。


# 2. Alexaスキル-Lambdaファンクションの結合テスト

開発者コンソールのテストのタブにて、Alexaスキルのシミュレータが利用できますので、こちらを活用し、Alexaスキル-Lambdaファンクションの連携についてテストしましょう。

以下が、テストタブを利用してテストを実施した画面です。

![シミュレータ利用_01.png](https://qiita-image-store.s3.amazonaws.com/0/179480/88387933-9b40-5cf4-0c83-4a793d72cc6d.png)

**①に利用者の想定発話を入力することでテストを実施**できます。上手くLambdaファンクションと連携ができていれば、文章の発音なども①の下部、および**②にAlexaスキルの応答発話が記載**されます。シミュレータでは実機のEchoがありませんが、**応答部分の音声が出力されますので、意図通りの発話（発音やSSMLの設定など）を確認することが可能**です。

**Lambdaファンクションへ渡される入力JSONは③の部分に出力**されており、準備したIntentや、その内部構造も確認することが可能です。入力を受けた**Lambdaファンクションからの応答が④に記載**されますので、想定どおりの動作ができているか確認を行いましょう。

上手く動作しておらず、上記の情報で原因を特定できない場合は、Lambdaファンクションの実行ログ（CloudWatch Logs）を確認しましょう。

画面付きのデバイスを利用するスキルの場合は、さらに下部の「Echo Showの画面」に表示されるはず・・ですが利用したことがありませんので、説明は割愛。

# 3. Amazon Echo実機テスト（ベータテスト）
自己所有しているEchoやテストに協力していただける方のEchoにて開発中のスキルを有効化し、実機テストを行います。前提として、**公開申請ができる状態までスキルの設定が完了していることが必要**です。
＃旧コンソールからしか有効化したことがなく、テストタブの方ばかり見に行ってしまって、かなり迷いました。

以下が設定の画面です。

![実機_01.jpg](https://qiita-image-store.s3.amazonaws.com/0/179480/112c2082-1dfc-c97d-96b1-76690aa242c4.jpeg)

公開タブ　⇒　公開範囲　⇒　ベータテスト　を選択します。

![βテスト.JPG](https://qiita-image-store.s3.amazonaws.com/0/179480/aec25ed9-a623-e4e7-be79-03009b0e7c03.jpeg)

ベータテストに利用するAmazon Echoを関連付けているアカウントのメールアドレスを追加し、「ベータテストを有効化」すると、スキルをベータテスターに限定して公開することができます。メールアドレス宛に、以下のような参加依頼メールが送付されます。自己所有の1台でのみテストを行う場合は、「ベータテスト管理者用Eメールアドレス」と「テスターのEメールアドレス」は同一のものでもOKです。

![WS000133.JPG](https://qiita-image-store.s3.amazonaws.com/0/179480/770e7722-96dd-b5dd-ba4a-2891bb8617bd.jpeg)

日本語環境（amazon.co.jp）へAmazon Echoを関連付けている場合は、赤い矢印のURLから承認すれば、インストールされます。現時点でのベータテスト期間は最長90日間で、それをすぎると自動で停止されます。（スキルのオーナー、ベータテスターにメールで以下のような通知が送られます。）

![WS000132.JPG](https://qiita-image-store.s3.amazonaws.com/0/179480/6b672c59-4271-9509-9ccb-b17802384548.jpeg)


一度設定した後は、スキル一覧のアクションに「ベータテストの管理」の項目ができますので、こちらからも設定を変更可能です。ベータテストの状態を有効化した状態では、ステータスが「開発中」のスキルが動作する状態となっており、公開中のバージョンは動作していないはず・・・です。
![スキル一覧.JPG](https://qiita-image-store.s3.amazonaws.com/0/179480/96635000-006c-fb88-9b9d-a7324c495d09.jpeg)


#おわりに
開発環境もどんどん進化しており、本記事もすぐに陳腐化（というかマニュアルが更新？）されるかもしれませんので、最新の情報は随時ご確認ください。
ATOMでコーディング環境を構築する(mac)

# 前置き
ギジュツリョク向上のために、まずは開発環境の構築をしよう。
とりあえず、快適なコーディング環境を用意して快適な生活を送りたいよね。
ということで、あまり触った事の無いATOMを導入してみた記録。

# What? **ATOM**
* Github社が提供しているオープンソースエディタ
    * 無料
* バージョン1.0リリースが2015年と割と若い？
    * でもコミッターが多くてどんどん高機能化が進んでいる模様
* 多くの開発者がATOM用のパッケージを開発公開している
    * 欲しい機能をインストールするだけで、自分好みにカスタマイズ可能

Github社が提供という**信頼性**
オープンソースであるという**無料という言葉の力**
必要な機能は自分で追加すればいいというシンプルな**拡張性**

phpstormを使っていて持て余している感がすごかった自分としては、とりあえず使ってみるにはもってこい。

# インストール
とても簡単。
1.https://atom.io/ にアクセス
2. "Download"をクリック
3. ダウンロードしたzipファイルを展開
4. "Atom"をアプリケーションへドラックアンドドロップ

# 拡張パッケージインストール
これだけでも開発はできそうだけど、せっかくいろいろ拡張パッケージが公開されてるので、
積極的に使っていきたいところ。

パッケージは、
> 上メニューの"ATOM" => "Preferences"

もしくは
> "Command" + ","

で設定を開いて、
> Install

を開けば検索できる。
なにを入れるかはお好きに。

# おすすめパッケージ
いろんなサイト見て回って、これ入れようとおもったパッケージメモ。
随時増えていきそう。

* [japanese-menu](https://atom.io/packages/japanese-menu)
    * メニューやら設定などを日本語に変えてくれる英語弱者には心強いパッケージ。
* [Project-manager](https://atom.io/packages/project-manager)
    * 複数のプロジェクトを行ったり来たりする人は入れておいたほうが快適
* [atom-beautify](https://atom.io/packages/atom-beautify)
    * ソースコードを綺麗に整形してくれるパッケージ
    * ぐちゃぐちゃになってしまったインデントも綺麗にしてくれる
* [file-icons](https://atom.io/packages/file-icons)
    * ファイルの種別ごとにアイコンと色を変えてくれる
* [linter](https://atom.io/packages/linter)
    * 構文エラーを指摘してくれる
* [pigments](https://atom.io/packages/pigments)
    * 指定している色でハイライトしてくれる


# おわりに
まだまだ知らない面白い機能がありそう。
おすすめパッケージがあったら、また追加していきます。
自分でも有益なパッケージ公開して、ATOMに還元できるようになれるといいね。
Crashlytics: 手動でクラッシュをトリガする方法

Crashlytics導入しました、さあ確認しよう！と見てみると、クラッシュレポートがゼロで動作確認できない・・・ということがあります。

以下のコードをソース上のどこかに入れることで、強制的にクラッシュを起こすことができますが・・・

```swift

Crashlytics.sharedInstance().crash()
```

シュミレーター経由だと、XCodeのデバッガーが作動するためCrashlyticsにレポートが送られない、という現象があります。

これを回避するにはコツがあり、XCodeが起動していない状態でクラッシュさせて、それからXCodeを起こしてCrashlyticsに送ってもらう必要があります。具体的には以下の手順です。

1. シュミレータを起動する。
2. XCode上でStopボタンを押す。
3. **シュミレータ上で**アプリを再起動し、クラッシュさせる
4. XCode上でStartボタンを押す。

公式にも書いてありますね。。。
https://docs.fabric.io/apple/crashlytics/test-crash.html
Log Parser で解析できる各種形式のSQLテンプレート

Microsoft の Log Parser で 解析できる形式の内、Webのアクセスログをよく使用するので、その SQL をメモ。

```sql:IIS形式テンプレ.sql
SELECT
     UserIP
    ,Date
    ,Time
    ,TimeTaken
    ,BytesSent
    ,BytesReceived
    ,StatusCode
    ,RequestType
    ,Target
    ,Parameters
FROM
    c:\xxxxx.log
```

```sql:NCSA形式テンプレ.sql
SELECT
     LogFilename
    ,LogRow
    ,RemoteHostName
    ,RemoteLogName
    ,UserName
    ,DateTime
    ,Request
    ,StatusCode
    ,BytesSent
    ,Referer
    ,User-Agent
    ,Cookie
FROM
    c:\xxxxx.log
```

```sql:W3C形式テンプレ.sql
SELECT
     date
    ,time
    ,c-ip
    ,cs-uri-stem
    ,cs-uri-query
    ,sc-status
    ,cs(User-Agent)
    ,cs(Referer)
FROM
    c:\xxxxx.log
```

## 参考

サイトの利用状況のログ収集について
https://msdn.microsoft.com/ja-jp/library/cc338018.aspx
nodejs: スケジュール設定付きSlack botの簡単なサンプル

![image.png](https://qiita-image-store.s3.amazonaws.com/0/77729/8fff161b-ed68-f03a-2496-8d53540bfe6d.png)

サンプルとして、1日の終わりに当日のgithubのcontribution数をslackに飛ばすbotをつくりました。
https://github.com/nnishimura/day-summary

かいつまんで説明したいと思います

## 準備
Slack上で、bot用のIncoming Webhookを作ります。
https://api.slack.com/incoming-webhooks

![image.png](https://qiita-image-store.s3.amazonaws.com/0/77729/e4ccca70-24fe-f8bf-39bf-49f9f85edff2.png)

投稿したいチャンネルを選んで進むと、`Webhook URL`が取得できます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/77729/89c11cd1-f005-5740-1d30-234bde5b821a.png)

これをコピーして、そのまま登録を完了します。

## Commanderを入れる

githubのユーザー名やbotの投稿時間のスケジュールをプログラムに渡せるように、
[commander](https://github.com/tj/commander.js/)をnpm installします。

これはnode側からコマンドラインの操作をしやすくするパッケージで、
後で`--schedule`等のオプションをつけてスクリプトを実行することで、
自由にbotの投稿時間を設定することができます。

```js:index.js
const program = require('commander')

program
  .version('0.1.0')
  .option('--github <string>', 'Add github username')
  .option(
    '--schedule [string]',
    'cron pattern, defaults to 20:00 every day',
    '00 20 * * *'
  )
  .parse(process.argv)
```

こうすると、例えば`node index.js --github 'akira'`というコマンドを実行した時、`program.github`で`akira`が取れるようになります。

## node-scheduleを入れる
botの投稿時間を決めるため、[node-schedule](https://github.com/node-schedule/node-schedule)をnpm installします。

```js:index.js
const schedule = require('node-schedule')

const pattern = program.schedule || '00 20 * * *'

const j = schedule.scheduleJob(pattern, () => {
  // slackに投稿する処理
})

```
前のステップで`--schedule`オプションに渡したパターン通り、slack通知の関数をトリガすることができます。
例えば、`00 20 * * *`だと毎日20時になります。

```
*    *    *    *    *    *
┬    ┬    ┬    ┬    ┬    ┬
│    │    │    │    │    │
│    │    │    │    │    └ day of week (0 - 7) (0 or 7 is Sun)
│    │    │    │    └───── month (1 - 12)
│    │    │    └────────── day of month (1 - 31)
│    │    └─────────────── hour (0 - 23)
│    └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, OPTIONAL)
```

## スラック投稿の処理

さきほど取得した`Webhook URL`にメッセージをPOSTします。
`Webhook URL`はそのままコード上に入れないで、環境変数として登録してください。

```js
const request = require('request')

const DEFAULT_PARAMS = {
  url: process.env.SLACK_WEB_HOOK_URL, // 環境変数
  form: 'payload={text: "default message",username: "test bot",icon_emoji: ":bar_chart:"}',
  headers,
  json: true
}

request.post(DEFAULT_PARAMS, (error, response, body) => {
  if (!error && response.statusCode == 200) {
    return console.log(body) // logs 'ok'
  }

  console.log('error: ' + response)
})
```

## 動かす
```
node index.js --github 'USER_NAME' --schedule 'SCHEDULE_PATTERN'
```

とりあえずこれで動きますが、このスクリプトをずっと実行したいので、[forever](https://github.com/foreverjs/forever)というパッケージを使います。

## Foreverで永続化
- `npm install -g forever`でグローバルインストールした場合は、

```
forever index.js --github 'USER_NAME' --schedule 'SCHEDULE_PATTERN'
```

- ローカルにしかない場合

```
./node_modules/.bin/forever index.js --github 'USER_NAME' --schedule 'SCHEDULE_PATTERN'
```

これでslack botのスクリプトを実行し続けることができます。

## まとめ
- コマンドラインツール化：[commander](https://github.com/tj/commander.js/)
- スケジュール：[node-schedule](https://github.com/node-schedule/node-schedule)
- 永続化：[forever](https://github.com/foreverjs/forever)
Error injecting method, java.lang.NoClassDefFoundError: akka/actor/CoordinatedShutdown$Reason

# エラー

```
play.api.UnexpectedException: Unexpected exception[CreationException: Unable to create injector, see the following errors:

1) Error injecting method, java.lang.NoClassDefFoundError: akka/actor/CoordinatedShutdown$Reason
  at com.google.inject.util.Providers$GuicifiedProviderWithDependencies.initialize(Providers.java:149)
  at play.api.db.slick.SlickModule.$anonfun$namedDatabaseConfigBindings$1(SlickModule.scala:43):
Binding(interface play.api.db.slick.DatabaseConfigProvider qualified with QualifierInstance(@play.db.NamedDatabase(value=default)) to ProviderTarget(play.api.db.slick.NamedDatabaseConfigProvider@a4117d7)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)

1 error]
        at play.core.server.DevServerStart$$anon$1.reload(DevServerStart.scala:186)
        at play.core.server.DevServerStart$$anon$1.get(DevServerStart.scala:124)
        at play.core.server.AkkaHttpServer.handleRequest(AkkaHttpServer.scala:189)
        at play.core.server.AkkaHttpServer.$anonfun$createServerBinding$1(AkkaHttpServer.scala:106)
        at akka.stream.impl.fusing.MapAsync$$anon$23.onPush(Ops.scala:1172)
        at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:499)
        at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:462)
        at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:368)
        at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:571)
        at akka.stream.impl.fusing.GraphInterpreterShell$AsyncInput.execute(ActorGraphInterpreter.scala:457)
```

# 解決策

**akka-actor**と**akka-stream**を**2.5.6**から**2.5.10**に変える
facebook アカウント連携エラー (URLを読み込めません: このURLのドメインはアプリのドメインに含ま........)

ローカル環境（localhost）でfacebook連携する時にうまくいかず、
 **[URLを読み込めません: このURLのドメインはアプリのドメインに含まれていません。このURLを読み込むには、アプリ設定のアプリドメインにすべてのドメインとサブドメインを追加してください]** とエラーが出てしまう。
いろいろ試しました(ドメインを書いたり、httpからhttpsに変更したり)がうまく連携できず....

以下自分が最終的に解決した方法です。


#解決策

① facebook developerのプロダクト、facebookログインへ。
② その中の「有効なOAuthリダイレクトURI」を(https://localhost:3000) から (https://localhost:3000/user/auth/facebook/callback) に変更。

これでうまくいきました。よかった、よかった。

#参考
[stackover flow-Facebook app domain name when using localhost]
(https://stackoverflow.com/questions/13376710/facebook-app-domain-name-when-using-localhost/46658295#46658295?newreg=8965181a8bbb4ac3a4821ae69342c0f8)
英語ですが、他の解決方法が載っているので上記で解決できなかった場合は読んでみてください。
会社で便利に Thunderbird （メールアドレス自動補完）

2017年になった昨今、会社のメーラは Office が入っていると思います。

入って無くてどうしても Thunderbird を使わざるをえない場合でも、メールボックスが IMAP をサポートしていれば、メールの送受信は簡単です。メール届いたら自動通知されるし。

＋αで、会社でログインなどの基板に使う Active Directory 情報を使って、メールアドレスの自動補完をする方法のメモ。

自分で再設定時に使う用の備忘録なので、AD, LDAP  の基本的な知識がある前提です。


Active Directory 情報を取得する
=============================

Domain 名を調べる
-------
社内資料とかを検索する。

Domain Controller アドレスを調べる
-------
AD ドメイン名でアクセスできる。
DNS と、AD ドメイン名が違う場合（例えば、MacOS を使っていて、会社の AD にアクセスしたい場合）は、DC のアドレスを調べる必要がある。

Base DN 名を求める
-------
一番良い方法って何なんだろう。
とりあえず、GUI から開くのが楽。
http://jxplorer.org/ は動いた。

Thunderbird に設定する
--------
* http://signal9.exblog.jp/12377640/

Mapping を変更する
--------
* https://www.google.co.jp/search?q=thunderbird+active+directory+query&oq=thunderbird+active+directory+query+&aqs=chrome..69i57.7598j0j7&sourceid=chrome&ie=UTF-8#q=thunderbird+ldap+mapping
* https://www.mozilla.jp/business/faq/tech/setting-management/
* http://piro.sakura.ne.jp/latest/blosxom/mozilla/thunderbird/2010-04-14_ldap.htm

自動補完の Mapping を設定する
--------
* https://wiki.mozilla.org/MailNews:LDAP_Address_Books
* http://signal9.exblog.jp/12377640/
意図しない Popup Blocker を以下に回避する方法で色々調べたこと随時更新

1. ちょっと込み入ったことをやろうとして、JavaScript で Browser Window を開く
2. 開発環境/テスト環境ではおけ。（いつだったかポップアップブロック解除してた)
3. 本番環境に出してみたらポップアップ Block された。(＠_＠;)

みたいな時に確認する項目

# あまり関係ないけど公式情報

## [Trusted Event](https://www.w3.org/TR/DOM-Level-3-Events/#trusted-events)
> Events that are generated by the user agent, either as a result of user interaction, or as a direct result of changes to the DOM, are trusted by the user agent with privileges that are not afforded to events generated by script through the createEvent() method, modified using the initEvent() method, or dispatched via the dispatchEvent() method. The isTrusted attribute of trusted events has a value of true, while untrusted events have a isTrusted attribute value of false.

### 要約
* ユーザー操作によってに生成されたイベント[^1]は、信頼された物として特別な権限をもって扱われる。
* 一方で、script によって生成されたイベント[^2]は特別な権限を持たない。
* `isTrusted` 属性でわかる。

[^1]: または、DOM の直接の変更によって生成されたイベント。
[^2]: `createEvent()` で生成された関数や `initMethod()` 関数で変更されたイベント、`dispatchEvent()` 関数で dispatch されたイベント。

# Block されないために

試して見た。。

https://jsfiddle.net/kazukima/yg3okg5y/

1. ajax のコールバックの中でも `isTrusted = true` （まじか。。。まぁそう覚えておくか）
2. ajax のコールバックの中で `window.open` するとポップアップブロックされる（期待値）。`async:false` にした場合は、ブロックされない（期待値）


うーん。`isTrusted` が参考になるかとおもったらそれもあるけど、もちろんイベントタイプも見てるんですね。

とりあえず ajax 結果で `window.open` したい場合、 `async:false` を付ければいけるっていうのは、そりゃそうなんですが。結局これはなに切っ掛けにしてるんだろう。。。。

# 脚注
EurekaでkeyboardDismissMode = .interactiveにしてもインタラクティブにならない問題を解決する方法

# 事象

Swiftのフォーム生成ライブラリEurekaを使用していますが、keyboardDismissMode = .interactiveにしてもインタラクティブにならず、onDragを指定した状態になってしまう問題が発生しました。

解決方法を確認したのでメモしておきます。

# scrollViewWillBeginDragging をオーバーライドする

`FormViewController`の実装を確認すると、`UIScrollViewDelegate`の実装の中で、キーボードのハンドリングをしていました。

```
extension FormViewController : UIScrollViewDelegate {

    // MARK: UIScrollViewDelegate

    open func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        guard let tableView = tableView, scrollView === tableView else { return }
        tableView.endEditing(true)
    }
}
```


`tableView.endEditing(true)`によって、キーボードを非表示にしているようです。


そのため、`FormViewController`を継承ている`ViewController`側で、`scrollViewWillBeginDragging`をオーバーライドして、`keyboardDismissMode`を`.interactive`に設定することで、キーボードをインタラクティブに非表示にすることができます。


```
override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { 
}    
```
Re:VIEWをmacOS High Sierraにインストールする

タイトルの通りの作業ログです。環境はmacOS High Sierra 10.13.4（17E199）Homebrewのバージョンは`1.6.2`です。
### Re:Viewのインストール  
[公式](https://github.com/kmuto/review#installation)の手順通りインストールします。

```shell
$ gem install review
```
### MacTexをインストール  
PDF出力に必要らしいので[公式](https://texwiki.texjp.org/?MacTeX#s59a1243)や[こちら](https://qiita.com/patorash/items/7df5074d8fdd901edc80#mactex%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)を参考にインストールを進めます。（ここではgui無しをいれます。）

```shell
$ brew install --cask mactex-no-gui
```

brew-caskとは、[公式](https://github.com/caskroom/homebrew-cask#homebrew-cask)によるとmacのGUIアプリもHomebrewで管理する為の拡張とのこと。仕様が変わって、`/usr/local/Caskroom`にアプリの情報のみを入れ、`/Applications`にアプリの実体をインストールするようになったそうです。参考:[Homebrew CaskのCaskroomの場所が変わったり色々変更があった](https://rcmdnk.com/blog/2016/06/28/comptuer-mac-homebrew-brew-file/)


次にTeXのアップデートをします。（20分近くかかりました。） [tlmgr](https://texwiki.texjp.org/?tlmgr)は`TeX Live のパッケージ管理ツール`です。（`sudo: tlmgr: command not found`になる場合 `exec $SHELL -l` でshellを再起動します。エラーが変わらない場合は、`brew cask uninstall mactex-no-gui` で一度削除して入れ直すなども試すとよさそうです。）

```shell 
sudo tlmgr update --self --all
```


デフォルトの用紙サイズをA4に変更します。

```shell 
$ sudo tlmgr paper a4
```  

後は[公式](https://github.com/kmuto/review#quick-start)の通りやればサンプルのPDFが開けます。  

```shell 
$ review-init hello
$ cd hello
$ (... add and edit *.re file, config.yml and catalog.yml ...)
$ rake epub  ## generating EPUB
$ rake pdf   ## generating PDF(Requirement TeX)
```  

より詳しいQuickStartは[Re:VIEW Quick Start Guide](https://github.com/kmuto/review/blob/master/doc/quickstart.md)を見るとよさそうです。

VSCodeで.reファイルを編集した後に`rake pdf`が次のエラーでコケるときは制御文字が入っていることを疑った方がいいかもしれません。 対策→[VSCodeで制御文字を表示する](https://qiita.com/tikidunpon/items/bd1bd99cf0897e638062)  

```shell
!Package inputenc Error: Keyboard character used is undefined
(inputenc)                in inputencoding `utf8'.
```
MacのターミナルでRubyをバージョンアップする方法

Rubyのバージョンを変更しようとした際に引っかかったので記録します。

#SPEC
macOS Sierra 10.12.6

macOSには最初からRubyがインストールされているので
現在のRubyのバージョンを確認

```
$ ruby -v
ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16]
```

#rbenvのインストール
今回はバージョンアップにHomebrewのrbenvを使用するため
はじめにrbenvをインストールして最新にアップグレードします。

```
$ brew update
$ brew install rbenv ruby-build
$ brew upgrade rbenv
```

rbenvのバージョンを確認

```
$ rbenv -v
rbenv 1.1.1
```

#インストールできるRubyのバージョンを確認

```
$ rbenv install --list
```

#バージョンを指定してRubyをインストール

```
$ rbenv install 2.3.1
$ rbenv global 2.3.1
$ gem install railties && rbenv rehash
```

インストールできているか確認

```
$ rbenv versions
  system
* 2.3.1 (set by /Users/ユーザー/.rbenv/version)
```
rbenvに2.3.1が入っているので、
再度Rubyのバージョンを確認

```
$ ruby -v
ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16]
```
変わらず。

#バージョンが変わらない場合
上記でバージョンが変わっていなければ
rubyの場所を確認してください

```
$ which ruby
/usr/bin/ruby
```
rbenvでRubyをバージョンアップする場合、
`/Users/ユーザー/.rbenv/shims/ruby`
を参照している必要があるので変更していきます。

```
$ rbenv init
# Load rbenv automatically by appending
# the following to ~/.bash_profile:

eval "$(rbenv init -)"
```
`eval "$(rbenv init -)"`をコピーして~/.bash_profileに追記します

```
$ vi ~/.bash_profile

・
・
・
Swap file "~/.bash_profile.swp" already exists!
[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort: 
```

編集するので `e`キーをタイプ
vim画面に入ります。

##vimについて
vim画面では「コマンドモード」と「挿入モード」があり、
最初はコマンドモードになっています。

編集するには挿入モードにする必要があるので
`i`キーか`a`キーを押すと、最下行に

```
-- INSERT --
```
と表示されます。これで挿入モードになっています。

先ほどコピーした`eval "$(rbenv init -)"`を追記したら、
`esc`キーを押してコマンドモードに戻ります。
`:wq`と入力してenterすると編集内容を保存して終了します。（カーソルが画面のどこにあっても大丈夫です。）

ちなみに、
保存せずに強制終了する場合は`:q!`と入力します。
もしless画面に入ってしまった場合は`q`で終了してください。

#再度確認
元の画面に戻ったらまず変更を反映します。

```
$ source ~/.bash_profile
```

再度Rubyのバージョンを確認

```
$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin16]
```

指定バージョンに変更されました。
micro:bit+アルミホイルスイッチの反応が鈍い


【2018-09-21追記】2018年9月現在、リリース予定のmakecodeのv1-betaでは「端子Pxがタッチされた時」ブロックのレスポンスがよくなっています。今後は下記の手法は使わなくても良くなりそうです。


#問題点

micro:bitで子供達が電子工作をするのに便利なのがワニ口クリップ＋ダンボール＋アルミホイルです。
![dannbo-ru.jpg](https://qiita-image-store.s3.amazonaws.com/0/44523/ddae925d-bcce-3aef-01c4-7102cbcf41aa.jpeg)

ところが、いざ作ってみると「反応がにぶい」「検出されない事がある」といったトラブルに出会うと思います。

例えば、アルミホイルとダンボールでフットスイッチを作って
![image.png](https://qiita-image-store.s3.amazonaws.com/0/44523/06e2049a-c40c-8817-d176-4e74bca4bf63.png)

こんなプログラム
![image.png](https://qiita-image-store.s3.amazonaws.com/0/44523/3b90de99-0061-c3d3-86b7-f1a20660a373.png)

を書いたとします。

これだと、しっかり踏まないと検出されません。

#対策

ちょっと面倒ですが、こんな風に書くとちゃんと検出してくれるようです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/44523/b4e08ef8-6ee6-3c50-b884-d477f30788b6.png)

もし、もっと良い方法があれば教えて下さい。

#おまけ

アルミホイルでスイッチをつくるとみすぼらしかったり、ワニ口クリップで挟むところがすぐに破けてしまいます。
そんな場合にお勧めなのが、セリアのキッチンコーナーで売っているアルミテープ。

- アルミホイルより厚くて破れにくい
- 通電もバッチリ
- 裏面が粘着面になっているので綺麗に貼れる（アルミホイル＋両面テープだとシワシワに）
- 50mm幅で7mもあって100円

子供たちと遊ぶ時には最高です！（ダイソーでも売っているそうなのですが近所では見つけられませんでした）
jstatのログを即Excelで見れるようにする

メモリ関連の調査をしているときにどうしてもExcelで集計したいということを言われたので、とりあえずやってみた。

普段のjstatのログは以下のように出る。

~~~
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
512.0  512.0   0.0    0.0   124928.0  6358.9   83968.0    42417.6   65064.0 58754.0 9256.0 7392.2  15501   94.212 15488 1702.193 1796.405
~~~

とりあえず日付とカンマ区切りができればそのままExcelで読んでよしなにできそうなので、sedとawkを使ってやってみた。
動作しているアプリケーションがWindows環境なので、あらかじめsedとawkを実行できるようにインストールしておく。
Macで試していたらawkのstrftimeがないと怒られるのでgawkをインストールした。

~~~
awk: calling undefined function strftime
~~~

で、いろいろ試して以下のようになった。

~~~
jstat -gc <process id> 10s | gawk '{print strftime("%Y/%m/%d-%H:%M:%S"), $0; fflush();}' | sed -e 's/^  *//g; s/  */,/g' >> jstat.csv
~~~

これで以下の用に出力されるようになる。

~~~
2018/04/28-23:28:46,S0C,S1C,S0U,S1U,EC,EU,OC,OU,MC,MU,CCSC,CCSU,YGC,YGCT,FGC,FGCT,GCT,
2018/04/28-23:28:46,512.0,512.0,0.0,0.0,124928.0,4831.7,83968.0,42283.1,65064.0,58754.0,9256.0,7392.2,15507,94.412,15494,1703.366,1797.778
2018/04/28-23:28:47,512.0,512.0,0.0,0.0,124928.0,4831.7,83968.0,42283.1,65064.0,58754.0,9256.0,7392.2,15507,94.412,15494,1703.366,1797.778
~~~

ヘッダにも日付が入ってしまうけどそこは妥協点ということにしておく。
【自分メモ】Railsで画像アップロード機能の実装

## 環境
・Ubunts 14.04
・Rails 5.1.5
・Ruby 2.4.0
・PostgreSQL 9.3.18

## 使用するgem
・carrierwave

## 実装手順
### gemをインストール
Gemfileに以下の内容を書いて、`bundle install`を実行

```:Gemfile
gem 'carrierwave', '~> 1.0'
```

### Uploaderを作成する
carrierwaveのインストールが完了したらuploaderクラスを生成できるので、以下のコマンドでuploaderを作成する

```console
rails g uploader <アップローダー名>
```

### Uploaderでアップロードした画像を保存する場所を指定する

```:app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
  storage :file 
  # 画像を保存する場所を指定
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
end
```

### Uploaderをモデルのカラムに紐付ける
アップロードした画像をどのテーブルのカラムに保存するかを定義する
`mount_uploader`メソッドを使ってカラムとUploaderを紐付ける

例：Sampleモデルのimageカラムに作成したUploaderを紐付け

```sample.rb
class Sample < ApplicationRecord
  mount_uploader :image, ImageUploader
end
```
Dart : Webdev と Flutter を ごった煮で開発する方法

Dart を用いることで、Html5 のフロントエンドや、サーバサイド、スマートフォン用のアプリを開発することができます。


一つのProjectで、これらの開発をするにはどうすれば良いでしょうか?
色々試してみて、今落ち着いた方法について書いてみます。



# Webdev と Flutter は、 混合できない
pubspec.yaml に、 flutter と webdev のプロジェクトを一緒書くことができません。

pub get
pub run build_runner serve
とすると、 Flutter Project には使えないよと注意されます。

※ 2015年の頃はできました。
※ サーバーサイドとは、一緒に書くことができる。

例えば以下のような感じに書いても使えません。

```yaml
name: hello
description: A new Flutter project.

web:
  compiler:
    debug: dartdevc

flutter:
  uses-material-design: true

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: any
  build_web_compilers: any

environment:
  sdk: '>=2.0.0-dev.48 <2.0.0'
```


# とてもメンドくさい

一つのProject に書けないのは、とても面倒くさいです。

例えば、 umiuni2d という package を作ることして、
umiumi2dには、 サブプロジェクトとして、
umiuni2d_sprite, umiuni2d_audio, umiuni2d_httprequest, umiuni2d_io とあるとします。

それぞれ、 「共通のInterface」、「flutter」、「html5」 と用意すると、
これだけで、24個の github repogitory ができてしまいます。
https://github.com/kyorohiro/umiuni2d


例えば、IntelliJ で開発すると、
一つのPackage を開発するのに、
共通用、 Flutte用、 Webdev 用の 3つのProject を開きながら開発することになります。

大変!! 重い!! 面倒!!

※ DartEditor の時は、 　複数Project でも、快適に一つの画面で管理できてましたね。

# アプリ側は楽をしよう

ライブラリー側は仕方がないので、 アプリ本体は、楽をしようとして、以下のような感じに落ち着きました。

https://github.com/kyorohiro/umiuni2d_sprite_example


### pubspec.yaml を二つ用意する

Webよう

```yaml
name: hello
description: A new Flutter project.

web:
  compiler:
    debug: dartdevc
dependencies:
  cupertino_icons: ^0.1.0

dev_dependencies:
  build_runner: any
  build_web_compilers: any


environment:
  sdk: '>=2.0.0-dev.48 <2.0.0'
```

Flutterよう

```yaml
name: hello
description: A new Flutter project.

flutter:
  uses-material-design: true
  assets: 
     - web/assets/font_a.json 
     - web/assets/font_a.png 

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.0

dev_dependencies:
  flutter_test:
    sdk: flutter

environment:
  sdk: '>=2.0.0-dev.48 <2.0.0'

```

動作確認するときに、使用するpubspec.yamlを切り替える。
すると、

- web/ 配下のassetsをおくことで、リソースを共通化できます!!
- IDEのリファクタ機能でWebdev to Flutter のコードを同時にリファクタリングできます。

と良いことだらけ



# おわり

他にも方法があるけど..
こんな感じです。


# Ref 

今回のサンプル
https://github.com/kyorohiro/gottani_project_dart_flutter_webdev

作成中のFlutter と Html5 共用のゲームライブラリーのサンプル
https://github.com/kyorohiro/umiuni2d_sprite_example
RaspberryPi と NatureRemo を使って GoogleHome 向けアプリをつくってみる

Google Homeで次のようなアプリがあったらいいなーと以前から思っていたので、何も予定のないGWで作って見ようと思います。
これを機にラズパイ買ったが初心者です。あくまで自分用のメモ。


#:white_check_mark:メールマガジンを読み上げ
####:paperclip:毎週1回配信されるメールマガジンの内容を「最新のメルマガ読んで」で読み上げてくれる
　<ざっくり想定しているプロセス>　
　Gmailで受信
　⇒Spreadシートに常に1行目が最新となるよう登録
　⇒「OK Google, XXXのメールマガジンを読んで」
　　XXXの部分が「最新の」「1番目の」だとSpreadの1行目、「1つ前の」「先週の」だと2行目、のように読み上げてほしいものを指定したい

#:white_check_mark:「ただいま」の処理を少し賢く
####:paperclip:IFTTTの連携だと1つの文で行う処理は決まっているので、寒かったら暖房を入れる、18時過ぎてたら照明つけるなど、条件によって挙動を変えてほしい
　<ざっくり想定しているプロセス>　
　「OK Google, ただいま」
　⇒現在時刻が18時～5時の間ならば、照明をつける
　⇒気温が10度以下なら暖房をつける、もしくは25度以上なら冷房をつける
　⇒「テレビはつけますか？」と聞かれ「うん」:テレビをつける／「いいや」:「何もしない」

#:white_check_mark:HDDに録画した番組を削除
####:paperclip:録画した番組を見終わった後の操作が固定なので一言で片づけたい
　<ざっくり想定しているプロセス>　
　「OK Google, この録画を消して」
　⇒[録画リスト]ボタン押下
　⇒[黄色]ボタン押下
　⇒[↓]ボタン押下x2回
　⇒[決定]ボタン押下
　⇒「よろしいですか？」と聞かれ「いいよ」:[決定]ボタン押下／「やっぱだめ」:[戻る]ボタン押下
　※ボタンを押した直後に連続しても押しても反応しないので、0.5秒くらい間隔をあける(やってることは幼稚園児でもできるのに実装しようとしたら意外とめんどい・・・)

#:white_check_mark:LINEで双方向のやりとり
####:paperclip:IFTTTの連携だと送信はできるが、それだけでは物足りないので受信したメッセージも読み上げてほしい
　<ざっくり想定しているプロセス>　
　「OK Google, LINEでうんこ投げるぞ　と送信」
　⇒考え中


もうすでに実現してる人もいて、調べると実装方法はいくつかあるみたいだけど、どうやってやるかもふくめこれから考えていきます。

プロセスとともに随時更新予定。
AV1 specification を読む 2018-04-17 (7.10.2.5. Setup Shear Process)

#AV1 specification 日本語訳 (2018-04-17)

Setup Shear Process では、与えられたワープパラメータから、アフィン変換行列の alpha, beta, gamma, delta を計算します。
この演算には整数除算が含まれます。
整数除算は 7.10.2.6. Resolve Divisor Process で定義されるように、乗算とシフト演算で実装します。


ワープパラメータは自動計算される場合もあるため、うまく変換できない場合があるので、warpValid=0 になることもあります。

----

#### 7.10.2.5. Setup Shear Process

> The input for this process is an array warpParams representing an affine transformation.

この処理の入力は配列 warpParams で、アフィン変換を表現します。

> The outputs from this process are the variable warpValid and variables alpha, beta, gamma, delta representing two shearing operations that combine to make the full affine transformation.

この処理の出力は、warpValidと、完全なアフィン変換を生成するために結合された、2つの剪断操作を表現する偏す alpha, beta, gamma, delta です。

> The variable alpha0 is set equal to Clip3( -32768, 32767, warpParams[ 2 ] - (1 << WARPEDMODEL_PREC_BITS) ).
> The variable beta0 is set equal to Clip3( -32768, 32767, warpParams[ 3 ] ).

alpha0 = Clip3( -32768, 32767, warpParams[ 2 ] - (1 << WARPEDMODEL_PREC_BITS) )
beta0 = Clip3( -32768, 32767, warpParams[ 3 ] )

> The resolve divisor process specified in section 7.10.2.6 is invoked with warpParams[ 2 ] as input, and the outputs assigned to divShift and divFactor.

7.10.2.6節で規定される除算解決処理を warpParams[2] を入力として呼び出し、出力を divShift, divFactor に割り当てます。

> The variable v is set equal to ( warpParams[ 4 ] << WARPEDMODEL_PREC_BITS ).
> The variable gamma0 is set equal to Clip3( -32768, 32767, Round2Signed( v * divFactor, divShift ) ).
> The variable w is set equal to ( warpParams[ 3 ] * warpParams[ 4 ] ).
> The variable delta0 is set equal to Clip3( -32768, 32767, warpParams[ 5 ] - Round2Signed( w * divFactor, divShift ) - (1 << WARPEDMODEL_PREC_BITS) ).

v = ( warpParams[ 4 ] << WARPEDMODEL_PREC_BITS )
gamma0 = Clip3( -32768, 32767, Round2Signed( v * divFactor, divShift ) )
w = ( warpParams[ 3 ] * warpParams[ 4 ] )
delta0 = Clip3( -32768, 32767, warpParams[ 5 ] - Round2Signed( w * divFactor, divShift ) - (1 << WARPEDMODEL_PREC_BITS) )


> The output warpValid is set as follows:
>
>  * If 4 * Abs( alpha0 ) + 7 * Abs( beta0 ) is greater than or equal to (1 << WARPEDMODEL_PREC_BITS), warpValid is set equal to 0.
>  * If 4 * Abs( gamma0 ) + 4 * Abs( delta0 ) is greater than or equal to (1 << WARPEDMODEL_PREC_BITS), warpValid is set equal to 0.
>  * Otherwise, warpValid is set equal to 1.

出力の warpValid を以下のように設定します。

 * 4 * Abs( alpha0 ) + 7 * Abs( beta0 ) >= (1 << WARPEDMODEL_PREC_BITS) ならば、warpValid = 0
 * 4 * Abs( gamma0 ) + 4 * Abs( delta0 ) >= (1 << WARPEDMODEL_PREC_BITS) ならば、warpValid = 0
 * そうでなければ、warpValid = 1


> The remaining output variables are set as follows:

残りの出力変数を以下のように設定します。

```C++
alpha = Round2Signed( alpha0, WARP_PARAM_REDUCE_BITS ) << WARP_PARAM_REDUCE_BITS
beta = Round2Signed( beta0, WARP_PARAM_REDUCE_BITS ) << WARP_PARAM_REDUCE_BITS
gamma = Round2Signed( gamma0, WARP_PARAM_REDUCE_BITS ) << WARP_PARAM_REDUCE_BITS
delta = Round2Signed( delta0, WARP_PARAM_REDUCE_BITS ) << WARP_PARAM_REDUCE_BITS
```
EC2のインスタンスからSES経由でSendmailする


SDK使えば済む話ですが、PHPとか使ってるとローカルでsendmailできる前提にいろいろ動いてたりするので、sendmailをSESを連携するようにしてみたメモ。基本的には[ここ](https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/sendmail.html)に手順があるのですが、そのままでは動かいないので、メモしておきます。

## やりたいこと

* EC2からsendmailでメール送信したい（PHPとかから送る必要あるので）
* SPFとかDKIMの設定を楽に確実にしたい

>素のEC2で設定してもよかたのですが、素直？にSES使うことにしました。

## 知っておかないとハマること

私はAmazon初心者なので、幾つか前提を理解しておらずハマりました。

SESはメール送信用のサービスですが、本格運営のためには「制限解除申請」的なものが必要で、そのままの状態（Sandbox）では、以下の制限があるようです。

* 1日200通まで
* 予め登録したメールにしか送れない（from, toに設定できない）

など。その他、1秒間に1通というのもあるらしいですね。あと、東京リージョンにはサービスが無いとか。。。
あと、EC2からのメール送信にも制限があり、申請による解除が必要のようです。

>メール送信専用サービスなので、ちゃんと設定すれば制限なんて無いのかな？と勝手に思っていました。

## SESでまずテストメールが送れるようにしておく

### ドメインの登録

SES ダッシュボードの左ペインのDomainsでまず、送信（From）に利用したいドメインを登録しておきます。

### メールアドレスの登録

続いてEmail Addressesで、送信先アドレスを登録しておきます。

### テストメールの送信

上記の登録がおわり、ステータスがverifiedになったら、Domainsの[Send a Test Mail]で（指定した）メールにテストメールが届くか確認します。

メールが届けばSESとしては動いてる状態です。

## SMTPのアカウント（Credential）を取得しておく

SMTP Settingsで、IDとPasswordを取得しておきます。

## Sendmailの設定

私はAmazon Linux(1)を利用しています。標準でMTAとしてsendmailが動いているようですね。
postfixに変更することも考えましたが、とりあえずそのまま使います。

>なお、上記フローに「まずはsendmailが使えるか確認しろ」と書いてあったので、sendmailで送信試験をしたところ、送れたり、送れなかったりしたので、最初いろいろ悩みました。遅れない場合、一度 /etc/init.d/sendmail restart で、sendmailを再起動してもよいかもしれません。

## フロー通りに設定する

設定は[ここ](https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/sendmail.html)通りに進めればよいのですが、幾つか変更点があります。

### フローの確認

まず、全体の作業の流れはおおよそ下記のようなものです。

*. SESの設定が終わっている（前提）SPF, DKIMの設定+test mail送信済み
*. sendmailが動いている（前提）

を前提として、

1. /etc/mail/authinfoの作成と編集（なかったので新規作成）
2. /etc/mail/authinfo.dbの生成
3. /etc/mail/accessの編集
4. /etc/mail/access.dbの再生成
5. /etc/mail/sendmail.mcの編集
6. /setc/mail/sendmail.cfの再生成（とパーミッション変更）
7. sendmailの再起動
8. メール送信テスト
9. （制限解除申請）

という感じ。


### LOINGをPLAINに

例として、下記の表記がありますが、"M:LOGIN"のところを"M:PLAIN"にしました。

```diff
-AuthInfo:email-smtp.us-west-2.amazonaws.com "U:root" "I:USERNAME" "P:PASSWORD" "M:LOGIN"
+AuthInfo:email-smtp.us-east-1.amazonaws.com "U:root" "I:USERNAME" "P:PASSWORD" "M:PLAIN"
```

>なお、例はオレゴンリージョンを利用していますが、サーバ名はリージョンに合わせて変更します。
私は、バージニア北部を利用したので、email-smtp.us-east-1.amazonaws.comを利用しました。

### portを25から587に

sendmail.cfの設定時、例は25番ポートを使っていますが、587とかじゃないと動きません。

```diff
define(`SMART_HOST', `email-smtp.us-west-2.amazonaws.com')dnl
-define(`RELAY_MAILER_ARGS', `TCP $h 25')dnl
+define(`RELAY_MAILER_ARGS', `TCP $h 587')dnl
define(`confAUTH_MECHANISMS', `LOGIN PLAIN')dnl
FEATURE(`authinfo', `hash -o /etc/mail/authinfo.db')dnl
MASQUERADE_AS(`YOUR_DOMAIN')dnl
FEATURE(masquerade_envelope)dnl
FEATURE(masquerade_entire_domain)dnl
```

>あと、挿入位置に注意が必要です。MAILER()定義の前に挿入する必要があります。

### sendmail.cfのパーミッションは666ではなく、644

sendmail.cfのパーミッションが666だと怒られます。

```diff
-sudo chmod 666 /etc/mail/sendmail.cf
+sudo chmod 644 /etc/mail/sendmail.cf
```

### 再起動して送信テスト

手順どおりですが、sendmailの再起動を忘れずに。

## 制限解除申請

メールが問題なく送れているようなら、Sending Statisticsメニューを選択すると[Request a Sending Limit Increases]というボタンがあるので、クリックして制限解除申請を行います。

>5時間後くらいに承認メールがきました。1万通/日, 10件/secで申請しましたが、5万件/日, 14件/secで承認されたようです。

## 参考サイト

* https://qiita.com/OMOIKANESAN/items/1b8941258fb7ebbdb057
* https://www.infoscoop.org/blogjp/2015/07/29/amazon-ses-release-limit/