OmniAICreator/Qiita-1.07M huggingface dataset:
fluentdで転送するデータを整形する

# 概要

fluentd経由でElasticsearchにログデータを送信しようとしたところ、dateのフォーマットが正しくなくてエラーになった。

```
Could not push log to Elasticsearch: {
  "took" => 3, "errors" => true, "items" => [{
    "index" => {
      "_index" => "maroidx", "_type" => "activity_log", "_id" => "AV-e-Ur1Cjl2zC9FVgdv", "status" => 400, "error" => {
        "type" => "mapper_parsing_exception", "reason" => "failed to parse [timestamp]", "caused_by" => {
          "type" => "illegal_argument_exception", "reason" => "Invalid format: \"2017-11-09 13:08:42\" is malformed at \" 13:08:42\""
        }
      }
    }
  }]
}
```

ログに出力される"timestamp"のフォーマットが

```
%Y-%m-%d %H:%M:%S
```

これに対してElasticsearchのdateフォーマットは半角スペースNG(だったはず)なので

```
%Y-%m-%dT%H:%M:%S
```

こういう形に変えたい。

# 間にプラグインを挟む
[fluent-plugin-record-reformer](https://github.com/sonots/fluent-plugin-record-reformer)というgemを使わせていただいて整形することにした。

```
<match activitylog>
  @type record_reformer
  output_tag reformed.activitylog
  timestamp ${DateTime.parse(timestamp).strftime('%Y-%m-%dT%H:%M:%S')}
</match>

<match reformed.activitylog>
  @type elasticsearch
  host 192.168.1.3
  port 9200
  index_name maroidx
  type_name activity_log
</match>
```

"timestamp"はふつうのString型なので、一旦 DateTime.parse してあげているところがポイント。
ジェネリックなリスト生成についての備忘録

コメントをいただきました。
以下のソースを書いていたのですが非常にまずかったようです。

```csharp:ダメな例。

private List<T> MakeList<T>(int maxRow)
{
    Type type = typeof(T);
    var entity = Activator.CreateInstance(type) as T;

    var list = new List<T>();

    for (int i = 0, i < maxRow; i++)
    {
        list.Add(entity);
    }

    return list;
}
```

>この書き方は、極めて良くないと思います

>まず、var entity = Activator.CreateInstance(type) as T;の部分ですが、Tが引数無しのコンストラクタ>が定義されていない場合、MissingMethodExceptionが飛んでくることになります。

>また、list.Add(entity);としてますが、コレは結局最初作成したインスタンスの参照をすべて持たせることに>なるので、値型と、参照型で挙動に差が生まれることになり、良くないかと。

　　
で、コメントからソースそのまま引用。

```csharp:new制約

  public static List<T> BuildList<T>(int maxRow) where T : new()
    {
        if(maxRow<0) throw new ArgumentOutOfRangeException(nameof(maxRow));

        var list = new List<T>(maxRow);

        for (int i = 0; i < maxRow; i++)
        {
            list.Add(new T());
        }

        return list;
    }
```
　　
まずLINQ使えばこんなメソッドいらなかったらしい・・・

```csharp:LINQ
var list = Enumerable.Range(0, 10).Select(i => (x:i, y:i + 10)).ToList();
```

　　
また、Activator.CreateInstanceやnew T()などについて調べました。

**Activator.CreateInstance**
　[Acitivator.CreateInstanceメソッド](https://msdn.microsoft.com/ja-jp/library/system.activator.createinstance(v=vs.110).aspx)
　→引数なしコンストラクタのパラメータを使う前提のようです。

　尚、速度的にはActivator.CreateInstanceとnew()で大差ないようで、
　というのもnew T()も実は裏でActivator.CreateInstanceを使っているらしい。
　ジェネリックで速度を出したければ式木が必要との事。
　(といっても劇的に速くなるわけでもない)

　この辺もいずれまとめようかと思います。

　　
**where句について**
　Tに対して、```where T : new() ```とすることで、
　『引数なしのコンストラクタを持つT』の制約が付けれるようです。
　これでコンパイルエラーにより、
　Exceptionを未然に防げるセーフティな実装になるんですね。
　[型パラメータの制約](https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters)
　
 　また、引数ありのコンストラクタ制約をつけたい場合はサポートされていない為、
　これまた式木使って自前の制約を作る必要があるようです。~~式木難しいよね・・・~~

　　
個人的には勉強になりましたがなんとも
お粗末な記事になりました・・・

---
参考：
[.NET TIPS　文字列で指定したクラスのインスタンスを作成するには？](http://www.atmarkit.co.jp/fdotnet/dotnettips/386createinstance/createinstance.html)
[インスタンス生成あれこれ ](http://tawamuredays.blog.fc2.com/blog-entry-91.html)
[インスタンスの生成速度 - Qiita](https://qiita.com/Temarin/items/d6f00428743b0971ec95)
DMM.com Advent Calendarが生まれた経緯

普段DMM.comラボでコードを書いている @usagi-f です。
DMMでは今年はAdventCalendarにチャレンジしてみようということになりました。

初日であるこの記事では、カレンダーが生まれた背景を簡単に紹介させてもらいます。DMMの開発者たちの日常が少しでも垣間見えればと思います！

**カレンダーのURLはコチラ**
[DMM.com #1 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/dmm)
[DMM.com #2 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/dmm2)

# 経緯

## 爆誕

弊社には社員の提案を自由に書くことができる掲示板のようなものが存在しており、日々いろいろなアイデアが投稿されています。ある日とあるエンジニアからAdventCalendarを作りませんか？という提案がありました。

通常は投稿されたアイデアはエライ人たちのところへ持っていかれて「やろう！」とか「ちょっと保留にしておこう」といった判断をしてもらうのですが、それを待たずとも**有志で初めてしまってもいいのでは？**という声があがり、その**25分後にカレンダーが爆誕**していました。

<img src="https://qiita-image-store.s3.amazonaws.com/0/69809/4c770a27-eddf-bc1d-fc20-afca17dd7e63.png" width=550>

[DMMアカデミーの記事](http://dmm-academy.com/2017/05/17/helloworld/)にもあったDS方式とはまさにこのことです。

以下引用

>## DS方式
考えても分かりませんでした。
twitterフォロワー数325人の私には、経験がなさすぎて分からない。

>だからDOします。

>そして、SORRYします。

>考えて考えたら、
行動して（DO）間違ったら謝る（SORRY）
DS方式で進めていこうと思いました。

幸いにも今回の動きには多くの人が賛同してくれました。感謝🙏

## 1つ目が埋まる

58分後。
そしてその2分後に出来る2つ目。

<img src="https://qiita-image-store.s3.amazonaws.com/0/69809/c7b74d25-5ae7-b125-be83-5208773b2135.png" width=550>

## 2つ目が埋まる

そして翌日の夜にしれっと埋まってしまいました。

<img src="https://qiita-image-store.s3.amazonaws.com/0/69809/2f5dfa86-2848-2a22-d1e9-c733868038a4.png" width=550>

# Slack Enterprise Grid

2017年現在で数千人が在籍するDMMにおいて、ここまでの動きが出来たのにはSlack Enterprise Gridが導入されていたことが大きいかもしれません。

[Enterprise Grid | Slack](https://slack.com/enterprise)
[Slack Enterprise Grid 国内初導入！全社展開における取り組みをご紹介！ - DMM inside](https://inside.dmm.com/entry/2017/11/02-dmmlabotech-slackEG)

以前は数多く存在する部署ごとにチャットが存在していましたが、Enterprise Gridへ移行することで各チーム毎の枠は残しつつも横断的なコミュニケーションが可能になります。

所属に関係なくTech系へのアンテナが高い人間が集まっているチャンネルがあり、今回そのチャンネルで呼びかけたところ上記のようにあっという間にカレンダーが生まれ、枠が全て埋まってしまいました。

# こんな人たちがいます

そんな背景があったため、参加者のバックグラウンドはバラバラです。

サーバーサイド・クライアントサイドの各エンジニアはもちろん、インフラエンジニアもいますし、ゲーム系や、ビッグデータを扱うエンジニアもいます。
新卒エンジニアも参加しており、中にはデザイナーなどの非エンジニアも今回記事を書く予定です。

DMMでは展開しているサービスが非常に多岐に渡ることから、所属している人間の持っているスキルも様々です。そんなDMMの面白いところを感じていただけたら幸いです。

**カレンダーのURLはコチラ**(再掲)
[DMM.com #1 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/dmm)
[DMM.com #2 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/dmm2)
よく忘れるssh-keygen(鍵長:4096/暗号化方式:rsa/ファイル名指定)

よく忘れるからメモ

# 参考
 - [お前らのSSH Keysの作り方は間違っている](https://qiita.com/suthio/items/2760e4cff0e185fe2db9)
 - [ssh-keygenでファイル名を指定して鍵を生成する](https://qiita.com/goldbook@github/items/575981f3ec0bc582ea24)

# コマンド
```bash
ssh-keygen -t rsa -b 4096 -C <comment(mail address)> -f ~/.ssh/id_rsa_sample

# permission
chmod 600 ~/.ssh/id_rsa_sample

# clip copy
pbcopy < ~/.ssh/id_rsa_sample.pub

# ssh agent
ssh-add ~/.ssh/id_rsa_sample

```
Rails で外部制約付きのカラムを削除する

```ruby
t.references :user, foreign_key: true, null: false
```

のように作った外部制約付きのカラムを削除する。

**環境**

- Ruby 2.4.2
- Rails 5.1.4
- MySQL 5.7.x

**Tasks テーブルの user_id を削除する場合**

```bash
$ bin/rails g migration RemoveUserIdFromTasks
```

```ruby:xxxxxxxxxxxxxx_remove_user_id_from_tasks.rb
class RemoveUserIdFromTasks < ActiveRecord::Migration[5.1]
  def change
    remove_reference :tasks, :user, foreign_key: true
  end
end
```

この状態で

```bash
$ bin/rails db:migrate
```

すればOK。
外部ライブラリをimportして実行可能な*.swiftファイルをつくる - Swift Package Manager 編


↓のものはCarthageだったが、そのSwift Package Manager (Swift 4)でのやりかた

外部ライブラリをimportして実行可能な*.swiftファイルをつくる
https://qiita.com/banjun/items/3f22b4951bca07cc55c7



次のような先頭行をもつ `main.swift` を使うと、 cloneしてきて `./main.swift` で(ビルド&)実行できる。


```swift
#!/bin/sh
":" //#; DIR=$(dirname $(readlink $0 || echo $0))
":" //#; env -i PATH=$PATH swift build --package-path "$DIR" -Xswiftc -suppress-warnings -Xswiftc -sdk -Xswiftc $(xcrun --show-sdk-path --sdk macosx) && exec "$DIR/.build/debug/bansan" "$@"
import Foundation
import SourceKittenFramework

// SourceKittenFrameworkをつかうコード
```

※実行モジュール名(Package.swiftのexecutable)が `bansan` のとき


SPMでは、メインファイルは `main.swift` で決め打ちのようで、メインのスクリプトとして他のファイル名を使うことはできない。executableのターゲットの、メインファイルではないファイルでは、トップレベルに `#!` を置くとビルドエラーになる(`Hashbang line is allowed only in the main file`)。つまり1パッケージに複数の `hoge.swift`, `fuga.swift` を置くという運用をしたい場合は、もうすこし複雑になりそう。

### 追記

iOSアプリのビルドフェーズから実行すると、環境変数に引きずられて、iPhone SDKで `swift build` してしまい失敗することがある(失敗しないこともある)。`env -i PATH=$PATH` で `PATH` 以外の環境変数をクリアし、そのような場合にも影響しないようにしている。
FFmpegを使ってHuluを保存する方法

ffmpeg を使えばHuluのリアルタイム放送をmp4ファイルに録画（保存・ダウンロード）することができる

- この記事はmacOS想定
- ffmpegさえ利用可能にすればWindowsやLinuxでも使えるのでは

# Homebrew のインストール
必須ではないが便利

```:macOS
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

# ffmpeg のインストール

```:macOS
brew instal ffmpeg
```

## インストールできたかの確認

```:macOS
ffmpeg -version
```

```
ffmpeg version N.N Copyright (c) 2000-YYYY the FFmpeg developers
```


# 録画したファイルを置く専用フォルダを用意して移動

```:macOS
$ cd Desktop
$ mkdir video
$ cd video
```

# Huluを録画する


## Chromeブラウザを開く

## デベロッパーツールを開き、Networkタブへ移動する
表示 > 開発 / 管理 > デベロッパー ツール
"Network"タブを表示する

## Huluへログインする

## 録画したいHuluのリアルタイムチャンネルを開く

```
https://www.happyon.jp/realtimes/hoge
```

## hoge.m3u8の情報を取得する

### Networkコンソールにm3u8を表示する
フィルターに``` m3u8 ```を指定すると便利

### hoge.m3u8を右クリックしてcURLを取得する
Copy > Copy as cURL

<img width="657" alt="2017-11-09_16_01_27.png" src="https://qiita-image-store.s3.amazonaws.com/0/207089/e3af0442-4cae-9832-a217-19fd3817a031.png">
※ ``` master.m3u8 ``` ではなく ``` 01.m3u ``` や ``` 02.m3u ```




### ffmpeg コマンドラインの構築に必要な情報を抽出する
コピーしたcURLは以下のようになる

```
curl 'https://hoge.akamaihd.net/hls/live/hoge/akamai/01.m3u8?hdntl=exp=hogehoge~acl=/hls/live/*~data=hdntl~hmac=hogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehoge' -H 'Origin: https://www.happyon.jp' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: ja,en-US;q=0.8,en;q=0.6' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36' -H 'Accept: */*' -H 'Referer: https://www.happyon.jp/realtimes/hoge' -H 'Connection: keep-alive' --compressed
```

### ffmpeg コマンドラインを構築する
上記の情報を以下のように再構築する

```
ffmpeg \
-headers 'Origin: https://www.happyon.jp' \
-headers 'Accept-Encoding: gzip, deflate, br' \
-headers 'Accept-Language: ja,en-US;q=0.8,en;q=0.6' \
-headers 'Accept: */*' \
-headers 'Referer: https://www.happyon.jp/realtimes/hoge' \
-headers 'Connection: keep-alive' \
-user_agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36" \
-i "https://hoge.akamaihd.net/hls/live/hoge/akamai/01.m3u8?hdntl=exp=hogehoge~acl=/hls/live/*~data=hdntl~hmac=hogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehoge" \
-codec copy \
-bsf:a aac_adtstoasc \
-movflags faststart \
video.mp4
```


## 録画する
macOSのターミナルを開き、上記コマンドを実行する。
停止するには ```q``` を押す


# 確認する
フォルダ内を覗くと
``` video.mp4 ```
ができているはず

# 高度な操作
[ffmpeg Documentation] (https://ffmpeg.org/ffmpeg.html#Options)
にたくさんオプションが説明されている
各ブラウザでWebStorage（LocalStorage）を確認する方法 

## 背景
CookieからWebStorageに移行するにあたって、ブラウザによって確認方法が異なったので作成しました。

## ブラウザ毎の確認方法

<details><summary>Chrome</summary>

1. 開発者ツール（F12）を開く
2. ApplicationタブにLocal Storageがあるので、そこで確認する
   ![image.png](https://qiita-image-store.s3.amazonaws.com/0/207298/6785f36a-5d50-7d98-bdc9-f3f20aa135ad.png)
</details>
<details><summary>FireFox</summary>

1. 開発者ツール（F12）を開く
2. ストレージタブにローカルストレージがあるので、そこで確認する
  ![image.png](https://qiita-image-store.s3.amazonaws.com/0/207298/0dcf3f89-0ed9-9f66-37e7-e81a7a355fbf.png)
  
</details>
<details><summary>IE,Egde</summary>
1. 開発者ツール（F12）を開く
2. コンソールタブを開き、画面下部にjavascriptで記述する
  例）localStorage.getItem('hogehoge');
  ![image.png](https://qiita-image-store.s3.amazonaws.com/0/207298/7d1c6522-782d-e738-881e-5cc6787db3e4.png)
</details>
<details><summary>タブレット、スマートフォン</summary>

基本的な確認はCookieの確認方法（https://appbu.jp/iphone-safari-cookie ） と同じです。
1. 適当なページにアクセスし、ブックマークを作成する
   ※ブックマークの名前はlocalStorage確認用であることが分かるような名前だとよいかも
2. ブックマークを編集し、URL欄に確認用のjavascriptを書き込む
   ex) javascript:alert(localStorage.getItem(('hogehoge'));
3. localStorageに保存されているドメインのページにアクセスし、手順1,2で作成したブックマークを開く
4. ポップアップでlocalStorageの値が表示される。

</details>

## 消し方
localStorageの消し方はChrome、FireFoxの場合は開発者ツールのGUI操作で消せます。
その他に関しては以下のjavascriptで消せます
- 特定のlocalStorageのみ削除する場合
<code>localStorage.removeItem('hogehoge');</code>
- すべてのlocalStorageを削除する場合
<code>localStorage.clear();</code>


## 余談
Cookieと違ってキー指定しないと取れないので結構めんどくさいですねー。もっと楽な方法ないかなー。
sessionStorageの場合はlocalStorageをそれぞれ読み替えてください。
[MSTest] vstest.executionengine のプロセスが終了しない

VisualStudioから陽気にテストを走らせていたところ、急にビルドに失敗するようになったり、2回目以降のテストに失敗するようになったりしたので、その対処法を残しておきます。

問題のプロジェクトでは、C++製のDLLを `DllImport` で呼び出しており、
どうやらビルド失敗はプロジェクトに含まれるコンテンツ(DLL)がビルド時に出力フォルダへコピーできないこと、
2回目以降のテストが失敗しているのは前回テスト時の情報が(DLL側に)残ってしまっていること、がそれぞれの原因でした。

タスクマネージャを見てみると vstest.executionengine.exe なるプロセスがテスト終了後にも残り続けています。
パフォーマンスを確保するため、VSはテスト構成に変更がない限りこのプロセスを再起動しないようになっているとのことです。

[テスト]>[テスト設定]>[テスト実行エンジンの実行状態を保持する] のチェックを外すことで、テスト終了時にプロセスを終了させることができました。めでたし！

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/111100/a9bf39dd-9a09-4f68-af61-48791a950184.png)
KubernetesでPodからそのホスト専用のDatadog Agentにアクセスする

## TL;DR;

iptablesでMagic IP Addressを特定のPodにDNATするか、podのspec.nodeIP+Downward APIを使う

## iptablesを使う場合

[ノードローカルなdnsmasq + Daemonset kube-dnsの事例](https://github.com/kubernetes/kubernetes/issues/7470#issuecomment-263695219)と同じようなことをDatadog Agentでもやる。

### iptablesの設定

- Datadogメトリクスを受け付けるためのdd-agentのポートは8125
- [Datadog APMトレースを受け付けるためのdd-agentのポートは8126](https://docs.datadoghq.com/tracing/#configuration)
- ZipkinスパンをDatadog APMに送りたい場合は[dd-zipkin-proxy](https://github.com/flachnetz/dd-zipkin-proxy)/zipkinの9411

```
MAGIC_IP=169.254.123.123
HOST_INTERFACE=cni0
POD_IP=10.2.91.68

curl http://$POD_IP:9411
echo $MAGIC_IP

# dd-agent (statsd)
sudo iptables -t nat -I PREROUTING --dest $MAGIC_IP -p udp --dport 8125 -j DNAT --to-dest $POD_IP:9411 -i $HOST_INTERFACE

# dd-agent (trace)
sudo iptables -t nat -I PREROUTING --dest $MAGIC_IP -p udp --dport 8126 -j DNAT --to-dest $POD_IP:8126 -i $HOST_INTERFACE

# dd-zipkin-proxy (dd-agent内包)
sudo iptables -t nat -I PREROUTING --dest $MAGIC_IP -p tcp --dport 9411 -j DNAT --to-dest $POD_IP:9411 -i $HOST_INTERFACE

```

## dd-agentやdd-zipkin-proxyはDaemonSetでデプロイする

dd-agentやdd-zipkin-proxyはそれぞれDaemonSetとしてデプロイし、`hostNetwork: true`にする。`hostPort: ...`でもいいのでは？と思うかもしれないが、そうするとdd-agentがPod名をホスト名と誤認してしまい、Datadogにhostname=pod名のメトリクスやトレースが溜まってしまう。結果的にホスト名でメトリクスやトレースを検索することができなくなってしまうので、避けたほうがいい。

## spec.nodeIPを使う場合

[ここで案内されているように、Downward APIを使えばコンテナの環境変数にNodeのIPアドレスをセットできる。](https://github.com/kubernetes/kubernetes/issues/15169#issuecomment-343965301)

アプリ側で送信先IPアドレスを環境変数で設定できるようにする。


## まとめ

Dockerコンテナからの`$MAGIC_IP`宛のパケットがホストの同ポートに転送される状態になる。`$MAGIC_IP`はアクセス元のコンテナがいるノードに読み替えられるので、Podからホスト専用のdd-agentにアクセスできることになる。

## おまけ: Kubernetesのサポートはないの?

- [Node Localサービスの提案](https://github.com/kubernetes/kubernetes/pull/28637)が出されています。2017/12/2現在はまだマージされてないので、興味のある方はぜひ応援してください。

## 参考

- [I have node-local services I want to offer to pods, e.g. DataDog, how can I do that? · Issue #15169 · kubernetes/kubernetes](https://github.com/kubernetes/kubernetes/issues/15169)
- [kube2iamのiptables自動設定](https://github.com/jtblin/kube2iam/blob/master/iptables/iptables.go#L27-L30)
ESP-IDF のインストール（Windows10 Fall Creator's Update）

## はじめに
秋月電子通商の `ESP-WROOM-32` の開発ボード [ESP32-DevKitC](http://akizukidenshi.com/catalog/g/gM-11819/) が手に入ったので，私の備忘録代わりのメモにします．タイミングが悪かったのか，`make monitor` が動作しなくて困ったので，残しておきます．また，既存の `MSYS2` に `Toolchain` を導入するドキュメント [Setup Windows Toolchain from Scratch](https://esp-idf.readthedocs.io/en/latest/get-started/windows-setup-scratch.html) がありますが，すでに `64bit(X86_64)` の `MSYS2` で環境構築されている方は，`MSYS2` の環境が二つになりますが，`all-in-one toolchain` を導入することをお勧めします．詳しい方でないと手段と目的が変わります．

## ESP-IDF の インストール
[Standard Setup of Toolchain for Windows](http://esp-idf.readthedocs.io/en/latest/get-started/index.html) の手順に沿って行うだけです．

### Toolchain のインストール
ここでは，`D` ドライブの `Programs\espidf` にインストールします．

[このページ](http://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html) から `esp32_win32_msys2_environment_and_toolchain-20170918.zip` をダウンロードして展開します．展開してできた，`msys32` を `espidf` にリネームして，`D` ドライブの `Programs` に移動する．

`D:\Programs\espidf\mingw32.exe` からターミナルを起動して，動作の確認（？）をします．

```bash
$ cc --verbose
```

### ESP-IDF のインストール
先ほど起動した，`mingw32.exe` のターミナルで，`Git` からインストールします．`Proxy` 環境の場合は，`~/.gitconfig` に `Proxy` の設定を追加します．

```bash
$ cd /opt
$ git clone --recursive https://github.com/espressif/esp-idf.git
$ cygpath -ma esp-idf （Path の確認）
$ vi /etc/profile.d/export_idf_path.sh （環境変数の追加）
```

(`cygpath -ma esp-idf|clip` でクリップボードにコピーできる．)

```export_idf_path.sh
export IDF_PATH="D:/Programs/espidf/opt/esp-idf"
```

ターミナルを開きなおして，`printenv IDF_PATH` で 環境変数が設定されていることを確認する．


### ESP32-DevKitC の設定
パソコンと `ESP32-DevKitC` を繋げてドライバがインストールされるか確認する．インストールされなければ，[ここ](https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers) から `CP210x_Windows_Drivers.zip` をダウンロードしてドライバをインストールします．

デバイスマネージャーからポートを確認する．ここでは，`COM5` とします．

### 開発環境の動作確認
`mingw32.exe` のターミナルから下記コマンド実行する．(ここでは，`/home/esp` で作業)

```bash
$ mkdir -p /home/esp
$ cd /home/esp
$ cp -r $IDF_PATH/examples/get-started/hello_world .
$ cd hello_world
$ make menuconfig
```

`make menuconfig` で設定項目が表示されるので，`Serial flasher config` → `Default serial port` を `COM5` に変更して閉じる

```bash
$ make
$ make flash (ESP32-DevKitC にプログラムを書き込む)
$ make simple_monitor
```

`simple_monitor` で動作確認を行います．うまくいかない場合はポートの設定などを見直します．

本来は，`simple_monitor` は旧来のもので，今は，`monitor` を使うのですが，`Windows10 Fall Creator's Update` 以降 `IOError` で動作しないので `D:\Programs\espidf\opt\esp-idf\tools\idf_monitor.py` の560 行目を下記のように変更します（[参考](https://github.com/espressif/esp-idf/issues/1136)）．

```
self.output.write(b)
self.matched = b'
```

↓

```
try:
    self.output.write(b)
    self.matched = b''
except:
    pass
```

ターミナルから `make monitor` で動作を確認します．すぐに修正されると思うので，現在嵌まった人向けに残しておきます．
【Android】アプリ起動時、GooglePlay開発者サービスがインストールされているかどうかチェックする方法

#事象
あるプロジェクトにて、社内のテスト端末を使用している際に、下記エラーが発生しているを発見。

```kotlin:エラー
Failed to load googlecertificates. qw:No acceptable module found. Local version is 0 and
```

#対応
自身の端末ではエラーにはなっておらず、調査してみると、
どうやらテスト端末側にGooglePlay開発者サービスがインストールされていないため、
`com.google.android.gms:play-services`は使用出来ないですよ、ってことらしい。
しかしコンソール上でエラーが吐き出されているだけで、異常終了にはならないため気づきづらい。
そこで、<b>起動時にチェックかけられたらいいんじゃない？</b>ってなり、
さらに調べてみると、以下のようにチェックが可能であることがわかった。

```kotlin:MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(null)

	setContentView(R.layout.activity_main)

	// GooglePlay開発者サービスがインストールされているかチェックする
	val api = GoogleApiAvailability.getInstance()
	val code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this)
	if (code == ConnectionResult.SUCCESS) {
		// インスール済みなので通常処理を実行
	} else {
		// インストールされていないのでダイアログを表示
		api.getErrorDialog(this, code, 0).show()
	}

}
```

インストールされていない場合は、公式に用意されている以下のダイアログを呼べばいいと思う。
`api.getErrorDialog(this, code, 0).show()`

#備考
今回はたまたま見つけたので対応しましたが、
基本的にはGooglePlay開発者サービスはインストールされている<b>はず</b>なので、
おまじない程度に起動時に書いておくのもありかなって思いました。（問い合わせとかくると面倒だし…）

Qiitaに同様の記事がなかったので自分へのメモとして記事にしてみました。
他にも同様の件で困っている方の参考になれば幸いです。
Ubuntuをインストールしてからやった設定まとめ


研究室でUbuntuを使う機会があったので、一通りやったセットアップのメモです。

### 環境
OS: Ubuntu17.04
PC: ThinkPad L560

## ディレクトリ名を日本語から英語へ変える

Ubuntuをインストールしたら、ダウンロードとかディスクトップとかのディレクトリ名が全部日本語になっているので、それだと端末で扱いにくいので英語に変更します。

```Bash
$ LANG=C xdg-user-dirs-gtk-update
```

## GoogleChromeのインストール

公式ページで、debファイルをダウンロード
https://www.google.co.jp/chrome/browser/desktop/index.html

libappindicator1というパッケージが必要なので、インストールします。

```
sudo apt-get install libappindicator1
```

その後、debファイルをダウンロードしたディレクトリに移動して、dpkgでインストールを行う。

```
sudo dpkg -i ダウンロードしたインストーラ名.deb
```

これでエラーが出なければ完了


## Atomのインストール

PPAを入れてリポジトリを追加

```
sudo add-apt-repository ppa:webupd8team/atom

sudo apt-get update
```

その後、apt-getでインストール

```
sudo apt-get install atom
```

エラーが出なければ完了

## DropBoxのインストール
UbuntuのソフトウェアセンターにDropBoxがあるので、そこでインストールする。

## Slackのインストール

公式ページでdebファイルをダウンロード
https://slack.com/downloads/linux

ダウンロードしたファイルをダブルクリックして、ソフトウェアセンター内でインストールする。



## Albertのインストール
ランチャーアプリはAlbertを使います。

「webupd8」のPPAリポジトリを追加してインストールします。

```
$ sudo add-apt-repository ppa:nilarimogard/webupd8
$ sudo apt-get update
$ sudo apt-get install albert
```

## Clipitのインストール
クリップボードマネージャ。
ソフトウェアセンターにあるので、「Clipit」で検索してインストール。

##あとがき
あらためて見るとソフトウェアセンターって便利ですね。
webpack-html-plugin + ejs で SSR する

Router未対応だが、とりあえずイニシャルページが確定的で事前にコンパイルできるケースでSSRする。

## やり方

- ejs で html をビルド時に SSR して埋めてしまう。
- その時のコンテキストは node なので babel-register を叩けば動くはず

## コード

```ejs:src/ssr/index.ejs
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <%
      require('babel-register');
      const React = require('react')
      const ReactDOM = require('react-dom/server');
      const App = require('../components/App').default;
    %>
    <div id='app-root'><%= ReactDOM.renderToString(React.createElement(App)) %></div>
    <script src="index.bundle.js"></script>
  </body>
</html>
```

```js:webpack.config.js
const path = require('path')
const webpack = require('webpack')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ENV = process.env.NODE_ENV || 'development'

module.exports = {
  entry: { /* */ },
  output: { /* */ },
  module: { /* */ },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'src/ssr/index.ejs'),
      minify: false,
      inject: false
    })
  ]
}

```

html-webpack-plugin で minify してしまうと SSR の引き継ぎに失敗するので、その点だけ注意
CognosのXQEログの出力先を変更する

##はじめに
Cognosのログは製品インストールディレクトリ配下の/logs以下に出力されますが、
ログ管理やディスク管理の面からログの出力先の変更を求められることが多々あります。

ただし、Cognos Configurationで設定できるログの出力先変更は、cogaudit.log (Cognos Aanalytics 11.0.7以降、それまではcogserver.log)のみです。
![WS000006.JPG](https://qiita-image-store.s3.amazonaws.com/0/146283/7ac6433d-2475-3903-5d9c-f69c54f830fe.jpeg)

その他のログファイルに関しては、一部、製品による自動ローテーションが実施されるものがありますが、ログの消しこみやローテーション機能の作りこみを実装する必要がありました。
特に、DQMモードを使用している際に出力されるXQEフォルダ配下のログは自動では削除されないので十分な考慮が必要でした。



今回は、そんなXQEログの出力先を変更する方法を記載します。

## 設定変更

設定する箇所は、こちら。Cognosインストールディレクトリ配下にあるファイルを編集します。
\<CA_Installdir>/configuration/xqe.config.xml




![WS000001.JPG](https://qiita-image-store.s3.amazonaws.com/0/146283/9b9b7179-58f4-04ad-3a15-4d8a054f1fc0.jpeg)



xqe.config.xmlのバックアップを取得したらファイルを開きログの出力先を変更します。
※Windows環境では、Program Files配下のファイルを直接更新できない場合があります。その場合は、編集可能な場所にコピーし編集してから元のフォルダに戻してください。

変更前
`<!--logsFolder value="../../logs"/-->`

変更後
`<logsFolder value="C:\temp\xqelogtest/logs"/>`

![WS000008.JPG](https://qiita-image-store.s3.amazonaws.com/0/146283/6b5c0a5b-5b25-20bd-9d65-4860b34258ba.jpeg)

上書き保存して、Cognosを再起動後にDQMのレポートを実行するとXQEが指定したディレクトリに出力されるようになっていることを確認できます。
![WS000005.JPG](https://qiita-image-store.s3.amazonaws.com/0/146283/0d50121b-40fe-e558-ad2c-6cbd577e9060.jpeg)



これでXQEログの出力先が変更されました。
以上になります。
CleanArchitectureにおけるInterface Adapterの役割を調べた

# 目的
Interface Adapterのコード(Presenter、Repository、Gatewayなど)は、どのような役割を負うべきかを調べる。

# 動機
ローカルとサーバーのデータベース同期ライブラリを開発していて、「どのデータベースであろうとも、アプリケーションロジックを変更する必要はない」というデータベースの独立性を持ちたかったので、CleanArchitectureの導入を考えた。

そこで[まだMVC,MVP,MVVMで消耗してるの？ iOS Clean Architectureについて
](https://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc)を参考にしながら進めていたのだが、Domain層の中にTranslatorが含まれているのに疑問を覚えた。

上の記事のサンプルコードを元に、データベースを**Realm**から**CoreData**に取り替えた場合のことを考えてみたところ、ユースケースを書き換えなければいけないことに気がついた。

以下のコードでは、ユースケースがTranslatorに依存しているので、データベースを変更した場合Translatorの別クラスを作って書き換えなければいけない。

```swift:TimelineUseCase.swift
 func loadTimelines() -> Observable<TimelinesModel> {
        let login = loginAccountRepository.getSelectedTwitterAccount()
        let accounts = socialAccountRepository.getTwitterAccounts()
        
        return Observable.combineLatest(login, accounts) { ($0, $1) }
            .flatMap { (identifier, accounts) -> Observable<TimelinesModel> in
                guard let identifier = identifier, let selectAccount = accounts.filter({$0.identifier.isEqual(to: identifier)}).first else {
                    return Observable.error(AppError.notAuthorized)
                }
                return self.timelineRepository.getTwitterTimelines(selectAccount)
                    .map(translator: TimelineTranslater()) #この部分
        }
    }
```

これは、データベースの変更によってドメインレイヤを書き換えさせられているのでおかしいのでは？と思ったため、調査をした。

# 調査
[ボブおじさんの元記事の翻訳](http://blog.tai2.net/the_clean_architecture.html)をよく読み直したところ、こう書いてあった。
(長いのでまとめまで飛ばしても可)
>**インターフェイスアダプター**
このレイヤーのソフトウェアは、アダプターの集合だ。これは、ユースケースとエンティティにもっとも便利な形式から、データベースやウェブのような外部の機能にもっとも便利な形式に、**データを変換する。**たとえば、このレイヤーは、GUIのMVCアーキテクチャを完全に内包するだろう。プレゼンター、ビュー、そしてコントローラーは、すべてここに属す。モデルは、コントローラーからユースケースに渡され、そして、ユースケースからプレゼンターやビューに戻される、単なるデータ構造である可能性が高い。

>同じように、データはこのレイヤーで、エンティティーやユースケースにもっとも便利な形から、どんな永続化フレームワークが使われているにしろ、それにとってもっとも便利な形に変換される。例えば、データベースなど。**この円よりも内側のコードは、データベースについてなにも知るべきではない。**もしこのデータベースがSQLデータベースであるならば、どんなSQLであれ、このレイヤーに、もっと言うと、このレイヤーの中のデータベースに関連した部分に、制限されるべきだ。

> また、このレイヤーには、その他すべてのアダプターもある。それらは、**外部の形式(たとえば外部サービス)から、ユースケースとエンティティーで使われる内部形式にデータを変換する**ために必要なものだ。


重要だと思った部分は以下の部分

 - ユースケースやエンティティに最も便利な形式から、データベースやウェブのような外部の機能に最も便利な形式に、データを変換する。
 - 外部の形式(たとえば外部サービス)から、ユースケースとエンティティーで使われる内部形式にデータを変換する。
 - **この円よりも内側のコードは、**データベースについてなにも知るべきではない。
→つまりInterface Adapterはデータベースについて知っていてよい

# 結論
ボブおじさんの元記事から考えると、Interface Adapterは
**単なるI/Fではなくデータ変換の責任を持っており、そのためにはデータベースに依存しても良い。**
となる。

なので、TranslatorはRepositoryが依存するようにすれば良いと思う。

同様に、ドメインモデルからUIで使うViewModelに変換を行う必要があったとすると、Presenterで変換を行えば良いと思う。
GPUで作ったpickleをCPUで使う時のTips

# 概要
研究において、GPUで学習してもらったPickleのdumpファイルはGPUで作ったPickleのファイルであるため、どうやらCPUでそのまま使えないらしい。実際にやってみたところエラーが出たので改善策をまとめておく。


このままではせっかく作ったモデルファイルで予測ができない。
よってGPUで作ったpickleのモデルファイルを使って予測を行うために自分がやったことをメモする。

# 環境
#### python => 3.5.2
#### chainer => 2.0.1

# CPU用にモデルファイルを変換
pylearn2にあるgpu_pkl_to_cpu_pklを使ってdumpファイルをcpu用に変換する。
ただし、これはどうやら実験段階にあるため、環境によってはそもそもうまくいかない場合があることに注意する。

1. Pylearn2がインストールされていない場合はインストールする(公式ドキュメントは[こちら](http://deeplearning.net/software/pylearn2/#download-and-installation))
2. Pylearn2のgpu_pkl_to_cpu_pklを使って変換を行い、保存する。

```

```

[画像]

# 変換後
変換後、予測のタスクをやってみたところしっかり予測できた。
エラーもなし。スバラシイ。


# 対策(そもそもではあるが)
そもそもGPUで保存する際にCPUで使えるように保存できないのかと思って調べてみたところ

```
model.to_cpu
pickle.dump()
```

これでchainerの場合はCPU向けのPickleにできるらしい。センセイェ...
※GPUでの学習において、このpickle.dumpをepochごとに行なっている場合は、次のepochを始める際にmodel.to_gpuをしておかないと、モデルがおかしくなるので注意が必要。

# 参考

[Pylearn2 公式ドキュメント](http://deeplearning.net/software/pylearn2/#)
[Pylearn2(Github)](https://github.com/lisa-lab/pylearn2)
[Converting a theano model built on GPU to CPU?](https://groups.google.com/forum/#!topic/torch7/i8sJYlgQPeA)
DynamoDBのAutoscalingがスケジュール対応したので試してみる【AWS CLI】 


# DynamoDB AS
DynamoDBのキャパシティの値を事前に指定した値でスケーリングさせる機能です。
現在、DynamoDBのテーブルを新しく作成するときにはdefaultで有効化にチェックが入る機能です。

# なぜ、スケジュール機能が必要？
DynamoDBのオートスケールを有効化していると、
__日中は最低値２００で使用して夜間は５０にしたい__
と言ったことを解決するには、夜間のみオートスケールを解除して・・・といった面倒な事が必要でした。

これを時限起動で出来るようになったのがスケジュール機能！

# CLI

```bash:awscli
aws application-autoscaling
```

を使用します。

- 登録: put-scheduled-action
- 確認: describe-scheduled-actions
- 削除: delete-scheduled-action

それぞれ見ていきます。

## 登録

```bash:awscli
aws application-autoscaling put-scheduled-action \
    --service-namespace dynamodb \
    --schedule "cron(01 00 * * ? *)" \
    --scheduled-action-name TestAcction \
    --resource-id table/table_name \
    --scalable-dimension dynamodb:table:ReadCapacityUnits \
    --scalable-target-action MinCapacity=10,MaxCapacity=50   
```


### schedule
cloudwatchで指定しているのと同じ指定方法です。
[ルールのスケジュール式](http://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html)

注意する点はUTCで認識されるのでそのへんは気をつけて下さい。

### start-time/end-time
その時点から有効・その時点で無効

`"2017-11-09T14:10:00+09:00"`
みたいに指定

### resource-id

- DynamoDBのテーブル: ``table/テーブル名``
- DynamoDBのGSI: `table/テーブル名/index/インデックス名`

### scalable-dimension

- 読み込みキャパシティ: `dynamodb:table:ReadCapacityUnits`
- 書き込みキャパシティ: `dynamodb:table:WriteCapacityUnits`
- インデックスの読み込みキャパシティ: `dynamodb:index:ReadCapacityUnits`
- インデックスの書き込みキャパシティ: `dynamodb:index:WriteCapacityUnits`

### scalable-target-action
最小値と最大値を設定

`MinCapacity=INT,MaxCapacity=INT`

の形式で指定

## 確認

```bash:awscli
aws application-autoscaling describe-scheduled-actions \
    --service-namespace dynamodb \
    --scheduled-action-names TestAcction
```

### scheduled-action-names
登録の時に指定した `scheduled-action-name` を指定する

"hogehoge" の形式

## 削除

```bash:awscli
aws application-autoscaling delete-scheduled-action \
    --service-namespace dynamodb \
    --scheduled-action-name TestAcction \
    --resource-id table/table_name \
    --scalable-dimension dynamodb:table:ReadCapacityUnits
```


# 参考
[put-scheduled-action](https://docs.aws.amazon.com/cli/latest/reference/application-autoscaling/put-scheduled-action.html)
[ルールのスケジュール式](http://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html)
Mac をシングルユーザモードで復旧(?)したメモ


仕事用 Mac が壊れてなんとか使えるようになるまでの記録です。

運悪く Time Machine が壊れている時 Mac が起動しなくなった。そこでわざわざデータのサルベージに一日費やす羽目になってしまった。Time Machine 用の HD は丁度一年前くらいに調子が悪くなり交換を依頼したのだがまだ使えるからという事でフォーマットして騙し騙し使っていたら２週間前くらいにハード的に壊れた。寿命は三年半くらい。念のため三年くらいで交換しておけばよかったと後悔した。それから後を追うように Mac 本体の SSD が逝ってしまった。Diagnosis を信じるとこちらはハード的にはまだ大丈夫そう。

症状: Mac を立ち上げログインを試みるとプログレスバーが途中で止まり電源が落ちる。

## シングルユーザモードで外付けハードディスクにデータをサルベージする。

まずシングルユーザで起動する。私の場合以下の操作が必要だった。

* Mac の電源を入れる。
* すぐに Command + s を押す。
* 画面にうっすらとカーソルのような小さな四角い箱が表示されて消える。
* ログイン画面になるのでパスワードを入れてログイン (多分そのままシングルユーザにならないのは暗号化してるから?)
* 真っ黒な画面なコマンドを受け付ける画面になる。

ここで、

    # /sbin/fsck -fy

とやると運が良ければディスク修復が出来るらしいが、私の場合は

    CreateNewBTree returned -34
       Disk full error
    ** The volume Macintosh HD could not be repaired.

となって諦めるほかないか。いや、この時点でファイルシステムはまだ読めているので諦めるのは早い。せめて外付けハードディスクに読めるデータを避難させて、OS の再インストールを行う事にした。まず、そのまま

    # ls /dev/disk*

で現在のディスク名割当状況を見て USB ハードディスクを接続し `ls /dev/disk*` すると新しいディスクは disk2 に割り当てられた。ここででマウントポイントを作っておく。シングルユーザモード起動時ルートファイルシステムは読み込みモードになっているので、書き込み可能にしてマウントし直す。

    # mount -uw /
    # mkdir /tmp/mnt

fstyp でファイルシステムを調べてここへマウントする。

    # fstyp /dev/disk2s2
    hfs
    # mount -t hfs /dev/disk2s2 /tmp/mnt

あとはホームディレクトリのコピーを行うだけ。中断してやり直す事を想定して rsync を使ったが、遅くてイマイチだった。

    # mkdir -p /tmp/mnt/2017-11-08/Users/hoge
    # rsync -av /Users/hoge/ /tmp/mnt/2017-11-08/Users/hoge/

不思議なことに、ここで

    # exit

とやるとちゃんと通常の Mac OS 起動直後の画面に行くことが出来た！ただいつ壊れるかわからないので名残惜しいが OS の再インストールを行い、細々と必要アプリをインストールし直している所。

参考

* [Repair Your Hard Disk in Single User Mode](http://www.everythingmacintosh.com/tech-notes/repair-your-hard-disk-in-single-user-mode/)
* [OSXシングルユーザーモードでUSBメモリをマウントする](http://blog.daich.org/2015/06/21/osx-single-user-mode-data-recovery/)

## 試したこと。

以下どの方法も解決の役に立たなかった。

* [PRAM リセット](https://support.apple.com/ja-jp/HT204063)
    * 何も起きなかった。
* [SMC リセット](https://support.apple.com/ja-jp/HT201295)
    * 何も起きなかった。
* [リカバリ](https://support.apple.com/ja-jp/HT201295)
    * Disk Utility によるチェック
        * エラーなしと診断された。
* [診断](https://support.apple.com/ja-jp/HT202731)
    * エラーなしと診断された。
* [セーフモード](https://support.apple.com/ja-jp/HT201262)
    * セーフモードにならなかった。
sbtのwarningの中身を読む

## 課題
sbtがコンパイルの度

```
[warn] there was one deprecation warning; re-run with -deprecation for details
[warn] there was one feature warning; re-run with -feature for detail
```

というようにwarningがあるということを教えてくれるが、そのままだと読むことが出来ない。

## 解決策
sbtコンソールからコンパイルしたいproject(下例ではhoge-project)に移動し、scalacOptionsを設定した上でコンパイルしてやれば大丈夫です。

```sbt
$ sbt

> project hoge-project
> set scalacOptions in ThisBuild ++= Seq("-deprecation", "-feature")
> compile
```

ワンライナーでも書けて、上と同じものは

```bash
$ sbt 'project hoge-project' 'set scalacOptions in ThisBuild ++= Seq("-deprecation", "-feature")' compile
```
となります。


scalacOptionsの中身は `re-run with ...` で要求されているものを適宜与えてやればよいかと思います。


参考: https://stackoverflow.com/questions/9578521/scala-sbt-how-to-re-run-with-deprecation
タブが隠れてるときはポーリングをやめる

Webで疑似ストリームを実現するために高頻度のポーリングを使用することはあると思いますが、そのタブがアクティブでないときはサーバーにも閲覧者のブラウザにも無駄なコストになりかねないので停止したいものです。

でも、アクティブでないといっても複数の窓を並べて見るような場合ならばフォーカスが当たって無くても更新されてほしいもの。

ちゃんと対応できるAPIがあります。[Page Visibility API](https://developer.mozilla.org/ja/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API)がね。

ポーリング程度であれば、以下のようなメソッドや関数を用意しておけば充分でしょう。

```js
function shouldPoll() {
    return !document.hidden; // 必要に応じて他の確認と合わせる
}
```

非対応ブラウザを考慮するんであればちゃんと対応確認すべきかかもしれませんが、モダンブラウザならまず対応してます。(Android4.3以前AOSP？そんなものは知らない。)

もちろん動画、音声等のメディアの再生停止やWebSocket等の接続切断だって[visibilitychange](https://developer.mozilla.org/ja/docs/Web/Reference/Events/visibilitychange)イベントで対応可能です。

他の窓で当該のタブが完全に隠れて(覆いかぶさられて)いたり、他のタブの背後に回っている場合、最小化されている場合やアクティブなワークスペースに当該の窓がない場合は`hidden`、少しでも見えていれば`visible`として扱われるようです。(細かい挙動はOS、ブラウザに依存するかもしれませんが)


-----

なお、`document.hidden`は歴史的な理由により維持されていますがそれよりも`document. visibilityState`を使え、と[W3C勧告](https://www.w3.org/TR/page-visibility/#hidden-attribute)に記載されています。

こちらを使う場合はこう。

```js
function shouldPoll() {
    return document.visibilityState === 'visible'; // 必要に応じて他の確認と合わせる
}
```
【使用感】Unity等で使えるポリゴン削減ツール「Simplygon」

Simplygonは2017年1月にMicrosoft社が開発元を買収し、ほぼ完全無料化されたポリゴン削減ツールです。HoloLens向けアプリを開発する中でポリゴン数の最適化が必要になり、使用してみました。
（使用環境：Unity 5.6.1f1, Simplygon 2.5.1）

Simplygon Studios 
https://www.simplygon.com/

※SDKもインストールし、同時起動する必要があるようでした。（2017/11/9現在。下記サイトに記載がありました）

**※Unity Editor内のwindowメニューの"Simplygon"項目がなくなっていてUnity Editorでの使用ができなくなっていました（2017/12/20現在）**

アバターの作成 - VRchat 日本wiki http://vrchatjp.playing.wiki/d/%A5%A2%A5%D0%A5%BF%A1%BC%A4%CE%BA%EE%C0%AE

#使い方

使い方については下記のサイトを参考にさせていただきました。

[Unity5]Simplygonでモデルを軽量化する方法 凸鉄屋台板 ～ヤキタコのゲーム開発日誌～ 
http://yakigame.blog.fc2.com/blog-entry-7.html

一点プラグインのGUI構成が変更になっている箇所があり、リダクション後にダウンロードボタンは表示されず、ダウンロードするには画面上部の「Download Assets Automatically」のチェックボックスをONにしておく必要があるようでした。

![17 (1).png](https://qiita-image-store.s3.amazonaws.com/0/210804/058249e7-57df-40fc-c026-e96904c8c569.png)


# 感想
Unityで使う際には、無料で品質も悪くなく、つけたコンポーネントも引き継がれるので、とても使い勝手がよかったです。
（ライセンスサーバーエラーがよく出るところが1点気になりました）

###無料

![20 (1).png](https://qiita-image-store.s3.amazonaws.com/0/210804/ffd36dd9-21f1-9770-da04-f0d2a57ed17c.png)

有料版との違いは赤丸をしたところくらいのようです。

###品質

![21 (1).png](https://qiita-image-store.s3.amazonaws.com/0/210804/24dce62b-cd8f-47f7-0ef2-06f5fe7af528.png)

Asset Storeのアニメーションのついたフリーのモデルを使用させていただきました。左がリダクション後のモデルです。元の20%まで落としているので、妥当な品質なのではと思いました。

###コンポーネントの引き継ぎ

馬のAnimatorコンポーネントがリダクション後のモデルにも設置されていました。

![22 (1).png](https://qiita-image-store.s3.amazonaws.com/0/210804/0bcd5bf6-e814-e370-12c1-977e9a1fb594.png)

#困ったこと

ライセンスチェックを定期的に行っているのか、ライセンスサーバーとアクセスできない環境では使用できなくなることがありました。

![6b.png](https://qiita-image-store.s3.amazonaws.com/0/210804/da52a691-665e-03bc-e8a5-d349c6bea810.png)
Text Fieldでフォーカスが当たった際に入力されてる値が消えないようにする


#環境
Xcode9.1

#解決
Inspectorから解決する方法とCode中で解決する方法がありました

##Inspectorから解決
Text FieldのInspectorで、Clear Buttonの下にある `Clear When editing begins`のチェックを外す

##Codeで解決
`clearsOnBeginEditing`プロパティを`false`にする


```
@IBOutlet weak var textField: UITextField!
    
override func viewDidLoad() {
    super.viewDidLoad()
    
    textField.clearsOnBeginEditing = false
}
```

##因みに
Inspectorで`Clear When editing begins`のチェックした状態で`clearsOnBeginEditing`プロパティを`false`にすると`clearsOnBeginEditing`プロパティの方が優先されました
古い Chef の remote_file リソースでのファイルダウンロード時に `EOFError` が出たときの対処

# 起こったこと

CentOS6.x でやった話です。

久々にプロビジョニングしようとして `chef-solo` を実行したのですが、レシピに書かれていた `remote_file` リソースでファイルをダウンロードするところで `EOFError` が発生して、レシピの実行が止まってしまいました。

```
$ sudo chef-solo -o php_setup::default
Starting Chef Client, version 11.4.4
Compiling Cookbooks...
Converging 1 resources
Recipe: php_setup::default
  * remote_file[/var/tmp/php-5.6.32.tar.gz] action create_if_missing
================================================================================
Error executing action `create_if_missing` on resource 'remote_file[/var/tmp/php-5.6.32.tar.gz]'
================================================================================


EOFError
--------
end of file reached


Resource Declaration:
---------------------
# In /var/chef/chef-repo/site-cookbooks/php_setup/recipes/default.rb

  1: remote_file '/var/tmp/php-5.6.32.tar.gz' do
  2:   source 'http://php.net/distributions/php-5.6.32.tar.gz'
  3:   checksum '7bef1ae8cd633df5b9c5964262d276d2dc21acbfcd94022d1e2084d199315df4'
  4:   action :create_if_missing
  5: end



Compiled Resource:
------------------
# Declared in /var/chef/chef-repo/site-cookbooks/php_setup/recipes/default.rb:1:in `from_file'

remote_file("/var/tmp/php-5.6.32.tar.gz") do
  provider Chef::Provider::RemoteFile
  action [:create_if_missing]
  retries 0
  retry_delay 2
  path "/var/tmp/php-5.6.32.tar.gz"
  backup 5
  cookbook_name :php_setup
  recipe_name "default"
  checksum "7bef1ae8cd633df5b9c5964262d276d2dc21acbfcd94022d1e2084d199315df4"
end



Chef Client failed. 0 resources updated
```

# 対処法

インストールされている chef-solo のバージョンを見たところ、結構古いものでした。

```bash
$ chef-solo --version
Chef: 11.4.4
```
同じレシピを実行して成功した別のサーバーの chef-solo のバージョンは 12系でした。

```bash
$ chef-solo --version
Chef: 12.4.1
```
これでも十分古いですが…。

試しに 12系 をインストールしてみたところ、 `remote_file` リソースでエラーが出なくなりました。
エラーメッセージからあれこれ調べて微妙にハマってしまったのですが、解決策は何のことはないレベルのものでした。

ちなみに 2017/11 現在の、Chef の最新バージョンは 13.6.4 です。コマンドラインでそのままインストーラーを実行すると最新のものが入ってしまうため、12系のバージョンを指定してインストールしました。
( see [Chefクライアントを任意のバージョンを指定してインストールしたい - Qiita](https://qiita.com/FALZ/items/b5fcd8088d182c5b2016) )
[WordPress][MySQL] WordPress の全テーブルのエンジンをすべて innodb に変更する

小ネタ。
wp-cli を使って WordPress の全エンジンを InnoDB に変える方法。
ちまちま ALTER TABLE 発行するのも疲れるので。
こんな感じのシェルスクリプト作って実行すればいいんでないかな。

```modify-engine.sh
#!/bin/bash
WP_PATH=${1:-/var/www/html}
TABLES=$(wp --path=${WP_PATH} db tables --all-tables)
for TABLE in ${TABLES}; do
    echo "** ${TABLE} **"
    wp --path=${WP_PATH} db query "ALTER TABLE ${TABLE} ENGINE=innodb, ALGORITHM=COPY;"
done
```

現在のテーブルのエンジンが何かを調べたい場合も、wp-cli でできるよ。

```
$ wp db query "SELECT table_schema, table_name, engine FROM information_schema.tables WHERE table_schema='$(wp eval 'echo DB_NAME;')';"
+--------------+-----------------------------+--------+
| table_schema | table_name                  | engine |
+--------------+-----------------------------+--------+
| wordpress    | wp_commentmeta              | InnoDB |
| wordpress    | wp_comments                 | InnoDB |
| wordpress    | wp_links                    | InnoDB |
| wordpress    | wp_options                  | InnoDB |
| wordpress    | wp_postmeta                 | InnoDB |
| wordpress    | wp_posts                    | InnoDB |
| wordpress    | wp_term_relationships       | InnoDB |
| wordpress    | wp_term_taxonomy            | InnoDB |
| wordpress    | wp_termmeta                 | InnoDB |
| wordpress    | wp_terms                    | InnoDB |
| wordpress    | wp_usermeta                 | InnoDB |
| wordpress    | wp_users                    | InnoDB |
+--------------+-----------------------------+--------+
```
C++ Builder XE4, 10.2 Tokyo > Form1:項目追加 + Form2:追加項目の取出し > TStringList実装

```txt:動作環境
C++ Builder XE4
RAD Studio 10.2 Tokyo Update 2 (追記: 2018/01/05)
```

### 処理

- 装置などからデータが適宜追加される
    - 例: 200msecごとに1個ずつ
- データを適当な個数で取出し
    - 例: 1秒ごとに5個ずつ

### フォーム構成

- Form1がデータ追加
- Form2がデータ取出し

### code

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	Timer1->Enabled = false;
	Timer1->Interval = 200; // msec
	Timer1->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
	static int idx = 0;

	Form2->AddItem(IntToStr(idx));
	idx++;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
	Form2->Show();
}
//---------------------------------------------------------------------------
```

```Unit2.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
	: TForm(Owner)
{
	m_itemList = new TStringList();

	Timer1->Enabled = false;
	Timer1->Interval = 1000; // msec
	Timer1->Enabled = true;
}
__fastcall TForm2::~TForm2()
{
	delete m_itemList;
	m_itemList = NULL;
}

void __fastcall TForm2::AddItem(String item)
{
	m_itemList->Add(item);
}
//---------------------------------------------------------------------------

static const int kNumExtract = 5; // 取出す項目数

void __fastcall TForm2::Timer1Timer(TObject *Sender)
{
	if (m_itemList->Count < kNumExtract) {
		return;
	}

	// TODO:資源のロック開始

	String item = L"";
	for(int idx=0; idx < kNumExtract; idx++) {
		item = item + L"," + m_itemList->Strings[idx];
	}
	for(int loop=0; loop < kNumExtract; loop++) {
		m_itemList->Delete(0);
	}

	// TODO:資源のロック解除

    String msg = item + L" @ " + Now().FormatString(L"yyyy/mm/dd hh:nn:ss.zzz");

	Memo1->Lines->Add(msg);

}
//---------------------------------------------------------------------------
```

### 結果

5個の項目表示が1014msecごとに実施されている。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/94e2d138-2bf1-2fcc-c362-93ce347ea3be.png)


### 資源のロック

Form2のTimer処理中にForm1からAddItem()は問題ないだろうか。

MutexやCriticalSectionなどを検討していたが、下記の調査では期待したようなロック動作にはならなかった。
https://qiita.com/7of9/items/eb3a7f2bd19e892c2b20

### 備考

フォームでなくTThreadで実装すると、スレッドの優先度を設定できる。
ただし、TThreadで実装してもロックのかかるタイミングは期待したものではなかった。
gzip 圧縮したテキストファイルに、解凍せずに追記する

## 目的
* 題記の通り、gzip 圧縮したテキストファイルに追記したいけど、「解凍→追記→圧縮」が面倒

## 環境
```console:centos-release
$ cat /etc/centos-release
CentOS Linux release 7.4.1708 (Core)
```
```console:gzip
$ gzip --version
gzip 1.5
Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
Copyright (C) 1993 Jean-loup Gailly.
This is free software.  You may redistribute copies of it under the terms of
the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
There is NO WARRANTY, to the extent permitted by law.

Written by Jean-loup Gailly.
```
## やってみる
```console
$ echo "January" |gzip -c >> month.gz
$ echo "February" | gzip -c >> month.gz
$ zcat month.gz
```

```console:出力結果
January
February
```

OK！
KotlinでMockitoのany()などのArgumentMatchersを使う方法


KotlinでMockitoの```any()```や```isA()```を利用すると```java.lang.IllegalStateException: Mockito.any() must not be null
```が発生します。

これらのメソッドがnullを返すため（プリミティブ型であればデフォルト値を返すのでこのエラーは起きません）で、Null安全なKotlinではエラーになります。
検証対象のメソッド引数をNullableにすれば当然解決しますが、それはやりたくないですよね。

例えば、以下の部分をモックにして引数を検証したいです。

```kotlin
transition.onNext(TransitionType.Success())
```

実際のコードとテストの検証時では別のインスタンスなので、同じクラスかどうか検証したいです。
なので、こう書きます。

```kotlin
Mockito.doNothing().`when`(mockEventBus).onNext(Mockito.isA(TransitionType.Success::class.java))
```

これだとエラーになります。

# 解決方法

以下の```nullReturn()```のようにキャストすれば動作するようになりました。

```kotlin
class TestUtils private constructor() {

    companion object {
        fun <T> isA(type: Class<T>): T {
            Mockito.isA<T>(type)
            return nullReturn()
        }

        fun <T> any(): T {
            Mockito.any<T>()
            return nullReturn()
        }

        private fun <T> nullReturn(): T = null as T
    }
}
```

```kotlin
Mockito.doNothing().`when`(mockEventBus).onNext(TestUtils.isA(TransitionType.Success::class.java))
```

理由はわかりませんが、Kotlinは ```null as String``` のようにnullをキャストするとコンパイラーnullチェックを回避できます。
NotNullなクラスにキャストしているから、実際はnullでもNotNullとして判断されているのでしょうか。
（実行時には```TypeCastException```で落ちます。）
そして、何故かGenericsでのキャストでは実行時にも動作するのです。
固定メニューのactiveとページの現在地を連動

# 固定メニューのactiveとページの現在地を連動

## 仕様

メニューと、divの位置を連動する

## ソース

### html
```html:test_10.htm
<html>
<head>
<link rel="stylesheet" type="text/css" href="test_10.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript" src="test_10.js"></script>
<title>test_10 固定メニューのactiveとページの現在地を連動</title>
</head>
<body>
<nav id="menu-wrap">
  <ul id="menu">
    <li><a href="#content_first">Contents1</a></li>
    <li><a href="#content_second">Contents2</a></li>
    <li><a href="#content_third">Contents3</a></li>
    <li><a href="#content_fourth">Contents4</a></li>
    <li><a href="#content_etc">Contents5</a></li>
  </ul>
</nav>
<div class="contents" id="content_first">1</div>
<div class="contents" id="content_second">2</div>
<div class="contents" id="content_third">3</div>
<div class="contents" id="content_fourth">4</div>
<div class="contents" id="content_etc">5</div>
</body>
</html>
```

### javascript

※スクロールアニメーションをつけました

```javascript:test_10.js
$(function() {
  var list=[];
  ['#content_first',
   '#content_second',
   '#content_third',
   '#content_fourth',
   '#content_etc'
   ].map(function(x){
     list.push({
       "min": $(x).offset().top,
       "max": $(x).next().length>0?$(x).next().offset().top-1:($(x).offset().top+$(x).height()),
       "id": x,
     })});
  var pre_pos = 0;
  $(function() {
    $('#menu a[href="' + location.hash + '"]').addClass('active');
    $('#menu a').on('click', function() {
      $('#menu a').removeClass('active');
      $(this).addClass('active');
      $('html,body').animate({scrollTop:$($(this).attr("href")).offset().top }, 500, 'swing');
    });
  });

  $(document).on('scroll', function() {
    var this_pos = $(window).scrollTop();
    var pre_id = get_id(pre_pos);
    var this_id = get_id(this_pos);
    if (pre_id !== this_id) {
      if(this_id!==null){
        location.hash=this_id.substr(1,this_id.length);
        $(window).scrollTop(this_pos);
      }else{
        location.hash="";
      };
      $('#menu a').removeClass("active");
      $('[href="' + this_id + '"]').addClass("active");
    }
    pre_pos = this_pos;
  });
  function get_id(pos) {
    var arr = list.filter(function(x) {
      return x.min <= pos && x.max >= pos;
    });
    if (typeof arr[0] == "undefined") return null;
    return arr[0].id;
  }
});
```

### css
```css:test_10.css
#menu-wrap {
  position: fixed;
}
#menu{
text-align: left;
  display: flex;
margin: 0px;
  padding-left: 20px;
}
#menu li {
  display:inline;
}
#menu li:last-child a{
  border-right:1px solid #000000;
}
#menu a:hover{
  background-Color:yellow;
}
#menu a{
  width: 80px;
  border:1px solid #000000;
  border-right:0px;
  padding-left: 5px;
  padding-right: 5px;
  display: inline-block;
  text-decoration:none;
}
.contents {
  height: 500px;
}
.active {
  background-color: red;
}
#content_first,#content_third,#content_etc{background-Color:aqua;}
#content_second,#content_fourth{background-Color:lime;}
```
[android]gzipでダウンロード

# gzipエンコーディング指定でhttpダウンロード

引数でgzipエンコード指定して文字列として返すだけのメソッド


```java:
    public static String download(String urlString, boolean gzip) {
        final int TIMEOUT_READ = 5000;
        final int TIMEOUT_CONNECT = 30000;
        final int BUFFER_SIZE = 1024 * 5;

        InputStream inputStream;
        StringBuilder stringBuilder = new StringBuilder();
        BufferedInputStream bufferedInputStream = null;

        try {
            URL url = new URL(urlString);

            URLConnection urlConnection = url.openConnection();
            urlConnection.setReadTimeout(TIMEOUT_READ);
            urlConnection.setConnectTimeout(TIMEOUT_CONNECT);
            
            if (gzip) {
                urlConnection.setRequestProperty("Accept-Encoding", "gzip");
                inputStream = new GZIPInputStream(urlConnection.getInputStream());
            } else {
                inputStream = urlConnection.getInputStream();
            }
            bufferedInputStream = new BufferedInputStream(inputStream, BUFFER_SIZE);

        } catch (IOException e) {
            Log.d(TAG, "err con:" + e.toString());
        }

        try {

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream, "UTF-8"));
            String line = "";

            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line);
                stringBuilder.append("\r\n");
            }
            
            bufferedReader.close();

        } catch (IOException e) {
            Log.d(TAG, "err file:" + e.toString());
        }

        return stringBuilder.toString();
    }

```
Windows 10 64bit でanaconda上のjupyterでCythonが走らなかった件について

Windows 10 Pro 64bit，anaconda 上のjupyter(5.0.0)でCythonがうまく走らず(python 3.6.1) 以下のエラーが表示された。
``` "Unable to find vcvarsall.bat" ```

Visual Studio Community 2017を開いて，Python関連のツールをインストールした。右上の検索窓に```python```と打つと候補がすぐに出てくる。
インストール完了後は次のようなエラーが出た。
```CompileError: command 'cl.exe' failed: No such file or directory```

adminでvisual studioのコマンドプロンプトを開いてもだめ。
Anaconda navigatorでcythonのバージョンを見てみたら0.25.2でupdateがあったので0.26.1に更新してみた。
変化なし。

cl.exeの場所を特定し，(C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\binにあった)環境変数を追加。
エラーが変わった。
```CompileError: command 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\cl.exe' failed with exit status 2```

#解決
[Microsoft Visual C++ 2015 Build Tools](http://landinghub.visualstudio.com/visual-cpp-build-tools)をインストールしたら解決した。