OmniAICreator/Qiita-1.07M huggingface dataset:
Spring AOPを利用してSpring Boot アプリケーションのログを落とす

[Spring Boot + MySQLでシンプルなWeb REST APIサーバを実装する - Qiita](https://qiita.com/YutaKase6/items/007f6b7d12d342c1330c#%E3%83%AD%E3%82%AC%E3%83%BC%E3%82%92%E5%B0%8E%E5%85%A5%E3%81%99%E3%82%8B)

# Outline
Spring AOPを利用してSpring Boot アプリケーションのログを落とす。
利用するロガーはSLF4J+Logback。

## [SLF4J](https://www.slf4j.org/)
![](https://www.slf4j.org/images/logos/slf4j-logo.jpg)
javaのロギングのインタフェースの仕様。
これを用いることで、Loggerの実装を隠蔽することができる。  
## [Logback](https://logback.qos.ch/)
![](https://logback.qos.ch/images/logos/lblogo.jpg)
slf4jの実装の一つ。

# AOP
Aspect Oriented Programming
クラスやメソッドに横断的に存在する処理(まさにロギングとか)を一箇所にまとめて記述しようという考え方。
Springではアノテーションを用いて実装されている。

# dependencies
spring-boot-starter-webを利用していれば使えるので、特に追加等は必要ない。

# LoggingAspects.java
ログの出力を実行するクラス。
AOPを利用してこのメソッドを様々な箇所に注入する。 
 
```LoggingAspects.java
package com.example.springapi.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect
@Component
public class LoggingAspects {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspects.class);

    @Before("within(com.example.springapi.application.controller.UserController)")
    public void controllerStartLog(JoinPoint joinPoint) {
        String string = joinPoint.toString();
        String args = Arrays.toString(joinPoint.getArgs());

        logger.info("Start {}, args: {}", string, args);
    }

    @AfterReturning("within(com.example.springapi.application.controller.UserController)")
    public void controllerEndLog(JoinPoint joinPoint) {
        String string = joinPoint.toString();
        String args = Arrays.toString(joinPoint.getArgs());

        logger.info("End {}, args: {}", string, args);
    }

    @AfterThrowing(value = "within(com.example.springapi.application.controller.UserController)", throwing = "e")
    public void afterException(JoinPoint joinPoint, Exception e) {
        String string = joinPoint.toString();
        String args = Arrays.toString(joinPoint.getArgs());

        logger.error("Error!, Exception: {}, {}, args = {}", e.getMessage(), string, args);
    }
}
```

## @Aspect
AspectJというAOPライブラリのアノテーション。
実際はSpringBootがAOPの機能を実装しているが、アノテーションのみAspectJのを使ってるらしい。
@Aspectと@Compornentを付与することで、AOPのコンポーネントとして登録され、横断的に注入することが可能になる。

## @Before
Adviceと呼ばれる。
注入したメソッドのどのタイミングでAspectを呼び出すかを指定する。
AfterとかAfterThrowingとかいろいろある。

## within(...)
PointCutと呼ばれる。
注入するメソッドの条件。
[Spring AOP ポイントカット指定子の書き方について](https://qiita.com/rubytomato@github/items/de1019aeaaab51c8784d)  

## JoinPoint
注入されたメソッドに関する情報が格納されているクラス。
ChromeでSSL警告を表示しないようにする

開発時にlocalhostや127.0.0.1などのアドレスで、httpsな環境にアクセスした際に、ChromeのSSL証明書警告を表示しないようにする方法を調べました。

Chromeから以下のURLにアクセスする。

[chrome://flags/#allow-insecure-localhost](chrome://flags/#allow-insecure-localhost)

※Edgeの場合は下記
edge://flags/#allow-insecure-localhost

一番上にある
「Allow invalid certificates for resources loaded from localhost.」の項目をEnableに変更

画面下に再起動のボタンが表示されるので、クリックしてchromeを再起動
スライスのレシーバの挙動

スライスの先頭要素に値を追加するレシーバを作成する際に、ポインタ関連で詰まったので、その時の失敗例と成功例、その理由を書いておく。

# やりたかったこと

以下のように、スライスの先頭に値を追加するレシーバを作成したい。

```go
type Numbers []int

func (numbers Numbers) AddToHead(num int) {
    // 省略
}

func main() {
    nums := Numbers{0}
    fmt.Println(nums) // [0]
    nums.AddToHead(5)
    fmt.Println(nums) // [5 0]
}
```

# 失敗例

## パターン1

```go:パターン1
package main

import "fmt"

type Numbers []int

func (numbers Numbers) AddToHead(num int) {
	numbers = append(append(numbers[:0], num), numbers[0:]...)
}

func main() {
	nums := Numbers{0}
    fmt.Println(nums)
	for i := 1; i < 5; i++ {
		nums.AddToHead(i)
        fmt.Println(nums)
	}
}
```

これを実行すると

```:出力結果
[0]
[1]
[2]
[3]
[4]
```

となってしまう。

### 理由

`AddToHead()`内で、以下の処理が行われているため、上記の結果が出力される。

1. 値レシーバなので、`nums`が`numbers`にコピーされる。この時、`&nums != &numbers`だが、内部の要素は参照渡しとなるため、`&nums[0] == &numbers[0]`。
2. `append(numbers[:0], num)`が実行され、`numbers[:0]`の隣、すなわち`numbers[0]`に`num`が追加される。この時点で、`nums[0] = num`となる。
3. `append(append(numbers[:0], num), numbers[0:]...)`が実行されるが、この後実行される処理は`numbers`を対象に行われており、`numbers`とアドレスが違う`nums`は影響を受けない。

上記の処理により、`nums[0] = num`に書き換えが行われただけで、`nums`に追加処理がされていないため、上記のような出力が得られる。

## パターン2

```go:パターン2
package main

import "fmt"

type Numbers []int

func (numbers Numbers) AddToHead(num int) {
	tmp := append(Numbers{num}, numbers[0:]...)
	numbers = append(numbers[:0], tmp...)
}

func main() {
	numbers := Numbers{0}
    fmt.Println(numbers)
	for i := 1; i < 5; i++ {
		numbers.AddToHead(i)
        fmt.Println(numbers)
	}
}
```

これを実行すると

```:出力結果
[0]
[0]
[0]
[0]
[0]
```

となってしまう。

### 理由

`AddToHead()`内で、以下の処理が行われているため、上記の結果が出力される。

1. 値レシーバなので、`nums`が`numbers`にコピーされる。この時、`&nums != &numbers`だが、内部の要素は参照渡しとなるため、`&nums[0] == &numbers[0]`。
2. `tmp := append(Numbers{num}, numbers[0:]...)`が実行され、新たに`Numbers{num}`を生成し、それに`numbers`の要素をコピーして追加する。
3. `numbers = append(numbers[:0], tmp...)`が実行されるが、この処理は`numbers`を対象に行われており、`numbers`とアドレスが違う`nums`は影響を受けない。(この処理が行われた時点で、`numbers[0]`のアドレス、すなわち`nums[0]`のアドレスも失われたので、このレシーバ内からは`nums`に干渉できない。)

上記の処理から、`nums`に対して何も行われないため、上記のような出力が得られる。

# 成功例

以上の失敗から、原因を考えた結果できた成功例。

```go:成功例
package main

import "fmt"

type Numbers []int

func (numbers *Numbers) AddToHead(num int) {
	tmp := append(Numbers{num}, (*numbers)[0:]...)
	*numbers = append((*numbers)[:0], tmp...)
}

func main() {
	numbers := Numbers{0}
    fmt.Println(numbers)
	for i := 1; i < 5; i++ {
		numbers.AddToHead(i)
        fmt.Println(numbers)
	}
}
```

これを実行すると、

```:出力結果
[0]
[1 0]
[2 1 0]
[3 2 1 0]
[4 3 2 1 0]
```

の出力が得られ、目的を達成していることがわかる。

失敗例のパターン2から「**値レシーバからポインタレシーバに変更**」のみ変更を加えたもの。

### 理由

`AddToHead()`内で、以下の処理が行われているため、上記の結果が出力される。

1. ポインタレシーバなので、`nums`のアドレスが`numbers`にコピーされる。
2. `tmp := append(Numbers{num}, (*numbers)[0:]...)`が実行され、新たに`Numbers{num}`を生成し、それに`(*numbers)[0:]`の要素をコピーして追加している。`nums`と`numbsers`が同一のアドレスなため`nums[0:]`の要素を追加していることになる。
3. `numbers = append(numbers[:0], tmp...)`が実行され、`numbers`の先頭に`tmp`の要素を追加する。この処理は`numbers`を対象に行われているが、同一アドレスの`nums`も変更されている。

上記の処理から、`nums`に値が追加され上記のような出力が得られる。
AvahiもResponderも要らない。そう、systemdならね

このフレーズはAppleのCMに使われていないらしいですね。
# TL;DR
systemd-networkd＆systemd-resolvedなマシンにこいつを置いてみろ：

```systemd.unit:/etc/systemd/dnssd/ssh.dnssd
[Service]
Name=%H ssh daemon
Type=_ssh._tcp
Port=22
```
詳しくは[`man 5 systemd.dnssd`](https://www.freedesktop.org/software/systemd/man/systemd.dnssd.html)。以上終わり！

# 詳説
systemd-resolved(8)がmDNSだけではなく[DNS-SDも吹けるようになりました](https://www.freedesktop.org/software/systemd/man/systemd.dnssd.html)。[NEWS](https://github.com/systemd/systemd/blob/master/NEWS)によれば、version 236にて
>systemd-resolved's gained support for registering DNS-SD services on the local network using MulticastDNS. Services may either be registered by dropping in a `.dnssd` file in `/etc/systemd/dnssd/` (or the same dir below `/run`, `/usr/lib`), or through its D-Bus API.

とあるのでこれ以降のバージョンであればおそらく使えます。

さて、注意深いあなたは`/etc/systemd/dnssd/`に突撃する前にsystemd-networkd(8)の設定を確認しましょう。目的のネットワークを構成するユニットファイルに`MulticastDNS=true`をセットし、systemd-networkdを再起動させてください。すでに有効になっていればそのままでOKです。

なお、この時注意する必要があるのはIPv6環境でカスタムカーネルを用いている人はsystemd-networkdをリスタートするとリンクローカルアドレスでしかアクセスできなくなる危険があることです。これは[カーネルコンフィグで`CONFIG_IPV6_MULTIPLE_TABLES`が`N`になっているとICMPv6 Router Solicitationの送信に失敗する](https://github.com/systemd/systemd/issues/2365)という問題らしく、（それが本質的解決かどうかはさておき）こいつを有効にしてカーネルをリビルドすれば問題は起きなくなります。

上記の例では、SSHサーバを手動設定するファイルを設置しています。サービスタイプについては[公式リスト](http://www.dns-sd.org/servicetypes.html)を参照して記述しましょう。追加の説明書きとかを一緒に配りたい場合は、ポート番号の次に`TxtText=説明書き`と付けてあげればこれも一緒に吹きます。2バイト文字も行けるはず。ちなみにmanpageでは`TxtData=データ名=base64エンコードした文字列`なるデータ貼付法も書かれていますが、例えばアイコン配ったらホスト一覧画面で使ってくれる仕組みとかどっかにあるんでしょうかね。

なお、例に登場した`%H`はsystemd.unit(5)で使える、自マシンのホストネームを表す表現ですが誤って`%h`と書くと"Invalid slot."という謎のエラーが出るので確実に大文字としましょう。~~私はこれのために半年くらいフイにしました~~

#というわけでGoodbye, Avahi!
まあデーモン同士で直接連携する仕組みとかはまだまだ追いつかないようですから、ユニットファイルの手書きを強いられるのは仕方ないところですが。
今後のNetatalkとかSambaとかがD-Bus経由でサクッと吹くようになることを期待しましょう。
UnityでTHETA Vを操作するときの注意点（UnityWebRequest）

# はじめに
- UnityでTHETA V操作アプリを作成しようとしたところ変なところで引っかかったのでメモ

# 現象
- UnityWebRequestでTHETA V（v2.41.1）を操作しようとしたところ以下の問題が起きた
    - GETは成功する
    - POSTがAndroid（Galaxy8、OculusGo）で失敗する（Macでは動作）
        - 失敗時は、Request Time Outになる
   
# 原因
- UnityWebRequestのPOST実行時、Android版はヘッダに「Expect: 100-continue」が付くため

# 対策
- 「Expect: 100-continue」を外す
    - UnityWebRequest.useHttpContinue = false を設定

# 実際のコード

```c#:ThetaAccessControl.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using System;
using System.Text;
using System.IO;


public class ThetaAccessControl {

	public string baseUrl = "http://192.168.1.1";

    public int requestTimeout = 5;

    void Start() {
    }
 
    public IEnumerator Get(string url, string key, UnityAction<string, string, byte[]> action, UnityAction<string, UnityWebRequest> error) {
        var request = UnityWebRequest.Get(url);
        request.timeout = requestTimeout;

        // リクエスト送信
        yield return request.SendWebRequest();
 
        // 通信エラーチェック
        if (request.isNetworkError) {
            if (error != null) {
                error(key, request);
            }
        } else {
            if (request.responseCode == 200) {
                if(action != null) {
                    byte[] results = request.downloadHandler.data;
	    			action(key, url, results);
                }
            } else {
                if (error != null) {
                    error(key, request);
                }
            }
        }
    }
    public IEnumerator Post(string url, string bodyJsonString, string key, UnityAction<string, string, byte[]> action, UnityAction<string, UnityWebRequest> error) {
        var request = new UnityWebRequest(url, "POST");
		if (bodyJsonString != "") {
	        byte[] bodyRaw = Encoding.UTF8.GetBytes(bodyJsonString);
	        request.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
		}
        request.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
        request.SetRequestHeader("Content-Type", "application/json");
        request.timeout = requestTimeout;
        request.useHttpContinue = false;

        yield return request.SendWebRequest();

        if (request.isNetworkError) {
            if (error != null) {
                error(key, request);
            } 
        } else {
            if (action != null) {
                string result = request.downloadHandler.text;
                byte[] resultByte = request.downloadHandler.data;
                action(key, result, resultByte);
            }
        }
    }
}
```


# 参考
- http://d.hatena.ne.jp/naga_sawa/20101114/1289709797

# 備考
- これって、、、
Swift TableViewでの選択データ取得につきまして

はじめまして。プログラミング初心者です。初めての投稿です。

SwiftにてUiTableViewを用いている場合のデータの取得に関する質問です。

iPhoneのカレンダーのアプリにて新しいイベントを作成するページにある機能なのですが、イベントの繰り返しを変更する際に、ディフォルトのNeverをタップすると新しいページが開きます。
そのぺージにて選択を変更すると、選択されたセルのデータが次のページにて表示されます。


これはどのように設定すればよいのでしょうか。
セグエでもなさそうですし、セルにはUILabelではなく UItextviewを用いるのではと思いますが、どのようにデータを扱うのかよくわかりません。
また、選択したセルのデータをどのように取得し、どのタイミングで最初のページに転送しているのかも不明です。

以下にてスクリーンショットを添付します。

サンプルのコードを頂ければ助かります。

お手数ですが、よろしくお願いします。

<img width="414" alt="IMG_0963.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/280684/bfccbc79-c0c2-7f2d-1f42-ccc07f99a80d.jpeg">
<img width="414" alt="IMG_0964.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/280684/eba49c0a-ba8b-9e1a-84ae-1f7458cde688.jpeg">
<img width="414" alt="IMG_0965.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/280684/7f338757-9f80-5b22-f9df-4a1fc41da5e5.jpeg">
Keras+Tensorflow で猫の毛色分類（サビ猫は雑誌の表紙を飾ったのか？）4

### もくじ
1. [学習用画像を集める](https://qiita.com/piroyon/items/cd61a35f85519ac1d57e)
2. [猫のご尊顔を検出](https://qiita.com/piroyon/items/3ece37d9111529e3b941)
3. [学習](https://qiita.com/piroyon/items/b3822e4e6d329f793061)
3. **猫雑誌の表紙画像を集めて判定（ココ）**

## いったれ！
1. 学習用画像を集める
2. 猫のご尊顔を検出

に従って、猫雑誌の表紙画像を集めて、顔を検出した。
まず表紙
![スクリーンショット 2018-09-03 15.16.58.jpg](https://qiita-image-store.s3.amazonaws.com/0/45576/0501d30f-b02d-d44b-ff9f-0060988dc2cc.jpeg)

そして、こう
![スクリーンショット 2018-09-03 15.18.51.jpg](https://qiita-image-store.s3.amazonaws.com/0/45576/f1874c38-d76c-c33e-b137-3b94553a8f26.jpeg)


「3」で作ったベストモデルを使って判定。
シェルのfor文で、ご尊顏ファイルを引数に与えて使うスクリプト。
元データのディレクトリ構成からカテゴリ名を取ってて、ディレクトリ名をベタ書き...（catimages）

```py:test.py
import training as train  #import 3.'s training.py
import sys, os
from PIL import Image
import numpy as np

if len(sys.argv) <= 1:
  quit()

image_size = 160
source_dir = "catimages"
categories = [name for name in os.listdir(source_dir) if name != ".DS_Store"]

X = []
for file_name in sys.argv[1:]:
  img = Image.open(file_name)
  img = img.convert("RGB")
  img = img.resize((image_size, image_size))
  in_data = np.asarray(img)
  X.append(in_data)
X = np.array(X)
model = train.train(X.shape[1:])
model.load_weights("./snapshot/cat-bestmodel.hdf5")
predict = model.predict(X)

for i, pre in enumerate(predict):
  y = pre.argmax()
  print(sys.argv[i+1], categories[y])
```

国内雑誌の猫顔、385枚、海外雑誌の猫顔、313枚、
サビ猫（tortie）と判断されたのは・・・
####それぞれ一枚づつ

![jpt.jpg](https://qiita-image-store.s3.amazonaws.com/0/45576/6ddf5da1-4cea-4795-9775-fc7c11a790e0.jpeg)
![Clipboard.jpg](https://qiita-image-store.s3.amazonaws.com/0/45576/5b6ab650-1eab-bedb-6ca7-a7d459c67b6c.jpeg)

誤判定... orz 　（まぁ、ざっと見てもサビ猫表紙の雑誌はありませんでした...）
　　皆もっとサビ猫を愛そう

おしまいニャー

####おまけ　
日本雑誌
![jp2.png](https://qiita-image-store.s3.amazonaws.com/0/45576/533d0057-4eed-5f8d-53b4-6fc4e0aaeadd.png)

海外雑誌（ビビッドな文字色が多いためか、calico は誤判定が多かったです...）
![us2.png](https://qiita-image-store.s3.amazonaws.com/0/45576/69eabafe-f3b0-3dd4-9c6c-722fb88bb5fd.png)
Keras+Tensorflow で猫の毛色分類（サビ猫は雑誌の表紙を飾ったのか？）2

### もくじ
1. [学習用画像を集める](https://qiita.com/piroyon/items/cd61a35f85519ac1d57e)
2. **猫のご尊顔を検出（ココ）**
3. [学習](https://qiita.com/piroyon/items/b3822e4e6d329f793061)
3. [猫雑誌の表紙画像を集めて判定](https://qiita.com/piroyon/items/d1c6da27ff3f01504039)

## 猫のご尊顏を検出
「1」で集めた画像を何も考えずKerasに突っ込んだら、画像の水増ししても accuracy 0.5 ほど。
ぐぬぬ...
　　　「そーだ！画像から猫だけ検出しよう！猫でない画像も弾かれるはず！」
　そこでとても有名なこの記事、素晴らしいです。

- [ねこと画像処理 part 2 – 猫検出 (モデル配布)](https://rest-term.com/archives/3131/)

配布いただいているモデルと検出のプログラムを使い、猫のご尊顏が検出された領域をクリップして保存した。

- imagefilename：入力画像ファイル
- cascadefilename：上記でお配りいただいているOpenCVで読める学習済モデル.xmlファイル(cascade.xml)

検出条件は全てデフォルト、保存領域は検出結果より縦横10%づつ増量した（次の画像水増しで動かすため）。
下記のコードは、ご尊顏検出とクリップ・保存部分のみ。
呼び出しやらディレクトリ名やらなんやらよろしく追加改造する必要あり。

```Python
    import sys
    import cv2 as cv

    def detect(imagefilename, cascadefilename) :
       srcimg = cv.imread(imagefilename)
       filename, ext = os.path.splitext(os.path.basename(imagefilename))
       cascade = cv.CascadeClassifier(cascadefilename)
       objects = cascade.detectMultiScale(srcimg)
       i = 0
       for (x, y, w, h) in objects:
           nx = int(x - round(w / 10))
           if (nx < 0):
               nx = 0
           ny = int(y - round(h / 10))
           if (ny < 0):
               ny = 0
           nw = int(w + 2*(round(w / 10)))
           nh = int(h + 2*(round(h / 10)))
           detectedimg = srcimg[ny:(ny+nh),nx:(nx+nw)]
           newfilename = filename + '_' + str(i) + ext
           cv.imwrite(newfilename, detectedimg)
           i+=1
```
こんな感じになった（黒）。
![スクリーンショット 2018-08-30 9.57.13.jpg](https://qiita-image-store.s3.amazonaws.com/0/45576/c88b27a8-76a9-4ef2-7c5d-c5b6d2350cc7.jpeg)
草やら靴やら虚無やら、誤検出が1/4くらい。
明らかに猫でないものはFinder上でアイコンを見ながらざっと削除した。
毛色14種類、元画像はそれぞれが600枚ほど、ご尊顏検出結果がほぼ半分、誤検出を捨てたら200〜250枚づつくらい。
次はいよいよ学習。
M5Burner for macOS

# M5Burner for macOS (Python 2.7, Python 3.6, 3.7)

M5Stack.com にて M5Stackにファームウェアを書き込むツール M5Burner for Windows が公開されていますが、macOS用に欲しくなったのでスクリプトを書きました。

M5Stack.comからM5Burner-for-windows-v.0.0.x.zipをダウンロードて解凍したのち、firmwareフォルダと同じディレクトリに以下のスクリプトを配置して実行してください。

```python:m5burner.py
#!/usr/bin/env python
# -*- Coding: utf-8 -*-

from __future__ import print_function
import os, sys
import json
import subprocess
port = '/dev/cu.SLAB_USBtoUART'
baud = 921600
PYTHON_VERSION = os.sys.version_info[0]

# ----- read firmware.json -----
working_dir = os.getcwd()
sub_dir     = 'firmwares'
json_file   = os.path.join(working_dir,sub_dir,'firmware.json')
with open(json_file, 'r') as f:
     fw_list = json.loads(f.read())

# ----- select firmware to write -----
fw_names = [x['name'] for x in fw_list]
for i,x in enumerate(fw_names):
    print(i, x)
try:
    num = int(input('Select No = '))
    if not ( 0 <= num < len(fw_list) ):
        print('Error !')
        exit()
except ValueError:
    print('Error !')
    exit()

path = os.path.join(working_dir, sub_dir, fw_list[num]['path'])
table = {'%port':port, '%baud':str(baud), '%PATH':path, '\\':'/'}
cmds  = ['esptool.py --chip esp32 --port %port --baud %baud erase_flash']
cmds += ['esptool.py ' + x for x in fw_list[num]['commands']]
cmd   = '\n'.join(cmds)
for k,v in table.items():
    cmd = cmd.replace(k,v)

# ----- write firmware -----
if PYTHON_VERSION == 3:
    q = input('Write firmware: {0} (y/n) '.format(fw_list[num]['name'])).lower()
elif PYTHON_VERSION == 2:
    q = raw_input('Write firmware: {0} (y/n) '.format(fw_list[num]['name'])).lower()
    cmd = cmd.encode('ascii').replace('\\','/')

cmds = cmd.split('\n')
if q == 'y':
    for cmd in cmds:
        subprocess.call(cmd.split())

exit()
```

エラー処理とか、手抜きです。

- Python 2.7.15とPython 3.6.6で作動確認しました。
- あらかじめesptoolが導入されている必要があります。

### 参考
- [M5Burnerを使ってみる|スイッチサイエンス マガジン](http://mag.switch-science.com/2018/08/30/m5burner_try/) 
- [M5Stack.com](http://www.m5stack.com)

### 追記
- よく確認したら解凍したzipファイルの各ディレクトリに書き込み用のflash.shファイルがあるじゃないですか！スクリプトを書く必要が無かった。orz
- でもボーレートが間違って961200になっている箇所があるので良しとしよう。
validate時にselectボックスで値を保持する

# 値を保持する方法

validateがかかった時にselectボックスからユーザーが選択していた値を保持するには
基本的には下記のような記述でOK

```
= f.select :fruit, options_for_select([りんご,なし], selected: ticket.fruit), class: "input-item",:prompt => "開始時間"
```

ただ、時間などは値が変換されて返ってくるので上記のように書いても値が適用されない。
strftimeで変換して上げる必要がある。
そのままだと初期状態がnilでエラーになるのでtryをつけるとうまくいきます。

```
= f.select :event_time, options_for_select([12:00,13:00], selected: ticket.event_time.try(:strftime,'%H:%M')), class: "input-item",:prompt => "開始時間"
```

#参考記事

https://qiita.com/yuch_i/items/7deeb7a887ffdfaf916f
Simulator TimeoutでCarthage Updateできないとき

# Problem
iOS12対応のためにXcode10で作業しているとき、一部のライブラリがcarthage updateできなかった。
しかもwatchos向けにbuildしようとしたときだけ。

```
Build Failed
	Task failed with exit code 70:
	/usr/bin/xcrun xcodebuild -workspace /Users/shindyu/Workspace/XXX/Carthage/Checkouts/SWXMLHash/SWXMLHash.xcworkspace -scheme SWXMLHash\ watchOS -configuration Release -derivedDataPath /Users/shindyu/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10L221o/SWXMLHash/4.7.1 -sdk watchsimulator -destination platform=watchOS\ Simulator,id=3E26C69E-5E99-48A1-868C-95261A5D167A -destination-timeout 3 ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES build (launched in /Users/shindyu/Workspace/XXX/Carthage/Checkouts/SWXMLHash)

This usually indicates that project itself failed to compile. Please check the xcodebuild log for more details: /var/folders/p7/2x9v0r4n6cjb0fgcd6fclx0wrwbn7c/T/carthage-xcodebuild.KfccMG.log
```

どうやらwatchosのsimulator起動でタイムアウトしている。

# Solution
```xcrun simctl list```コマンドでsimulatorの確認。

```
$ xcrun simctl list

~~
-- watchOS 5.0 --
    Apple Watch - 38mm (3E26C69E-5E99-48A1-868C-95261A5D167A) (Shutdown) (unavailable, device type not supported by runtime)
    Apple Watch - 42mm (17EFF65A-C34B-496C-B4DD-8D3806E1855F) (Shutdown) (unavailable, device type not supported by runtime)
    Apple Watch Series 2 - 38mm (816BA81A-61A3-4B8C-90D2-16EB12A64FB9) (Shutdown)
    Apple Watch Series 2 - 42mm (63841123-B3F7-49F4-9B0A-CE2AB4F26CB3) (Shutdown)
    Apple Watch Series 3 - 38mm (BD311133-ACC3-4294-84DF-7E6D2BB22C67) (Shutdown)
    Apple Watch Series 3 - 42mm (68D82F7F-955D-4BA3-B7A7-7A9DDD1EC188) (Shutdown)
```

```xcrun simctl delete unavailable``` コマンドでunavilableなsimulatorを全削除

```
$ xcrun simctl delete unavailable
-- watchOS 5.0 --
    Apple Watch Series 2 - 38mm (816BA81A-61A3-4B8C-90D2-16EB12A64FB9) (Shutdown)
    Apple Watch Series 2 - 42mm (63841123-B3F7-49F4-9B0A-CE2AB4F26CB3) (Shutdown)
    Apple Watch Series 3 - 38mm (BD311133-ACC3-4294-84DF-7E6D2BB22C67) (Shutdown)
    Apple Watch Series 3 - 42mm (68D82F7F-955D-4BA3-B7A7-7A9DDD1EC188) (Shutdown)
```

これでcarthage update成功しました！　誰かの助けになれば幸いです。
kivyで全画面表示にする


kivy.graphicsでごにょごにょしたけどうまくいかなかった。

## kivy.core.window

```python

from kivy.core.window import Window
Window.fullscreen = True
```

全画面にすると抜けれないので、別の端末からsshして、killする感じにはなります。
[How do I exit KIVY fullscreen? \- Raspberry Pi Forums](https://www.raspberrypi.org/forums/viewtopic.php?t=146737)
Raspbian Liteでビルド済みのOpenCVパッケージを使うための依存パッケージいろいろ

Raspbian Liteでビルド済みのOpenCV 3.xパッケージ（正確に言うとPythonパッケージ）を使おうとしたら地味に辛かったのでメモしておきます。

良い子はおとなしくOpenCV 2.4でも使ってなさいってことなのか。

GUIつきのRaspbianまたは普通にインストールしたUbuntuなどではここまで面倒ではないと思います。

contribにある二値化処理アルゴリズムを試したかっただけなのに。コマンド一発の代償は大きいのかどうか。

**Python以外からOpenCVを使わない**、という前提です。C++でやりたい人は素直にコンパイルしましょう。

## ビルト済みパッケージのインストール

下記のPythonパッケージをインストールするとcontribつきのOpenCVバイナリがついてきます。
おもちゃのついたラムネ菓子、いわゆる食玩みたいなものです。

```
$ pip install opencv-contrib-python
```

または

```
$ pip install opencv-contrib-python-headless
```

Pythonから使う場合は以下のように。

```
import cv2
```

と、いいたいところですがまあ動かないでしょう。おそらく。

Raspbian Liteの場合は必要なパッケージがインストールされておらず、APT経由でないので自動的にはインストールされません。

## エラーと対応するパッケージ名のリスト



実際はいろいろとライブラリが見つからないというエラーが表示される。

カッコ内はソースからビルドするときに必要になりそうなパッケージ。

### HDF5

```
ImportError: libhdf5_serial.so.100: cannot open shared object file: No such file or directory
```

-> libhdf5-100 (libhdf5-serial-dev)

### HarfBuzz

```
ImportError: libharfbuzz.so.0: cannot open shared object file: No such file or directory
```

-> libharfbuzz0b (libharfbuzz-dev)


### WebP

```
ImportError: libwebp.so.6: cannot open shared object file: No such file or directory
```

-> libwebp6 (libwebp-dev)

### Jasper

```
ImportError: libjasper.so.1: cannot open shared object file: No such file or directory
```

-> libjasper1 (libjasper-dev)

### ???

```
ImportError: libImath-2_2.so.12: cannot open shared object file: No such file or directory
```

-> libilmbase12 (libilmbase-dev)

### OpenEXR

```
ImportError: libIlmImf-2_2.so.22: cannot open shared object file: No such file or directory
```

-> libopenexr22 (libopenexr-dev)

### Gstreamer

```
ImportError: libgstbase-1.0.so.0: cannot open shared object file: No such file or directory
```

-> ibgstreamer1.0-0 (libgstreamer1.0-dev)

### FFmpeg関連

```
ImportError: libavcodec.so.57: cannot open shared object file: No such file or directory
```
-> libavcodec-extra57 (libavcodec-dev)

```
ImportError: libavformat.so.57: cannot open shared object file: No such file or directory
```
-> libavformat57 (libavformat-dev)

```
ImportError: libswscale.so.4: cannot open shared object file: No such file or directory
```

-> libswscale4 (libswscale-dev)

### Gtk3

```
ImportError: libgtk-3.so.0: cannot open shared object file: No such file or directory
```

-> libgtk-3-0 (libgtk-3-dev)

### Qt関連

`headless`の場合は不要。

```
ImportError: libQtGui.so.4: cannot open shared object file: No such file or directory
```

-> libqtgui4 (libqt4-dev)



```
ImportError: libQtTest.so.4: cannot open shared object file: No such file or directory
```

-> libqt4-test



#### コピー用のリスト

```
sudo apt install libhdf5-100
sudo apt install libharfbuzz0b
sudo apt install libwebp6
sudo apt install libjasper1
sudo apt install libilmbase12
sudo apt install libopenexr22
sudo apt install libgstreamer1.0-0
sudo apt install libavcodec-extra57
sudo apt install libavformat57
sudo apt install libswscale4
sudo apt install libgtk-3
sudo apt install libgtk-3-0
sudo apt install libqtgui4
sudo apt install libqt4-test
```

## まとめ

需要があるのか著しく疑問ですが、せっかくなので。

不足があったらコメントで指摘してもらえると（どこかの誰かが）助かります。
URLのパラメータを抜き出してCookieにセットするコード

<!--
特定のURLパラメータの値をCookieを利用することによりページをまたいでブラウザに覚えさせるコード。
例えば、WebページをTwitterで宣伝するとき、URLに特定のパラメータを付与して投稿し、このコードをランディングページで動作させることにより、ランディングページ以外でもTwitterから来たユーザー限定で任意のJavaScriptコードを発動させる等の使い方ができる。

## URLのパラメータを抜き出してCookieにセットするコード

下の例ではURL内のパラメータ`pid`を抜き出してCookieに`query_pid`という名前で設定している。
また、Cookieはドメインレベルで90日間の有効期間で設定している。
これらの設定を必要に応じてお好みで変更して使用する。

### コード
```js:setCookieFromQ.js
/**
 * URLから指定したクエリの値を取得してCookieにセットするコード
 */
!function(){
  /**
   * URLから取得するクエリの名前を指定するための変数
   * @type {string}
   */
  var queryName = 'pid';

  /**
   * 作成するCookieの名前を指定するための変数
   * @type {string}
   */
  var cookieName = 'query_'+queryName;
  
  /**
   * 作成するCookieの生存期間を秒数で指定する変数
   * @type {number}
   */
  var maxAge = 90 * 24 * 60 * 60;
  
  /**
   * URLから指定したクエリの値を取得する関数
   * @param {number} q - 値を取得するクエリの名前を指定
   */
  var queryVal = function(q){
    var ret, param;
    var s = document.location.search;
    if(!!s){
      param = s.substring(1).split('&');
      for(var i=0,len=param.length; i<len; i++){
        if(!param[i].indexOf(q+'=')){
          ret = param[i].split('=')[1];
          break;
        } 
      }
    }
    return ret;
  }(queryName);

  // 指定したクエリの値を取得できたとき、これをCookieにセットする
  if(typeof queryVal !== 'undefined'){
    document.cookie = cookieName + '=' + queryVal + '; path=/; max-age=' + maxAge + ';';
  }
}();
```

もしサイトの常時SSL化（常にHTTPSで通信する設定）が完了しているのであれば、最後のコードを以下のように変更する。

```js:
  // 指定したクエリの値を取得できたとき、これをCookieにセットする
  if(typeof queryVal !== 'undefined'){
    document.cookie = cookieName + '=' + queryVal + '; path=/; max-age=' + maxAge + '; SameSite=None; secure;';
  }
```

**理由** ：[「Chrome 80」でのクッキー（Cookie）の心構え 〜 SameSite属性・Secure属性 〜 - Qiita](https://qiita.com/emacs_hhkb/items/ff6af4361b8a10f781a9)

### 動作例
コードを動作させてデベロッパーツールでCookieを確認してみると、
URL内のパラメータ`pid`の値を抜き出してCookieに`query_pid`という名前で保存されていることが確認できる。
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/103957/15c0a8dc-c363-e523-231c-b1fd5b9bda92.png)

## 指定のCookieの値を抜き出すコード
以下のようなコードでCookieにセットしたコードを読み出せる。
### コード
```js:getCookie.js
(function(){
  /**
   * 値を取得するCookieの名前を指定するための変数
   * @type {string}
   */
  var cookieName = 'query_pid';
  var cookies = document.cookie.split(';');
  for(var i=0; i<cookies.length;i++){
    if(!cookies[i].trim().indexOf(cookieName)){
      return cookies[i].split('=')[1].trim();
    }
  }
  return undefined;
})();
```
### 動作例
指定したCookie`query_pid`の値を抜き出せたことが確認できる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/103957/8a5670af-db03-a1fc-ac39-aa241fd467ed.png)

## 関連記事

- [目的のクエリパラメタの値を取得するコード - Qiita](https://qiita.com/aqril_1132/items/541340a0bd8c4c930e08)
- [JavaScriptの文字列マッチングまとめ(indexOf, lastIndexOf) - Qiita](https://qiita.com/aqril_1132/items/9f69575bfbcf24bdf7b5)
- [Cookieをオブジェクト形式で取得するJavaScriptコード - Qiita](https://qiita.com/aqril_1132/items/925a7cb04276d9f916d7)

-->
S3のオブジェクトをSSLで公開するには

# S3とSSL通信
企業などでホワイトリストで内部からアクセス可能なドメインを制限している場合、動的なWebサイトからS3の動画オブジェクトなどにリンクを張っていてもはねられてしまって表示できないケースがある。この場合、オブジェクトのURLを許可されたドメイン内に設定する必要があり、S3をWebサイトホスティングを有効にしたうえでDNSのゾーン設定でCNAMEしてやれば一応は対応可能だ。

しかし、S3の仕様でWebサイトホスティングドメインはSSLには非対応（2018年9月現在）になっている(※こちらを参照 [S3のSSL通信]
(https://qiita.com/Yuhkih/items/1754ac9caf3f12d75946) )

問題なのは、参照元のWebサービスがSSLアクセスの場合、chromeでは「保護された通信」から「保護されていない通信」へのリンクが記述されたページとして認識されてしまい、最悪そのままではページ自体が表示されないというケースがあることだ。

また、chromeが2018年10月から生のhttpアクセスを許可しなくなる、ということでS3からオブジェクトをSSLで呼び出す必要も出てきそうだ。

以下、自分のための作業メモ。

# 証明書の取得
ここはDNSのzoneファイルを書き換えできることを前提と考えて、DNS認証でACMから証明書を取得しよう。
以前のまとめを参照されたい。([ACMの証明書をメール検証からDNS検証に差し替えた話](https://qiita.com/Hide-Aoki/items/1cb65bed6ee37bed3027 ) )

ここでの留意点が、**リージョンをバージニア北部**にしておくこと。
CloudFrontが証明書を利用するにはバージニア北部に置かれていることが必要なためだ。ここが第一のハマりポイントだった。


#S3の設定について
これはデフォルトの設定で（非表示のままで）全く問題ない。
テスト用にindex.htmlを置く場合、バケット全体を公開するか、公開用rootフォルダを設定するかここで決めておく。自分はバケット全体を公開範囲にしたので、バケットの/にindex.htmlを置くことにした。

Webホスティング設定などは**不要**

バケット名は
（公開用サブドメイン名）.(メインのドメイン名）としておくと後でわかりやすい。

例: **movie.hogehoge.jp**

リージョンはどこでもよい。自分は普通に東京リージョンにした。

#CloudFrontの設定

CloudFrontのダッシュボードを開き、Create Distributionsをクリック
![CloudFront1.png](https://qiita-image-store.s3.amazonaws.com/0/264001/85090045-c2a4-8f88-1513-4a7236ff08fe.png)

次にweb distributionを選択
![CloudFront2.png](https://qiita-image-store.s3.amazonaws.com/0/264001/c682d5c0-8b19-14d5-a7ec-e471c107f647.png)


#####Distributionの諸元を設定
![CloudFront3.png](https://qiita-image-store.s3.amazonaws.com/0/264001/2ed5f220-8438-75f5-9b31-e29c72d6cfbd.png)

①S3のエンドポイント
②公開のルートにするフォルダを指定
 今回はバケット丸ごと公開するので何も入力しなかったが、**/root**のように絞り込むこともできる。
③　①+②がIDとして自動入力される。変更する必要はない。
④S3のバケットにアクセスする事を指定
⑤S3にアクセスするIAMを新規に生成する
⑥公開するバケットのポリシーに⑤で生成したIAMでアクセスできるように設定する。
⑦クライアントからHTTPがきたら、HTTPSに変換する。



![CloudFront4.png](https://qiita-image-store.s3.amazonaws.com/0/264001/18508a56-3daa-969f-e20a-6108d600da1c.png)
⑧CNAMEで設定するサブドメイン名を記入する。
⑨ACMで取得した証明書を使用する。
　使用可になった状態の証明書があれば、ここのリストボックスに出てくる。はずだが、**証明書のリージョンを間違えていると出てこない。**



![CloudFront5.png](https://qiita-image-store.s3.amazonaws.com/0/264001/1baa1911-7266-2951-15d8-38f63d63881b.png)
⑩確認用のサンプルhtmlのファイル名を指定する。
⑪このボタンを押してDistributionを作成する。

#####CloudFrontのダッシュボード
![CloudFront6.png](https://qiita-image-store.s3.amazonaws.com/0/264001/b2661864-b4b7-56ff-1019-07b78be32e4c.png)
⑫**DNSのゾーン設定でIN CNAMEするエンドポイント**がここに表示される。
⑬Enabledになるまでしばし待つ。


#DNSのゾーン設定

証明書の認証時に編集したzoneファイルをもう一度編集する。参照→[ACMの証明書をメール検証からDNS検証に差し替えた話](https://qiita.com/Hide-Aoki/items/1cb65bed6ee37bed3027 )
ここでも**IN CNAME**を使用してサブドメインをCloudFrontのエンドポイントに紐づける。

指定したいサブドメインがMOVIE、エンドポイントがxxxxxxxxxxxxxx.cloudfront.netであった場合、
`MOVIE IN CNAME xxxxxxxxxxxxxx.cloudfront.net.`
と表記する。
エンドポイントの最後にピリオドを付け忘れると相対指定になってしまうので、必ずつけてFQDNにすること。
※ここが今トピック第2のハマりポイントだった。

以上。
Linuxカーネルをソースコードからビルドする(CentOS 7)

# CentOS 7のカーネルをソースコードからビルドする
## この記事について
この前、素人ながらLinuxカーネルモジュールを修正する事になりました。なんとなく難しい気がして、もう一層Linuxカーネルそのものをビルドしようっと**間違った道**に走ってしまい…

結局、今は欲しいモジュールだけをビルドして使ってますが、後で役に立つかもしれないので~~立って欲しくないですが~~ソースコードを探す所からの過程をまとめてみました。

※多くの場合、**カーネルをソースコードからビルドしてまで使う必要はない**と思います。凄く手間のかかる作業なので本当に必要なのかもう一度考えてみましょう。

## ビルドに必要なパッケージをダウンロードする

`yum`で`Development Tools`をインストールします。`apt-get`の`build-essential`みたいに関連ツールを一括ダウンロードしてくれます。

```
$ sudo yum groupinstall "Development Tools"
```

カーネルをビルドする時必要なツールです。

```
$ sudo yum install rpm-build redhat-rpm-config asciidoc hmaccalc perl-ExtUtils-Embed pesign xmlto
$ sudo yum install audit-libs-devel binutils-devel elfutils-devel elfutils-libelf-devel java-devel
$ sudo yum install ncurses-devel newt-devel numactl-devel pciutils-devel python-devel zlib-devel
```

私の場合、`net-tools`と`bc`も要求されました。

```
$ sudo yum install net-tools bc
```

## ソースコードを手に入れる
CentosのWikiを参考しました[^1]。ソースコードはSRPM(Source RPM)を利用してダウンロードします。SRPMファイルは以下のURLからダウンロードできます。`{バージョン}`の所は欲しい数字に変えてください。
http://vault.centos.org/{バージョン}/os/Source/SPackages/
http://vault.centos.org/{バージョン}/updates/Source/SPackages

カーネルをビルドする時は一般ユーザーモードからすることが勧められているそうです[^2]。ユーザーに変更しましょう。

```
$ su user
```
ソースコードをダウンロードするディレクトリを作ります。

```
$ mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
$ echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros
```
srpmファイルをインストールします。

```
$ rpm -i http://vault.centos.org/7.3.1611/os/Source/SPackages/kernel-3.10.0-514.el7.src.rpm 2>&1 | grep -v exist
```

`rpmbuild`を使ってソースコードを得ることができます。パッチを当てたい場合kernel.specを修正する必要があるみたいです。

```
$ cd ~/rpmbuild/SPECS
$ rpmbuild -bp --target=$(uname -m) kernel.spec
```
ソースコードが`~/rpmbuild/BUILD/kernel*/linux*/`ディレクトリに展開されます。

## ビルド

`~/rpmbuild/BUILD/kernel*/linux*/`で作業します。
installでは`root`権限が必要なので`root`になるか`sudo`を使う必要があります。

一旦、初期化します。

```
$ make mrproper
```
設定ファイルを生成します。

```
$ make menuconfig
```

ビルドします。これからの作業はかなり時間が掛かります。必ず`-j`オプションを与えましょう。

```
$ make
```
モジュールをコンパイルします。

```
$ make modules
```
コンパイルされたモジュールを`/lib/modules`にインストールします。

```
$ make modules_install
```
コンパイルされたカーネルをインストールします。

```
$ make install
```

## 確認

起動するカーネルを確認します。インストールしたカーネルになっていると思います。

```
$ grub2-editenv list
```

現在利用できるカーネルのリストは以下のコマンドでみれます。`grub2.cfg`ファイルの名前は違う場合がありますので失敗する場合は`/etc`の下でそれっぽいファイルを探しましょう。

```
$ awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg
```

新しいカーネルで起動して欲しくない場合デフォルトを変えます。上で出力された数字かフルネームを使って指定できます。

```
$ grub2-set-default {上で出力された番号もしくは名前}
```

## 注意
- 本文の中では通り過ぎましたが`make menuconfig`には注意すべきだと思います。例えば、カーネルの名前を認識して動作するプログラムはしばしばありますので`make menuconfig`で設定するローカルネームは大事かもしれません。

[^1]: https://wiki.centos.org/HowTos/I_need_the_Kernel_Source
[^2]: http://www.owlriver.com/tips/non-root/
JSのheadObjectで期待したレスポンスが取得できない時

普通にコード書いてたらハマる人が多いのではないかと寄稿します。

# ハマった経緯

S3上のファイルの存在確認や、サイズ確認でgetObjectを利用するのは無駄ですので、headObjectを使いたいところです。

ところが[ドキュメント](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#headObject-property)に従って実装しても、Content-Length等のレスポンスが返ってきません。

HEADメソッドは200を返しているし、Response HeaderにもContent-Lengthは取得できています。でも上記メソッドのレスポンスにContent-Lengthはありません。

？？？

こんな時はだいたいIAMが悪さしてるのかと権限を見直しても問題なし。
バケットポリシーか？と疑って見ても問題なし。
CORS設定でもちゃんとHEADは許可している。

これaws-sdkのバグじゃないの、、、わしもう知らん、、、と心が折れかけたところで同僚が

つ　https://github.com/aws/aws-sdk-js/issues/631

と出してくれました。

# 解決策

```xml
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <MaxAgeSeconds>300</MaxAgeSeconds>
        <ExposeHeader>Content-Length</ExposeHeader>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>
```

ExposeHeader...だと、、、！！

pythonのSDKでは問題なく動いていたので、JS動かないのはJSのバグだ、と思いたくなっていたんですが、そうか、CORSなら納得だ、、、

SDKのドキュメントにもExposeHeaderについて記載しておいて欲しいなぁ、、と思った一幕でした。
CentOS7.5にMySQLインストール&CRUD権限付与

MySQLのインストールってどうやるんでしょうか。。状態からスタート。

#目的
AWSのEC2で作成したインスタンスにMySQLをインストールします。
ユーザを作成してCRUD権限を付与するテストも行います。

#環境
Centos7.5系
MySQL5系
macOS 10系


#MySQLのインストール
[このサイト](https://qiita.com/tech31/items/97b94fed3192b09ac5a9)に倣って作業を行います。
インスタンスはAWS MarketplaceからCentOS7を選択し作成したのでmariaDBがデフォで存在、手順に則って削除しています。
rootユーザのpass設定まで実施しインストール完了。
以下は私の環境での作業ログです（rootユーザで作業しているのでsudoは不要）。

```
# rpm -qa | grep maria
mariadb-libs-5.5.56-2.el7.x86_64

# yum remove mariadb-libs
# rm -rf /var/lib/mysql

# rpm -Uvh http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
# yum install --enablerepo=mysql57-community mysql-community-server
# mysqld --version
mysqld  Ver 5.7.24 for Linux on x86_64 (MySQL Community Server (GPL))

# systemctl enable mysqld
# systemctl is-enabled mysqld ※自動起動の状態であるかを確認するコマンド
enabled

# systemctl start mysqld
# systemctl status mysqld

# grep 'temporary password' /var/log/mysqld.log 
2018-11-07T05:09:56.133511Z 1 [Note] A temporary password is generated for root@localhost:パスワード
# mysql -uroot -p
Enter password: 

mysql> alter user 'root'@'localhost' identified by 'MyNewPass4!';
mysql> select host, user from mysql.user;
+-----------+---------------+
| host      | user          |
+-----------+---------------+
| localhost | mysql.session |
| localhost | mysql.sys     |
| localhost | root          |
+-----------+---------------+
3 rows in set (0.00 sec)
```

#ユーザ作成、CRUD権限付与

```
mysql> create user ユーザ名 identified by 'パスワード';
```

今回作成したユーザは「特定データベースの全テーブルにCRUD権限を付与」だったので以下のコマンドを投入。権限の反映も行います。

```
mysql> grant select, insert, update, delete on `DB名`.* to 'ユーザ名'@'%';
mysql> flush privileges;

```

>参考にしたサイト
>https://www.karakaram.com/mysql-user-grant
>https://qiita.com/FumiyaShibusawa/items/2e3b30ceedeafff0bce2

#所感
SQLってなんで大文字なの？をググったところ好みの回答がありましたので共有。
クックパッドの勉強会はエンジニアの方がとても能動的＆出てくる食事がバリウマ（クックパッド専属シェフ？のお手製）と聞いています。自分の目的とマッチした際に参加してみたいですね。

>https://techlife.cookpad.com/entry/2016/11/09/000033

#エラー（11/7追記）
久しぶりにインストール作業を行ったらエラーメッセージが。

```
Downloading packages:


Error downloading packages:
  1:perl-Pod-Simple-3.28-4.el7.noarch: [Errno 5] [Errno 12] メモリを確保できません
  〜省略〜
  perl-Pod-Perldoc-3.20-4.el7.noarch: [Errno 5] [Errno 12] メモリを確保できません
```

メッセージそのままでEC2インスタンスのメモリ不足（t2.micro）かな？と思いt2.mediumにスケールアップしたらあっさり解決しました。
メモリを増加するんじゃなくてインスタンスタイプを変更する、って考えなんですね。
>https://qiita.com/copei/items/bb09d61a53514e028260


#使ったコマンド

```
・バージョン確認
mysql -V

・ログイン
mysql -u root(もしくはユーザ名) -p

・ＤＢ作成
create database データベース名

・ＤＢ一覧
show databases

・ＤＢログイン
use データベース名

・ユーザの新規作成
create user ユーザ名 identified by 'パスワード'

・ユーザ権限の変更
grant select, insert, update, delete on `DB名`.* to 'ユーザ名'@'%'

・ユーザ権限の確認
show grants for 'ユーザ名'

・ユーザ一覧
select host,user from mysql.user

・テーブル一覧
show tables

・カラム一覧
desc テーブル名
```
Xcode + Git：プロジェクト作成後にリモートリポジトリを後から設定する

#背景
Bitbucketを試したくて、Xcodeでテスト用プロジェクトを作成。
うっかり初期設定でローカルリポジトリを作成してしまった。
Xcode内でリモートリポジトリを後から設定できるのか、少し迷ったのでメモ。

※前提として、リモートリポジトリにはREADME.mdファイルだけ存在する状態

#手順
1.ソースコントロールナビゲーターで右クリックして、「Add Existing Remote」
<img width="337" alt="スクリーンショット 2018-09-04 11.00.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/23789/b44147e9-fa01-2440-8aac-b52aa93202ef.png">

2.「Add an existing remote:」
<img width="510" alt="スクリーンショット 2018-09-04 11.09.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/23789/ddfebf35-02b4-4c2b-501a-1c2de4a5c8aa.png">
「Remote Name」は「origin」が設定されているはず。
「Location」はリモートリポジトリのパスを入力する。

3.ソースコントロールナビゲーター内の「Remotes」ツリーに「origin」が追加される
<img width="223" alt="スクリーンショット 2018-09-04 11.11.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/23789/b828bbd8-09f6-0342-6b3e-97324d052167.png">

4.Pushすると「The local repository is out of date」で怒られた
<img width="457" alt="スクリーンショット 2018-09-04 11.09.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/23789/824646dd-8019-84a5-8545-c1a3d34c2521.png">

今考えると、このときの状態はローカルとリモートでコンフリクトが起きている状態なので、
Pushできなくて当然か。

5.「Source Control > Fetch and Refresh Status」する
<img width="321" alt="スクリーンショット 2018-09-04 11.15.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/23789/03b29485-d460-15e9-1b1e-339ddd33acf4.png">

コミットメッセージには以下のような内容が記載される。
「Merge remote-tracking branch 'refs/remotes/origin/master'」

6.最後にPush。問題なければ、リモートリポジトリにはローカルのソースコードが追加されているはず

「Fetch and Refresh Status」は、Xcode9で追加された機能のようだ。
CircleCI Local CLIをHomebrewでインストールする

# 概要
表題の通りです。

[CircleCIのDocs](https://circleci.com/docs/2.0/local-cli/)にはcurlでダウンロードする方法が書いてありますが、実はHomebrewにformulaが存在するようなので、Homebrewを用いてインストールすることもできます（2018/09/04現在）。
特に複雑な手順もないのですが、書き残しておきます。

## 追記（2018/09/04 11:27）
普通に以下に書いてありましたね...🙈
https://circleci.com/docs/2.0/local-cli/#alternative-installing-on-macos-via-homebrew

# 手順
当然ですが、`brew`コマンド（Homebrewを操作するコマンド）を事前に導入しておいてください。

## 1. Homebrewでインストールする
普通にHomebrewでコマンドをインストールします。

```bash
brew update
brew install circleci
```

## 2. circleciコマンドをアップデートする
homebrewでインストールできるコマンドは、大抵バージョンが古くなっているので、`circleci update`コマンドを用いてアップデートします。

```bash
circleci update check
#=> A new release is available (0.1.1973)
#=> You are running 0.1.1430
#=> You can update with `circleci update install`

# 上記の出力に倣ってアップデート版をインストール
circleci update install
```

これで完了です。

# 参考
- [Using the CircleCI Local CLI - CircleCI](https://circleci.com/docs/2.0/local-cli/)
- [Homebrew について > パッケージ管理システム Homebrew \- Qiita](https://qiita.com/b4b4r07/items/6efebc2f3d1cbbd393fc#homebrew-%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)
【Win10】NetBeansでJSFの開発環境を構築する

## 背景
今までJavaは触ったことなかったのですが、突然JSF触ることになったので入門してみました
せっかくなのでやったことのメモをアウトプットしていこうと思います

まずは開発環境の構築についてメモっておきます

## 道のり
Step1 JDKをインストールする
Step2 PATHの編集
Step3 NetBeansをインストールする
Step4 プロジェクトを作ってみる

## Step1 Javaをインストールする
以下のサイトからJDKをダウンロードします
[Java SE Development Kit 8 Downloads](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)

このときJava SE 10ではなく、**Java SE 8**をダウンロードしてください
最新の10の方をインストールするとNetBeansをインストールするときにエラーが出てしまいます
こいつのおかげで30分無駄に・・・

ダウンロードが完了したらインストーラに従って進めば大丈夫です

## Step2 PATHの編集
「コントロールパネル」→「システムとセキュリティ」→「システム」の「システムの詳細設定」を開きます
「環境変数(N)...」ボタンをクリックすると環境変数の設定画面が開きます

「システム環境変数」の中に「Path」という変数があるので、編集ウィンドウから新規ボタンを押してJDKをインストールした場所のbinディレクトリのパスを追加します
例：```C:\Program Files\Java\jdk1.8.0_181\bin```

コマンドプロンプトを立ち上げて正しくPATHが通っているか確認します
```javac```と入力して以下のように表示されればOK

```
>javac
使用方法: javac <options> <source files>
使用可能なオプションには次のものがあります。
  -g                         すべてのデバッグ情報を生成する
  -g:none                    デバッグ情報を生成しない
  -g:{lines,vars,source}     いくつかのデバッグ情報のみを生成する
  -nowarn                    警告を発生させない

~中略~

  -J<flag>                   <flag>を実行システムに直接渡す
  -Werror                    警告が発生した場合にコンパイルを終了する
  @<filename>                ファイルからの読取りオプションおよびファイル名
```

次に```JAVA_HOME```という変数をシステム環境変数に新規追加します
値はJDKをインストールした場所のパスになります
例：```C:\Program Files\Java\jdk1.8.0_181```

こちらも再度コマンドプロンプトを立ち上げて正しく設定されているか確認します
```set JAVA_HOME```と入力して以下のように表示されればOK

```
>set JAVA_HOME
JAVA_HOME=C:\Program Files\Java\jdk1.8.0_181
```

## Step3 NetBeansをインストールする
以下のサイトからインストーラーをダウンロードします
[NetBeans IDE ダウンロード](https://netbeans.org/downloads/?pagelang=ja)

ダウンロードバンドルにいくつか種類がありますが、今回は「Java EE」をダウンロードしました
ダウンロードが完了したらインストーラーを起動します

Java SE 8がインストール済みでPATHの設定が正しくできていればインストーラーに従って問題なくインストールできると思います

## Step4 プロジェクトを作ってみる
* カテゴリは「Java Web」、プロジェクトは「Webアプリケーション」を選択して次へ
![jsf1.PNG](https://qiita-image-store.s3.amazonaws.com/0/34870/c2173f33-3315-d89c-0950-65114ad3e090.png)
* 名前は「jsf-sample」にしました
* サーバーと設定はデフォルト
* フレームワークは「JavaServer Faces」を選択
![001.JPG](https://qiita-image-store.s3.amazonaws.com/0/34870/f908f287-e3e0-bf4a-f4bc-c128e2a8ff41.jpeg)
このとき下のようにチェックが入っていない状態で終了するとJSFが選択されないので注意
![jsf2.PNG](https://qiita-image-store.s3.amazonaws.com/0/34870/24e38ed8-6433-a725-c25d-3033ee7268a8.png)
* プロジェクト名を右クリックして「実行」をクリック
![003.JPG](https://qiita-image-store.s3.amazonaws.com/0/34870/bd6a5d27-4bc3-d744-0a56-c463e8ed6d97.jpeg)

* ブラウザが立ち上がり```index.html```の内容が表示されます
![002.JPG](https://qiita-image-store.s3.amazonaws.com/0/34870/a857bccb-56f3-4caf-8b5e-ed3946ec9ed1.jpeg)

と、無事に画面が表示されたところで開発環境構築メモはここまで
AWS WAFがログ出力対応したけどハマった部分を書いておく

# Kinesis Fire Firehose を作ったけど選べない
ACLをGlobalに作成した場合は、バージニア北部にFirehoseを作る。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/164582/6b7b8834-c838-eb35-6e6d-122ccb4f64f5.png)

ACLを東京に作成した場合は、東京にFirehoseを作る。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/164582/18501208-0fd0-66ea-0797-abcfb8de0e34.png)
MyBatis3でINSERT時の自動採番されたIDを取りたい

tl;dr
------------

- AUTO INCREMENTやシーケンスなどで自動採番されたID値は、`useGeneratedKeys="true"`を使ったり、`<SelectKey>`でSQLを実行したりすると取得できる
- ID値は`keyProperty`の値を基に、**引数に渡したオブジェクトに対して**マッピングされる
- 戻り値の数値は「Insertした件数」や「Updateした件数」となる。（**IDではない**）


背景
------------

Insertによって生成されたIDを使い、色々したいことは間々あります。

調べると出ますが、どのようにして得られるのかを書いてなかったり、戻り値で得るみたいな記事を見かけたりして混乱したのと、ドキュメントにはちゃんと書いてあるけど、MapperのXMLしか出てなくて、コードでイメージできなかったので。
http://www.mybatis.org/mybatis-3/ja/sqlmap-xml.html#insert_update_and_delete

以下のstackoverflowの投稿でやっと使い方を理解できた。問題解決能力の低さよ。
https://stackoverflow.com/a/20954027



不明点
------------

- IDを得る方法は引数のオブジェクトにマッピングさせるしかない？（個人的には戻り値にしたい。）


実例
------------

以下のようなClass,Interface,MapperXMLを用意します


``` java:User.java
package jp.co.neosystem.fukasawah.myapp.db.entity;

public class User {
	long id;
	String name;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
```

``` java:UserMapper.java
package jp.co.neosystem.fukasawah.myapp.db.mapper;

import jp.co.neosystem.fukasawah.myapp.db.entity.User;

public interface UserMapper {
	/* Userクラスを引数に取るようにする。IDをマッピングするため必要 */
	int insert(User user);
}

```

``` xml:UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="jp.co.neosystem.fukasawah.myapp.db.mapper.UserMapper">
	<insert id="insert" useGeneratedKeys="true" keyProperty="id">
		INSERT INTO User (NAME) values (#{name})
	</insert>
</mapper>
```

``` java:Logic.java
/* 中略 */
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setName("foo");
int count = userMapper.insert(user);

// keyProperty="id"により、setIdを使ってマッピングされる。
// そのため、user.getId() で得られる。
System.out.println("insert user (user.getId()): "+ user.getId()); 
```


`keyProperty`: 今回は`id`を指定する。（MyBatisはこの値を見て`User#setId`を使うことを決定し、IDを設定する）



以上。
bootstrap3のmodalがAndroidでジャギーが出た時の対応

![スクリーンショット 2018-09-04 10.10.42.png](https://qiita-image-store.s3.amazonaws.com/0/65643/96e6418c-0c01-0673-ea15-8c3a7100d07d.png)

Bootstrap3使用。Androidで特定の条件のときにmodalに不自然なジャギーが発生した。

どうやらbox-shadowが描画に問題が起きるらしいので、表示に差し支えないのであれば、

```
.modal-content {
    box-shadow: none!important;
}
```
とでもしてやれば改善できるようです。
TO_CHARにTO_DATEを重ねる意味

# TO_CHARの結果に対してTO_DATE？？

SQLを見ていたら以下ような文を見つけました。

```sql

TO_DATE(TO_CHAR(sysdate, 'MM/DD/YYYY'), 'MM/DD/YYYY')
```

最近SQLを始めたばかりなので、何のことか分からず調べて見ました。
すると、[ここ](https://community.oracle.com/thread/342445)に解説が載っていました。

```sql
SQL> select SYSDATE mydate from dual;

MYDATE
---------
14-NOV-05

SQL> alter session set nls_date_format = 'MM/DD/YYYY';

SQL> select SYSDATE mydate from dual;

MYDATE
----------
11/14/2005

SQL> select TO_DATE(TO_CHAR(sysdate, 'MM/DD/YYYY'), 'MM/DD/YYYY') mydate from dual;

MYDATE
----------
11/14/2005

```

環境変数を使わずにDATEをフォーマットする方法みたいですね:relaxed:
私のようなSQL初心者が調査に困らないように記事にしました:spy:
おしゃれなMarkdown対応wiki : Growiを構築運用する

ローカルで運用できる，Wikiをずっと探していたのですが，`Growi`が非常に使いやすくてUIもオシャレなので，今回はDockerを使って導入・運用をDocker初心者が行って行きます．

![growi.png](https://qiita-image-store.s3.amazonaws.com/0/152224/83cab0c8-1434-0369-3e98-08e9a5606c0f.png)


[Growi | Official Page](https://growi.org)

# 導入
GitHubにdocker-compose版が公式に公開されているので，それをcloneする．

```bash
$ git clone https://github.com/weseek/growi-docker-compose.git
```

## 公開するような設定
デフォルトでは，`localhost`でしか動作しないように`docker-comopose.yml`が記述されているので，

```yml
services:
  app:
    ports:
      - 127.0.0.1:3000:3000
```

の部分を

```yml
services:
  app:
    ports:
      - 3000:3000
```
に変更しておくと，そのサーバのIPアドレスでGrowiにアクセスが可能になる．

## ファイルのアップロード設定
デフォルトでは，AWSでの運用が想定されているので，`docker-compose.yml`の`FILE_UPLOAD=local`を有効にする．

```yml
environment:
  - MONGO_URI=mongodb://mongo:27017/growi
  - ELASTICSEARCH_URI=http://elasticsearch:9200/growi
  - PASSWORD_SEED=changeme
  - FILE_UPLOAD=local    # activate this line if you use local storage of server rather than AWS
  # - MATHJAX=1            # activate this line if you want to use MathJax
  # - PLANTUML_URI=http:// # activate this line and specify if you use your own PlantUML server rather than public plantuml.com
```

## 起動

```bash
$ docker-compose up -d
```

![growi login.png](https://qiita-image-store.s3.amazonaws.com/0/152224/d097fa8d-136c-407d-042a-f16c630c7ed0.png)


# バックアップ

## Database
growiに必要なコンテナを全て起動した状態で，

```bash
$ docker run -it --rm --link growi_mongo_1 --network growi_default --volume $(pwd):/backup mongo bash -c "mongodump -v --host growi_mongo_1 --db growi --out /backup"
```

これで，カレントディレクトリの直下に`/growi`ディレクトリが生成されます．  
中には，ユーザ情報や記事情報が保存されています．

## Uploaded Files
アップロードファイルは，growiのコンテナIDをdocker psで調べて，

```bash
$ docker cp {growiのコンテナID}:/data .
```

これで，カレントディレクトリの直下に`data`ディレクトリが生成されます．  
中には，アップロードファイルが保存されています．

## PASSWORD_SEEDの取り出し
パスワードハッシュ用の環境変数`PASSWORD_SEED`を取得しておかないと，移行先のgrowiを初回起動したときに，自動生成されログインできなくなります．私は，`docker-compose.yml`に値を設定しているのでそれを用います．  

# リストア
バックアップで生成した`/growi`を用いて．

```bash
$ docker run -it --rm --link growi_mongo_1 --network growi_default --volume $(pwd):/backup mongo bash -c "mongorestore -v --host growi_mongo_1 --db growi backup/growi"
$ docker-compose restart
```

ファイルも同じように`/data`を用いて．

```bash
docker cp ./data {growiのコンテナID}:.
```

以上で私の場合は復旧できました!!
VagrantとDockerの使い分けについてまとめてみた


# Vagrantで実装する利点

* 素直な仮想マシン
  * 中身はVirtualBOXの仮想マシン
  * 実機で操作する感覚で対応できる
* 複数サービスを一手に管理
  * 起動時、複数のサービスを同時に立ち上げられる
  * サービスだけ再起動でき(OSの再起動不要)、他のサービスに影響が出ない(依存関係に依る)
  * docker-composeを使えばいいじゃんと意見もあるが、サービスの再起動に結局マシンを再起動するのと同じくらいの時間がかかってしまう
* 開発時には心強い
  * 特に、複数のサービスを組み合わせる or その間に自分で開発したサービスやアプリを組み込む時
  * dockerは手軽だが、1サービス1コンテナという成約があり、さらに自動的に起動したサービスが停止するとコンテナごと止まる弱点がある
      * サービスの再起動にコンテナ再起動と同じ時間がかかる
      * Vagrantならサービスだけ再起動できる
* 実機へのデプロイを実験するならこちらが便利

# Dockerで実装する利点

* 手軽
* 複数サーバを同時に立ち上げる感覚で操作できる
  * docker-composeを使えばなおさら
* サービスを立ち上げるのに最適化されている
* 本番環境で管理しやすい
* 同じポート番号を扱うサービスを複数抱えているなら検討の価値ある

# VagrantとDockerの使い分け

* 開発時はVagrantで行い、本番環境ではdockerでデプロイ
  * デプロイ先がDocker対応してるなら
* 同じポートを利用するサービスが複数あるならDockerでの開発も検討
* 実機へのデプロイのときはVagrantが便利