OmniAICreator/Qiita-1.07M huggingface dataset:
肩こりと戦うエンジニアにおすすめするグッズ

やはり今エンジニアの方が最も注目していることは肩こりじゃないでしょうか。
肩が凝っていては良い仕事ができません。
今回はあると嬉しい便利グッズを紹介します。
![katakori_man.png](https://qiita-image-store.s3.amazonaws.com/0/121223/9aa09287-993b-e506-72c6-9b4ba7183cf6.png)


### 1.セパレートキーボード
![a48ad2555147d03aad041da2e05b51c9_e233029c-526e-4932-92c4-7db2b31be68e.jpg](https://qiita-image-store.s3.amazonaws.com/0/121223/3887f700-1c14-6c05-dfb8-1007847df196.jpeg)
[ErgoDoxEZより](https://ergodox-ez.com/)

セパレートキーボードとは左右に分割されたキーボードのことで、一般的な物と比べて自然な姿勢で使用することができます。

![Barocco_09_s.jpg](https://qiita-image-store.s3.amazonaws.com/0/121223/313b0b5f-8854-c343-9ec9-755d8d48d1af.jpeg)
一般的なキーボードの手首への負担
[Kinesis Corporationより](http://www.kinesis-ergo.com/partners/health-safety/ergonomic-benefits/freestyle-ergonomic-benefits/)

肩を開いた状態で手首を自然な角度で保つことができるため、肩こりや腱鞘炎の予防となります。
高いので会社に買ってもらいましょう。




### 2.PCスタンド


![computer_side_man.png](https://qiita-image-store.s3.amazonaws.com/0/121223/eb860f20-7c30-c735-e642-944d2088e514.png)
![pose_necchuu_computer_man.png](https://qiita-image-store.s3.amazonaws.com/0/121223/033f3995-d4d3-4608-efec-6dabd4a3b8b7.png)

ノートPCを使用していると、必然的に目線が下に行きがちです。前かがみの姿勢になってしまうためストレートネックの原因となり、慢性的な肩こりを引き起こしてしまいます。

![home-hero-product-image.png](https://qiita-image-store.s3.amazonaws.com/0/121223/dea07bf2-0d7b-6eac-9ef3-cd11355f5eb7.png)

[Roost Industries Corpより](https://www.therooststand.com)

PCスタンドを使うと目線に近い位置に設置することができるので、姿勢を正しく保つことができます。
これも高いので会社に買ってもらいましょう。



### 3.できるだけ良い椅子
![REK_18259_20160811174342005_D.jpg](https://qiita-image-store.s3.amazonaws.com/0/121223/1446ddc5-7f35-7bb1-ae2f-7822edf930d1.jpeg)
[ハーマンミラーより] (www.hermanmiller.co.jp)

とても高いので会社に買ってもらいましょう。


### 4.ストレッチ・筋トレをする
![pose_nobi_man.png](https://qiita-image-store.s3.amazonaws.com/0/121223/dd584971-2345-92d0-0a47-f8278b32a561.png)

ストレッチ・筋トレは、極めて有効です。
良いグッズを揃えたとしても一日中デスクワークのエンジニアの場合、体を動かさなければ筋肉は固まるばかりです。また、すでに凝り固まっている場合は頑張ってグッズを集めても得られる効果が薄いことが私調べでわかっています。

体を鍛えましょう。


![978-4-584-13557-0.jpg](https://qiita-image-store.s3.amazonaws.com/0/121223/be482635-82b9-8ce3-6276-1a645232584c.jpeg)
長友佑都体幹トレーニング20 
[KKベストセラーズより](http://www.kk-bestsellers.com/cgi-bin/detail.cgi?isbn=978-4-584-13557-0)

こちらのトレーニング本は一見ハードな印象を受けますが、「姿勢を直したい」「腰痛を解消する」といった目的にもフォーカスしており、初心者でも導入しやすい内容となっています。私も実践していますが腹筋が強くなり、正しい姿勢が取りやすくなってきました。ついでに運動能力も向上するかもしれません。
これは技術書として会社に買ってもらいましょう。
curlをWindows10にインストールする

#curlってなんだ

cURL - Wikipedia
https://ja.wikipedia.org/wiki/CURL
コマンドラインからURL指定してデータ引っ張ってこられるツール、という理解をした。

#実は別名
windows10のPowerShellで実行すると使えるように見えるが、実は別名となっている。

PowerShell コンソール内で curl や wget が実行できないとお嘆きのあなたへ
http://devadjust.exblog.jp/22690878/
> "curl" という名前に対し、PowerShell のコマンド「Invoke-WebRequest」が別名として設定

ということなので外す。

>PS C:\> get-alias curl
>
CommandType Name Version Source
----------- ---- ------- ------
Alias curl -> Invoke-WebRequest

本体はInvoke-WebRequestというものになっている。

対策：.exeまで入れて実行するか、エイリアスを消す。
> del alias:curl

※解除はPowerShellコンソールのそのセッションでのみ有効

#curlのダウンロード

Windows：cURL のインストール - Web系開発メモ
http://web-dev.hatenablog.com/entry/windows/install-curl
curl - Download
https://curl.haxx.se/download.html

ずっと下の方にある`Win64 x86_64 7zip 7.56.1 binary SSL SSH Viktor Szakáts 1.88 MB`をダウンロード。

#インストールとパス設定

環境変数PATHに `C:\Program Files\curl\bin` を追加。
一度Windows PowerShellを終了させる。

バージョン表示させて実行可能か確認。

> PS C:\WINDOWS\system32> curl --version
curl 7.56.1 (x86_64-pc-win32) libcurl/7.56.1 OpenSSL/1.1.0g (WinSSL) zlib/1.2.11 WinIDN libssh2/1.8.0 nghttp2/1.27.0
Release-Date: 2017-10-23
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telne
t tftp
Features: AsynchDNS IDN IPv6 Largefile SSPI Kerberos SPNEGO NTLM SSL libz TLS-SRP HTTP2 HTTPS-proxy MultiSSL
PS C:\WINDOWS\system32>

OK。CURLコマンドが使えるようになった。
CentOS7でRedmineをmarkdown形式に変更する

こんな簡単な環境設定でも１人でやるとやたら時間かかりますね　　
貴重なプライベートの時間を食べてしまっていたので備忘備忘と

## 検証環境
OS環境：CentOS７
Redmineの環境:
 -  Redmine version                3.4.2.stable.16963
 -  Ruby version                   2.4.1-p111 (2017-03-22) [x86_64-linux]
 -  Rails version                  4.2.8
 -  Environment                    production
 -  Database adapter               PostgreSQL

## 設定方法

まず管理者権限のあるユーザでログインして

「管理」→「設定」まで移動

「テキスト書式」の部分をtextileから、markdownに変更するだけです。

もちろん下の保存ボタンをちゃんと押すこと

## 一体何にしくじったのか

そう変に時間がかかった原因はRedmineがversion3であるにもかかわらず
プラグインを入れようとしてエラーが起きまくるというのが原因でした...

入れなくてよかったんかい！

とまあしょうもないことでつまずいていたので今後はバーションとか気をつけます。


参考にした記事
[redmineでGitHubのMarkdown記法を利用する](https://qiita.com/mountcedar/items/9d313a6a0a8f86f1d962)

#### ※そうそう、markdownk形式にすると以前のtextleの記法が適用されなくなるので注意が必要
Qiita記事のストック数を確認するbookmarklet

2017/11/29追記：API制限に気づいて修正
2017/12/01追記：レイアウト変更で使えなくなりました。気が向いたらなおします。
2017/12/01追記：2017/12/1のレイアウト変更に対応しました。
2017/12/03追記：`<100`を`100^`に変えました。（どちらにせよ、しっくり来てないのでいい表現あれば知りたい・・・）
2017/12/03追記：`100^`を`100+`に変えました。

#はじめに
どれくらいストックされているのか気になったので、先人のbookmarkletを修正してみた。
先人：[ストック数用のbookmarklet](https://qiita.com/ksomemo/items/9da6a44edba7c541af89)・・・v1版なので動かず
先人の先人：[Qiitaの「いいね」に消された「ストック数」を復活させた](https://qiita.com/hikarut/items/c71063af8cb79124de72)・・・だいぶ前の奴なので動かず

#bookmarklet
##対象記事のみ
1. URL欄に以下のコードを貼り付けたブックマークを作る。
2. ストック数を見たいQiita記事を開いた状態で、1のブックマークを押下する。
3. ストックボタン付近の表示が変わって、ストック数が見える。

```js
javascript:(() => {
    let path = window.location.pathname
    , itemId=path.substr(-20, 20)
    , url = `https://qiita.com/api/v2/items/${itemId}/stockers?per_page=100`;
    if (path.match(/items/)) {
        $.ajax({
            url: url,
            success :(t) => {
                var over = (Object.keys(t).length == 100) ? "+" : "";
                const stockerLink = $(`<a href="${url}">${Object.keys(t).length}${over}</a>`);
                $(".it-Actions_item-stock").append(stockerLink);
            },
            error:() => {
                alert("qiitaStock request error");
            },
            dataType:"json",
            timeout:3e3}
        );
    }
})()
```

##注意事項
1. APIの都合で100以上の場合は、`100+`と表示します。
2. あんまり実行すると「Rate limit exceeded」で怒られてしばらく使えなくなります。用法用量[^1]を守ってお使いください。
3. stockersのリンクは、JSONファイルを生表示します。
JSON-viewrとかの拡張機能をブラウザに入れてご確認くださいませ。

[^1]: 1時間に60回。詳細は、[QiitaAPIv2ドキュメント＞概要＞利用制限](https://qiita.com/api/v2/docs)。


#もう使えないおまけ
2017/12/1のレイアウト変更で使えなくなりました。
もともと使い勝手も良くないので、修正するつもり無いですが、一応残しておきます。
##検索結果の一覧全て
1. URL欄に以下のコードを貼り付けたブックマークを作る。
2. [記事検索](https://qiita.com/search)した状態で、1のブックマークを押下する。
3. 右端くらいにストック数が見える。

```js
javascript:(() => {
    $(`.searchResult`).each(function(i, elem) {
        var itemId = $(elem).attr(`data-uuid`);
        var url = `https://qiita.com/api/v2/items/${itemId}/stockers?per_page=100`;

        $.ajax({
            url: url,
            success :(t) => {
                var over = (Object.keys(t).length == 100) ? " over" : "";
                var html = `<li>stockers:<a href="${url}">${Object.keys(t).length}${over}</a></li>`;
                $(elem).find(`.searchResult_sub`).find(`ul`).append(html)
            },
            error:() => {
                alert("qiitaStockList request error");
            },
            dataType:"json",
            timeout:3e3}
        );
    });
})()
```



以上

---
fbx形式ファイルをパースしたものをWebGL(GLBoost)で描画

#はじめに
Mayaなどでモデリング、アニメーションしたものから作られるfbxファイル。
これをWebGLで描画できるようにファイルの中身をパースして必要なデータを作る作業をしています。
描画にはWebGLの国産ライブラリであるGLBoostを使っています。
結論から言うと、静止しているモデルのメッシュは読み込んで描画出来るようになりました。

#インデックスデータの並びの特徴
fbxの頂点のインデックスデータはがポリゴン１枚ごとに区切られています。その区切りが - 表示で、例えば0,1,2,3というポリゴンのインデックスがあったとすれば0,1,2,-4という書き方になっています。区切りになるインデックスに-1を掛けてさらにそこから -=1 されています。この数値を直しながらインデックスデータを取得していきます。

#ハマった　その１
あと、ハマったのがゴミデータが混じっていることがあって、頂点データやインデックスデータの中に半角スペースがあったりします。それを取り除くかスキップする処理を書いてあげないといけないです。もしかするとCinema4Dのバグで、Mayaで作ったら半角スペースが混じったりしないかもしれません。

#ハマった　その２
もう１つハマったのが法線データの描画の仕方です。
fbxには法線がどのように定義されているかをマッピングモードで表し、データの格納方法をリファレンスモードで定義しています。
僕の持っているCGツールのCinema4Dではfbxファイルの中に
MappingInformationType: "ByPolygonVertex"
ReferenceInformationType: "Direct"
と書かれていました。
マッピングモードには
・ ByControlPoint
・ ByPolygonVertex
・ ByPolygon
・ ByEdge
・ AllSame
があるようです。
リファレンスモードには
・　Direct
・　Index
・　IndexToDirect
があるようです。
詳しくは http://shikemokuthinking.blogspot.jp/2013/07/fbx.html

マッピングモードのByPolygonVertexというのは、ポリゴンに対して法線が定義されています。
リファレンスモードのDirectは、マッピングモードがByPolygonVertexの場合は頂点の順番に法線が格納されています。
以上を考慮した上で法線を取得して並べないといけないのですが、もう１つ問題がありました。
僕がCinema4Dで作ったメッシュは共有頂点を使って描画するようなデータでした。
法線データは共有頂点に対応してないデータだったので、頂点データをバラして共有頂点がないようなデータに並べ替えて、それに対応するように法線データを並べ替えました。

以上が今回までに作ったParserと描画部分でした。

#アニメーションについて
アニメーションしているメッシュのfbxファイルがまだパース出来るようになっていません。
その原因は１つ、自分でCGツールでメッシュにボーンを入れてアニメーションさせるということが上手く出来ないからです。
CGツールはCinema4Dを使っています。
ボーンの入れ方のハウツー動画を買って勉強したりしてみましたが上手く出来ません。
Cinema4Dで上手くボーンを扱うことが課題です。

#今後
このアニメーションが出来ないというスランプに陥ってしまって、逃げでリバーシのゲームを作っていました。
https://qiita.com/minmin0530/items/b5f55e8128214d1b6c4e
たら話ですが、このリバーシが出来上がったらfbxのアニメーション制作に復帰しようと思っています。

#終わりに
fbxパーサーのプロジェクトです。
https://github.com/minmin0530/FBX-Parser-Animater

fbxの読込に少し時間がかかっていますが、メッシュの描画とコードです。
http://ai5.jp/code/head_normal/index.php
Riotタグの外側にコードを書く

Riotのタグファイルを作る際に、実はタグの外側にもコードを書けます。

# タグファイルとJavaScript

ふつう、Riotのタグファイルといえば、以下のようなものをイメージするでしょう。

```html:典型的タグファイル
<tag-name>
  <div>
    <!-- 略 -->
  </div>

  <style>
    /* 略 */
  </style>

  <script>
    // 略
  </script>
</tag-name>
```

実は、Riotのコンパイラは、タグの外側にJavaScriptを書くことも認めています（[テストケース](https://github.com/riot/compiler/blob/master/test/specs/fixtures/mixed-js.tag)と、その[期待される結果](https://github.com/riot/compiler/blob/master/test/specs/expect/mixed-js.js)）。

```html:JavaScriptを外側に書いた例
alert('foo')

<test-tag>
</test-tag>
```

```js:コンパイル後の結果
alert('foo')

riot.tag2('test-tag', '', '', '', function(opts) {
});
```

# 何に使う？

ブラウザ内コンパイルで使うようなRiotタグだと使いづらいかもしれませんが、Webpackなどに組み込んだ系では、けっこう使いみちがあります（この場合、外側に書いたコードもWebpackの1モジュールとして、無名関数でスコープが切られます）。

* タグ内から別のタグを呼び出している場合に、そのタグを`require`することで、依存関係を明確にする
* タグ内で使う別な関数を、事前に`require`しておく
* キャッシュなど、全てのタグインスタンスで共有できるデータ

なお、タグ内に書いたJavaScriptコードは、タグのマウントのたびに実行されるのに対して、外側に書いたコードはコード自体の読み込み時（作り方によって違ってきますが、`DOMContentLoaded`より前ということも考えられます）に動くので、そのあたりには注意が必要です。
WindowsでLaradockをdocker-composeしようとすると.IOError: [Errno 2] No such file or directory: u'.\\docker-compose.yml:docker-compose.dev.yml

## まず結論
[複数ファイルを指定する際の区切り文字がLinux系とWindowsで異なるらしい。](https://docs.docker.com/compose/reference/envvars/#compose_file)

## 前提
+ Windows10 Professional
+ Docker for Windows 17.09.0-ce-win33
+ Laradock v5.8.3

## 現象
Windows環境でのLaradock環境構築を進めていたところ、`$ docker-compose` を行う場面で以下のエラーが発生する。

```
docker-compose : .IOError: [Errno 2] No such file or directory: u'.\\docker-compose.yml:docker-compose.dev.yml'
```

数多あるWindowsでのLaradock環境構築記事にも特段の記載がないし、ドキュメントにも記載がない…と途方にくれていたのだが、  
どうやら[ドキュメントの追記がプルリクエスト申請中](https://github.com/laradock/laradock/pull/1269)だったようだ。

## 原因と対策
冒頭に示したとおりだが、区切り文字を正しく認識していなかったために「そのようなファイルがない」と判断されていたようである。

対策としては、`$ cp env-example .env` で作成した`.env`ファイルの該当部分を以下のように変更すればOK。

``` 
# 変更前
COMPOSE_FILE=docker-compose.yml:docker-compose.dev.yml
```

```
# 変更後
COMPOSE_FILE=docker-compose.yml;docker-compose.dev.yml
```

Windowsでの開発は茨の道なのでDockerコンテナを立ち上げようとしたが、開発以前にハマるとは。

## 参考資料
+ https://docs.docker.com/compose/reference/envvars/#compose_file
+ https://github.com/laradock/laradock/pull/1269
+ https://github.com/laradock/laradock/issues/1268
Microsoftアカウント登録

ハンズオンに必要となるMicrosoftアカウント新規登録（Windows）手順です。

#Microsoftアカウントサイトを開く
[Microsoftアカウントサイト](https://www.microsoft.com/ja-jp/msaccount/)を開きます。
キャッシュを拾って既存のアカウントでログインした状態になってしまう場合がありますのでその際にはプライベートモードで開きなおしてください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/178016/221aa936-047d-7a36-b587-9bcd5f491128.png)

#Microsoftアカウント新規登録
下にスクロールし、[アカウントの新規登録]ボタンをクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/178016/e1f58495-7a9f-e37a-8663-4c3a23927f1b.png)

##Microsoftアカウント登録手続き
以下の画面で[新しくメール アドレスを作成して、Microsoft アカウントとして利用する方法]をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/178016/d51dbc46-1d4f-2594-2ea3-ea21947346fd.png)

##アカウント作成
[signup.live.com](https://signup.live.com)をクリックします
![image.png](https://qiita-image-store.s3.amazonaws.com/0/178016/ec3b365a-d396-5886-3173-760149c3b30e.png)

任意のアカウント名とパスワードを入力します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/178016/8e04d0c7-3f3e-d5d0-12fb-7f52e05d8589.png)

##アカウント情報入力
アカウント情報を入力して[次へ]をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/178016/2d4eb812-a86e-3ea8-ea5e-4fb7d161c2aa.png)

詳細の追加画面で生年月日を入力して[次へ]をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/178016/3ddebce8-0dc4-8c11-09e9-4dfaf71b0e0c.png)

表示されている文字を入力して[次へ]をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/178016/c038b9ac-1728-eb15-4dc4-3647039d9b02.png)

#完了
こんにちは画面が出たら完了です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/178016/bf04cfb2-f0be-9bca-9690-9d50e717ad18.png)

#メール動作確認
念のため[Outlook.com](https://outlook.live.com/owa/)でOUTLOOKが開けるか確認しましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/178016/7e9bfc42-384e-a70b-8c78-19edfaf49e00.png)

以上です。
gitへのコミット時に文字コードを強制する(UTF-8のBOMを取り除く)

`JenkinsFile` にBOMが付いててこけることがあって、それの対処に使った内容。


## TL;DR

- pre-commit フックで対象ファイルのチェック。
- コミット対象のファイルを編集して再度 add する。


## hookスクリプト

`nkf` とか `file` とか `awk` とかもっと使い勝手いいコマンドで簡単にする方法はあるけど、
WindowsでSourceTree使っていて ~~MinGWにいろいろ入れるの面倒だったので~~ ピュアな環境で使えるようにしたかったので。

```bash:pre-commit
#!/bin/bash

gitroot=$(git rev-parse --show-toplevel)                                          # 1
pattern='jenkinsfile|\.gvy$'                                                      # 2

git diff --cached --name-only | egrep -i $pattern | while read file ; do          # 3
  target="$gitroot/$file"
  if [ ! -f $target ] ; then :                                                    # 4
  elif head -1 $target | grep $'\xef\xbb\xbf' > /dev/null ; then                  # 5
    tmp=$target.tmp                                                               # 6
    cp -p $target $tmp
    cat $tmp | perl -ple 's/^\xef\xbb\xbf// if (! $count++)' > $target            # 7
    git add $target                                                               # 8
    rm $tmp -f
  fi
done

```


## 内容の説明

1. `git diff` はリポジトリのルートからの相対パスが返るので、後でフルパス作れるように。
2. 処理対象とするファイル名のパターン。今回はJenkinsFileと共有処理書いてるGroovyスクリプトだったのでこの内容で。
3. コミット対象のファイル = インデックスされているファイル一覧を取得してファイル名フィルタを適用。
4. ファイルチェック、既存ファイルを削除する変更の場合はこれがないと怒られるので注意。
5. TF-8のBOMで始まるかチェック。`file` とか `nkf` の2.1.3以降使えるならそれで代用できるはず。
6. いじってそのまま更新かけるので一旦一時ファイル。`awk -i` 使えれば(ry
7. 先頭行だけUTF-8を置換、他はそのままファイルに書き出す。
8. ファイルの内容をインデックスし直す。
    - **ファイルの一部をインデックスしている場合も全部コミット対象になるので注意**


----

## 感想

C#とかやってるとBOM付きも使うから、混在すると面倒だよね \_(:3」∠)_
エンジニア全員がソースからのmakeとか抵抗なければ、nkfとかfileとかawkとか使ったほうが絶対きれいになるよねこれ \_(:3」∠)_

## 参考

- [Git - Git Hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
ArduinoによるDMX512制御（DmxSimpleを使わない）



# 概要
Arduinoを使って照明用のDMX512を制御します。
以前に、DmxSimpleライブラリを使ってプログラムを作成しました(https://qiita.com/Ina3/items/9af8e14d991e8b1791d4 )が、DMX512の仕様書を読んで、仕様書通りにプログラムを作成して、DmxSimpleライブラリを使わずに制御できるようになりました。

# DMX512のプロトコル
ウィキペディアの技術的解説（https://ja.wikipedia.org/wiki/DMX512-A ）から引用すると、『DMX512のデータは EIA-485 の電気的仕様を使っている。DMXの仕様では、電気信号については EIA-485 を参照することになっている。データは250kbit/sでシリアルに伝送され、1度に連続転送されるのは最大513バイトのパケットである。1バイトを DMX512-A では「スロット」と呼ぶ。このプロトコルでは1ビットのスタートビットと2ビットのストップビットを使い、データはリトルエンディアンである。パケットの先頭には最低でも88μ秒のブレーク信号があり、それに最低でも8μ秒の "Mark After Break" (MAB) が続く（1986年の規格では4μ秒だったが1990年に拡張された）。ブレーク信号は受信側にデータが後に続くことを予告するものである。ブレーク信号の後に最大513スロットが送信される。最初のスロットは「開始コード」であり、後に続くデータの種類を知らせるものである。照明や調光器向けの開始コードはゼロである。』となっている。


# プログラムのポイント解説
文章ではわかりにくにので、図であらわすと、次のようになる。
![DMXframe.jpg](https://qiita-image-store.s3.amazonaws.com/0/211560/1f9e5eed-de2f-55dd-317d-1299e509850e.jpeg)

Arduinoのシリアル転送を使って、基本的には、速度は250000bps、データが8ビットでストップビットは2ビットに設定すると動く。しかし、1ビット当たり4μ秒のデータに対し、88μ秒という長いLowのBreak信号と８µ秒というHighの "Mark After Break" (MAB)はシリアルではタイミング的に作りにくい。そこで、デジタルに設定したピンからLowの信号とHighの信号を出力した後で、そのピンをシリアルに設定しなおして、必要なデータを送り、データ転送が終わったら、シリアル通信を終了することでDMX信号を作成できた。

# ハードウェア(シールド)
DMX512を使うためには電気的にEIA-485に合わす必要があり、そのためにLT1785,SN75176,LTC485等のRS485トランシーバICをArduinoに接続する必要があります。
引用した回路図
![fig04.jpg](https://qiita-image-store.s3.amazonaws.com/0/211560/b65a6e85-a658-6d31-8d7a-2a7ba6414e76.jpeg)

引用元( https://playground.arduino.cc/DMX/DMXShield )
作成したシールド
100均で買ったプラスチックの箱に、USBとキャノンの穴をあけました。Arduino Unoがぴったり入ります。LTC485はキャノンコネクタに直接ハンダ付して空中配線しています。
![fig11.jpg](https://qiita-image-store.s3.amazonaws.com/0/211560/f07c9cc5-40a4-fde3-0c5a-6bbdc8e2ef4d.jpeg)


# DmxSimpleライブラリーのプログラムからの移植
DmxSimpleライブラリ内のスケッチであるFadeUpDownを基に、DmxSimleライブラリを使わずに,同じ動作をするプログラムを移植していきます。

まずは、オリジナルのDmxSimpleライブラリ内にあるFadeUpDownです。
1行目でDmxSimleライブラリを読み込み、4行目でDMXの出力をPin1に設定しています。

```
#include <DmxSimple.h>
int brightness = 0;
void setup() {
 DmxSimple.usePin(1);
 DmxSimle.maxChannnel(4);
}
void loop() {
  for (brightness = 0; brightness <= 255; brightness++) {
    DmxSimple.write(1, brightness);
    delay(15);
  }
  for (brightness = 0; brightness <= 255; brightness++) {
    DmxSimple.write(1,255- brightness);
    delay(15);
  }
　delay(400); 
}
```

以下は、DmxSimpleライブラリを使わずに、DMXの定義に従って動くようにしたFadeUpDownです。DMXの出力は同じPin1です。

```
int brightness = 0;
int Tx = 1;//DMXoutputPin
void setup() {
}
void loop() {
    for (brightness = 0; brightness <= 255; brightness++) {
       writeDMX( brightness);
       delay(15);
      }
      
    for (brightness = 0; brightness <= 255; brightness++) {
       writeDMX(255- brightness);
       delay(15);
      }    
      delay(400);
}

void writeDMX(int x){
      pinMode(Tx,OUTPUT);
        digitalWrite(Tx,0);//Break as LOW
        delayMicroseconds(88);
        digitalWrite(Tx,1);//MAB as HIGH
        delayMicroseconds(8);
        Serial.begin(250000,SERIAL_8N2);
        Serial.write(0x0);//Start Code as 0
        Serial.write(x);//Ch1 Data
        Serial.end( );
 }

```
inline-blockで上下が中央に揃えるのに時間かかった

横並びの要素を上下中央に揃えたかったのに上手くいかず、少し詰まったのでメモ。

# 原因
flexでの揃え方など、別な方法とごっちゃになってた。

# 解決法

- 親要素にheightとline-heightを同じサイズで指定
- 子要素に`vertical-align: middle`を指定

これだけ。

```css
.parent {
    height: 100px;
    line-height: 100px;
}
.parent .child {
    display: inline-block;
    vertical-align: middle;
}
```

上下中央の指定とか左右中央の指定、結構忘れる。。。
Terraformで管理しているAWS EBSボリュームを入れ替える

Terraform v0.8 以降で state をローカル以外にしていた時に、terraform importできない、`aws_volume_attachment`のようなresourceを入れ替える方法です。

ディスクサイズの拡張はオンラインで出来るようになったため、EBSを切り替える必要はなくなっていますがディスクサイズの縮小が必要になってしまったので。

# 環境

- terraform v0.11.0
  - stateのバックエンドをs3にしている。他のバックエンドでも同じ手順でいけるとは思います。

# 手順

## `aws_ebs_volume`

EBSの入れ替えを行なった後にそのボリュームIDを控えておきます。
リソース名が`name`として

```bash
terraform state rm aws_ebs_volume.name
terraform import aws_ebs_volume.name vol-id
```

で `aws_ebs_volume` については入れ替えできます。


## `aws_volume_attachment`

まず、いまの stateファイルを取得します。

```bash
terraform state pull > state.tfstate
```

リソース名が`name`だったとして、stateファイルから `aws_volume_attachment.name` を探すとこんな感じになっているはずです。

```json
                "aws_volume_attachment.name": {
                    "type": "aws_volume_attachment",
                    "depends_on": [
                        "aws_ebs_volume.name",
                        "aws_instance.name"
                    ],
                    "primary": {
                        "id": "vai-id",
                        "attributes": {
                            "device_name": "/dev/sdb",
                            "id": "vai-id",
                            "instance_id": "i-id",
                            "volume_id": "vol-id"
                        },
                        "meta": {},
                        "tainted": false
                    },
                    "deposed": [],
                    "provider": "provider.aws"
                },
```
今回はこのボリュームを入れ替えたので、`attributes`の`volume_id`の値を、新しくしたEBSのボリュームIDにします。
また、この後stateファイルを入れ替えるので、stateファイルの`serial` を一つカウントアップしておきます。 `serial` でバージョンが管理されているためです。

書き換え終わったら下記を実行してバックエンド上のstateファイルを書き換えます。

```bash
terraform state push state.tfstate
```

これで `terraform plan` しても齟齬が出なくなって入れば完了です。
CWL User Guide 12: Environment Variables をやってみた

# CWL User Guide 12: Environment Variables

[Common Workflow Language User Guide: Environment Variables](http://www.commonwl.org/user_guide/12-env/)

今回は環境変数について書かれています

ツール実行時は、最小限の環境変数のみ、定義されています。
実行環境のみ適用される環境変数を定義することができます。

# この回にでてくる主なキーワード
* EnvVarRequirement



# CWLファイル、

```env.cwl
#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
baseCommand: env
requirements:
  EnvVarRequirement:
    envDef:
      HELLO: $(inputs.message)
inputs:
  message: string
outputs: []
```

# パラメータファイル

```echo-job.yml
message: Hello world!
```

# 実行

## 実行方法

```
cwltool env.cwl echo-job.yml
```

## 実行結果

```
$ cwltool env.cwl echo-job.yml
/usr/local/bin/cwltool 1.0.20171107133715
Resolved 'env.cwl' to 'file:///home/vagrant/cwl_user_guide_work/12-env/env.cwl'
[job env.cwl] /tmp/tmpz4s5sH$ env
PATH=/home/vagrant/bin:/home/vagrant/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
HELLO=Hello world!
TMPDIR=/tmp/tmpHRXOIj
HOME=/tmp/tmpz4s5sH
[job env.cwl] completed success
{}
Final process status is success
```

# 今回使ったファイル

[cwl\_user\_guide\_work/12\-env at master · manabuishii/cwl\_user\_guide\_work](https://github.com/manabuishii/cwl_user_guide_work/tree/master/12-env)
パワポにソースコードを書いてPDF変換するとコピペがうまくいかない問題と対策

# 問題と対処法のいくつかの候補

パワポで作成したプレゼンに、例示用のソースコードを記載して、
それをPDF化して配布することの善し悪しはさておき、
PDF化したドキュメント中のソースコードのコピペがうまくいかない場合の、
よくある原因と、その対策です。

## 引用符の変換問題

PowerPointには、引用符の見た目をきれいに整えてくれる、
親切機能があります。

`"(Unicode値: U+0022)`を人にやさしい、
`“(Unicode値: U+201C)`と、`”(Unicode値: U+201D)`、
`'(Unicode値: U+0027)`を人にやさしい、
`‘(Unicode値: U+2018)`と、`’(Unicode値: U+2019)`、
に変換してくれます。

多くのプログラマは通常、
`“(Unicode値: U+201C)`、`”(Unicode値: U+201D)`、`‘(Unicode値: U+2018)`と、`’(Unicode値: U+2019)`の記号は
使わないまま一生を終えると思うので、
プログラマにとっては、必要のない記号でしょう(断言はしません)。

### 対策

パワポのオプションから、
[文章校正] > [オートコレクション]の設定を変更します。
[入力オートフォーマット]から、勝手に変換して欲しくないオプションはオフにします。

すでに、作成済みの文章は、
全体確認して、
`“(Unicode値: U+201C)`、`”(Unicode値: U+201D)`、`‘(Unicode値: U+2018)`と、`’(Unicode値: U+2019)`は、
一切不要と判断したなら、全置換してしまうのもありかと。


## コピペすると記載内容が複数回繰り返されてコピペされる問題

PDFにアクセシビリティ用の構造タグ情報が含まれている場合に、
これらの付加情報も含めてコピーされるようです。
アクセシビリティ用の構造タグは、主には読み上げに利用される情報のようです。

### 対策

アクセシビリティ用の構造タグをPDFに含める必要があるかどうか判断した後、
コピペ問題を回避する目的の方が優先と判断した場合は、オフにします。

PowerPointから、PDFをエクスポートする際に、
[オプション]から、
[アクセシビリティ用のドキュメント構造タグ]のチェックを外して、
エクスポートします。


## その他

これで大抵のコピペ問題は回避できると思います。

見た目上だけの問題ですが、
パワポとかのデフォルトのフォントはプログラマ好みになっていないことが多いので、
プレゼン中もPDF配布資料も、ソースコード部分は、プログラマ好みの、
`ゼロ0`と`オーO`の区別が付きやすいやつとかにするのがGoodだと思います。

配布時には、フォントの権利に気を配りつつ、PDFに埋め込むとよいと思います。
Dash by Plotly で ｘの a 乗の可視化を行う

# 本日は　

Dashの対話機能の練習

- https://plot.ly/dash/getting-started-part-2

として $x$ の $a$ 乗を与える関数 $x^a$ の可視化と $a$ をパラメータとして動かした時にどのように変化するかをみてみましょう．

# 実装例

```py3
import dash
import dash_html_components as html
import dash_core_components as dcc
import numpy as np

app = dash.Dash()
graph = dcc.Graph(id='graph-with-slider',
                  figure={'layout': dict(height=400, width=300)})
slider = dcc.Slider(id='slider', min=0, max=20, value=3, step=0.1)

app.layout = html.Div(children=[graph,
                                html.Label('power'),
                                slider],
                      style=dict(height=400, width=400))


@app.callback(
    dash.dependencies.Output(component_id='graph-with-slider',
                             component_property='figure'),
    [dash.dependencies.Input(component_id='slider',
                             component_property='value')])
def update_figure(power):
    xs = np.linspace(0, 1, 100)
    ys = pow(xs, power)
    data = [dict(x=xs, y=ys, type='line')]
    return dict(data=data)

def main():
    app.run_server()
if __name__ == '__main__':
    main()
```

# 実行例

![xpowera.gif](https://qiita-image-store.s3.amazonaws.com/0/135978/2ae2afd8-9305-24d2-a00f-86b7828662d7.gif)

power　の下にあるスライダーを動かすとそれに応じてコールバック関数としてデコレートされた `update_figure` 関数が呼び出されます．この関数は，ここでは，`id`が`slider`のコンポーネントであるSliderの`value` を引数として受け取り，`id`が`graph-with-slider`であるコンポーネントの　`figure`キーの値（呼び方はこれでで良いのだろうか？）を更新させるためにオプジェクトを返します．

# 余談
このグラフを眺めていると$x$の$n$乗を与える関数列

```math
\left\{ x^n \right\}_{n=1}^{\infty}
```

の一様収束性を連想しますね．
懐かしや．
Juce Valueクラス

# 概要
共有バリアント値を表します。

バリューオブジェクトは、VARオブジェクトへの参照が含まれ、その値を取得および設定することができます。
リスナーを設定することができ、値が変更された場合通知を受けることができます。

値のクラスは、共有、参照カウント基礎となるデータ・オブジェクトのラッパーです。
これは、複数を参照する値オブジェクトは、すべてのそれらのいずれかがそれを変更したとき、それらのすべてが通知されることを可能にする、データの同じ部分を参照することができます。

デフォルトのコンストラクタでValueを作成すると、単純なvarオブジェクトを包むラッパーとして機能しますが、ValueSourceのカスタムサブクラスを参照するValueを作成することによって、Valueを任意の種類の基礎データにマップできます。

重要な注意点！バリュークラスはスレッドセーフではありません！
複数のスレッドからアクセスする場合は、アクセスするコードの周りに独自の同期を使用する必要があります。

#リファレンスへのリンク

[classValue](https://juce.com/doc/classValue)

## 雑感
listenerクラスはGUI関連が初期化されていないと使えない模様。
（イベントハンドラマネージャのようなものが初期化されていないためアサートが出る。）

そのため検証にはGUIアプリケーションでプロジェクトを作成した。

## 検証

[ソース github](https://github.com/Kurooka/JuceExamples/tree/master/ValueTest)


```cpp:ソース

class listenerTest : public Value::Listener
{
public:
	listenerTest() {}
	virtual ~listenerTest() {}

	virtual void valueChanged(Value& value)
	{
		juce::Logger::outputDebugString("valueChanged!");
	}
};
listenerTest listener;
juce::Value v;
juce::Value v2;

//==============================================================================
int valuetest() 
{
	//リスナーの追加
	v.addListener(&listener);

	v = 11;
	juce::Logger::outputDebugString("v(11) v=" + v.toString());
	v.setValue(19);
	juce::Logger::outputDebugString("v(18) v=" + v.toString());

	v2.setValue(v);
	juce::Logger::outputDebugString("v2(v)  v=" + v.toString() + "v2=" + v.toString());

	v = 11;
	juce::Logger::outputDebugString("v(11) v=" + v.toString() + "v2=" + v.toString());

    return 0;
}

```

```cpp:出力
v(11) v=11
v(18) v=19
v2(v)  v=19v2=19
v(11) v=11v2=11
valueChanged!
```

#注意点
ValueのListenerは標準の状態だとメッセージスレッドのメッセージループから遅延配信されるためそれ以前にデストラクトされるとメッセージが発信されない。(AsyncUpdater)
また、GUIが初期化されていないとメッセージスレッドが作成されていないため機能しない。
（そのためサンプルではグローバル変数化しGUIアプリとして作成している。）
用途としてはコンポーネントなどのクラスに内包してGUIで使用することになると思うのでこの仕様でよさそうだが一応仕様は留意しておきたい。
CWL User Guide 11: Advanced Inputs をやってみた

# CWL User Guide 11: Advanced Inputs

[Common Workflow Language User Guide: Advanced Inputs](http://www.commonwl.org/user_guide/11-records/)

今回は入力パラメータについて、高度な設定ができることが書かれています

# この回にでてくる主なキーワード
* record

今回は、これまでとちがい、３ケースためしています。

* １つ目は、エラーになるケース
* ２つ目は、エラーにならないケース、排他的な指定
* ３つ目は、エラーにならないケース、２つ目の少し違う形のもの

# CWLファイル、record.cwl

```record.cwl
#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
inputs:
  dependent_parameters:
    type:
      type: record
      name: dependent_parameters
      fields:
        itemA:
          type: string
          inputBinding:
            prefix: -A
        itemB:
          type: string
          inputBinding:
            prefix: -B
  exclusive_parameters:
    type:
      - type: record
        name: itemC
        fields:
          itemC:
            type: string
            inputBinding:
              prefix: -C
      - type: record
        name: itemD
        fields:
          itemD:
            type: string
            inputBinding:
              prefix: -D
outputs: []
baseCommand: echo
```

# パラメータファイル１，record-job1.yml

```record-job1.yml
dependent_parameters:
  itemA: one
exclusive_parameters:
  itemC: three
```

# 実行

## 実行方法

```
cwltool record.cwl record-job1.yml
```

## 実行結果1

```console
$ cwltool record.cwl record-job2.yml
/usr/local/bin/cwltool 1.0.20171107133715
Resolved 'record.cwl' to 'file:///home/vagrant/cwl_user_guide_work/11-records/record.cwl'
record-job2.yml:6:3: invalid field `itemD`, expected one of: 'itemC'
[job record.cwl] /tmp/tmpxn1Gb8$ echo \
    -A \
    one \
    -B \
    two \
    -C \
    three
-A one -B two -C three
[job record.cwl] completed success
{}
Final process status is success
```

# パラメータファイル２

```record-job2.yml
dependent_parameters:
  itemA: one
  itemB: two
exclusive_parameters:
  itemC: three
  itemD: four
```

## 実行方法2

```
cwltool record.cwl record-job2.yml
```

## 実行結果2

```console
$ cwltool record.cwl record-job2.yml
/usr/local/bin/cwltool 1.0.20171107133715
Resolved 'record.cwl' to 'file:///home/vagrant/cwl_user_guide_work/11-records/record.cwl'
record-job2.yml:6:3: invalid field `itemD`, expected one of: 'itemC'
[job record.cwl] /tmp/tmpxn1Gb8$ echo \
    -A \
    one \
    -B \
    two \
    -C \
    three
-A one -B two -C three
[job record.cwl] completed success
{}
Final process status is success
```

# パラメータファイル3


```record-job3.yml
dependent_parameters:
  itemA: one
  itemB: two
exclusive_parameters:
  itemD: four
```

## 実行方法3

```
cwltool record.cwl record-job3.yml
```
## 実行結果3

```console
$ cwltool record.cwl record-job3.yml
/usr/local/bin/cwltool 1.0.20171107133715
Resolved 'record.cwl' to 'file:///home/vagrant/cwl_user_guide_work/11-records/record.cwl'
[job record.cwl] /tmp/tmp5enbk2$ echo \
    -A \
    one \
    -B \
    two \
    -D \
    four
-A one -B two -D four
[job record.cwl] completed success
{}
Final process status is success
```

# 今回使ったファイル

[cwl\_user\_guide\_work/11\-records at master · manabuishii/cwl\_user\_guide\_work](https://github.com/manabuishii/cwl_user_guide_work/tree/master/11-records)
Dockerにubuntuのコンテナを作成・日本語化する

##ubuntuのimageをpullする
```
$ docker ubuntu
```
※ここで一回通らなかったので、プロキシを設定しました。

##コンテナ作成・実行
```
$ docker run -i -t ubuntu /bin/bash
```


##日本語化
```
root #  locale-gen ja_JP.UTF-8
bash: locale-gen: command not found
```
locale-genが使えない。

↓のブログによると、language-pack を入れないといけないようです。
[docker の ubuntu イメージで日本語が入力できない件](http://www.getto.systems/entry/2016/04/13/114059)

##language-pack入れて日本語化

```
root #  apt-get install language-pack-ja-base language-pack-ja
root #　locale-gen ja_JP.UTF-8

Generating locales (this might take a while)...
  ja_JP.UTF-8... done
Generation complete.

```

できたっぽい。

```
root #  echo export LANG=ja_JP.UTF-8 >> ~/.profile
root #　source ~/.profile
root #　date
2017年 11月 29日 水曜日 10:26:01 UTC
```

というわけでできました！
《JavaScript》p5.jsでcanvasを任意の場所に配置する方法。



p5.jsが出力する `canvas` は `</body>` のすぐ上に配置されるようになっています。このままだと取り回しがしにくいので、任意の場所に移動させます。

## HTMLに要素をつくる
html に `canvas` の親要素とするラッパーを任意の `id` を割り当てて記述します。


```html

<div id="canvas"></div>

```


## setup() 関数で挿入箇所を指定
p5.jsの `setup()`  関数の中で、生成される `canvas` の親要素を変更します。


```js

let canvas = createCanvas(300, 300);
canvas.parent('canvas');

```

`createCanvas()` の返り値のオブジェクトを格納して、 `parent()` メソッドを実行することで、 `canvas`を指定した `id` を親要素として挿入することが出来ました。





おわります。
オンプレでのサーバ公開準備(セッション追加)

## はじめに
クラウドで動いているサーバをオンプレに移したいと思っている。
コストにはクラウドの方がリーズナブルだとは思っている。

ネットワークも含めたサーバ環境を自宅に置き触れ合いたい気持ちが強い。

## セッション追加の目的
- 固定グローバルIP利用の為、セッション追加が必要。<BR>
※別途プロバイダー契約は必要となる。

## 調べた事
- 個人契約では標準2セッション。
- 最大5セッションまで利用可能。
- 光電話は1セッション消費する。
- 光コラボレーションでもセッション追加可能。
  
## 現在の環境
- 光電話を使用中(合計2セッション使用中)
- ソフトバンク光
    
・ソフトバンク光でのセッション追加に関して
https://www.interlink.or.jp/service/flets/multisession.html
     
## 費用
- フレッツ・セッションプラス<BR> 

月額利用料324円/1セッション
基本工事費(1回の工事) 1,000円

・フレッツ・セッションプラス価格参考
https://flets.com/sessionplus/

- プロバイダー契約インターリンク<BR>

固定IP 1個 1,296円/月
固定IP 2個 2,376円/月
固定IP 4個 3,456円/月
初期費用無料

・インターリンク価格参考
https://www.interlink.or.jp/service/flets/b/price.html

## ざっくりした構成イメージ
- 図にはないけど、ROUTERからESXiへ直結させてメンテナンスセグを繋げる予定。
- ESXiホストサーバは構築済み。
- 仮想ルータはSEILを使う予定（2ライセンス所持）
- SEIL参考(https://www.seil.jp/doc/index.html#index/operation.html)

　　　![Network Diagram.png](https://qiita-image-store.s3.amazonaws.com/0/160993/d12af5b0-edf8-4e62-8280-bd12f0e4cda7.png)

## まとめ
光コラボでもセッション追加で固定グローバルが使えそう。
初期費用は2,000円～3,000円程度。
Google Home に話しかけて Slackに投稿し、話しかけた内容に反応するbotを作った話

## はじめに

会社の会議室兼FabスペースSonorite Creative Satellite(SCS)にGoogle Homeさんがやってきました。
とりあえずHackしたくなるのがエンジニアの性というもの。

備品管理とか大変なので、備品が無くなった報告をSlackにストックできるといいよねということで、IFTTT経由でSlackに飛ばすようにしました。

とりあえずやってみたら、「これもうちょっとかしこい返事できるようになったら便利じゃね?」ということでIFTTTの投稿に反応するbotも作ることに。

## 開発環境
言語 : Python 3.6
使用ライブラリ : slackbot (https://github.com/lins05/slackbot)
参考サイト : https://qiita.com/sukesuke/items/1ac92251def87357fdf6

Slack上でbotユーザー作ってー
ライブラリインストールしてー
それっぽい応答文作ってー
人間の投稿に反応すること確認してー
IFTTTの投稿も反応すること確に…だめでした
といった感じでハマりました。

## 対応策
1, 別のライブラリを試す
会社がMS系のあれこれをやっているので MS bot FrameWorkを試す
結構頑張って、Slackに繋いだけど、こちらでもIFTTTの投稿は拾え無かった。
IFTTTの投稿にだけ反応してくれないので、IFTTT→Slackに送られてくるやつがおかしいのでは?という仮説が立った

2, ライブラリをフォークしてデバッグ
やっぱりPythonでやろうってことで、改めてslackbotのリポジトリを見に行った。
IFTTT対応する雰囲気もないのでForkさせて頂いて、ローカル環境でコードを読みつつ投稿拾ってそうな場所にデバッガを仕込み、ユーザの投稿とIFTTTの投稿を比較

IFTTT経由のメッセージのJSONと通常のメッセージのJSONの形式が違っていたことが判明
ユーザ名がIFTTTだった場合JSONを綺麗にする処理を実装し、無事IFTTTの投稿を拾うことができるようになった

## その後
想定できる範囲内で、応答文を作り
ついでに「機材どこ?」っていう問い合わせにも反応できるようしてー
IFTTT or ユーザとbotとのやり取りをloggingするようにしてー
AzureにUbuntuマシンにデプロイして、社内にリリース
今のところちゃんと動いています

## 今後の課題
Google Homeに話しかけると、返事がSlack上に文字列として帰ってくるという歪なコミュニケーションスタイルが形成されているので、Google Homeが喋って返事できるようしたいなぁとか
備品購入はbotのレスに対してスタンプつけたら発注メール飛ばしたいなぁとか
思いつきで作ったからbotのキャラ設定ガバガバだなぁとか
やることいろいろあるんでゆるゆると改造していこうと思っています。

## まとめ
ガジェットが届いたらとりあえず遊ぶ
Google Homeはポンコツかわいい
わたしは魔改造する人とGoogle Homeに認識されたのか、何を聞いても「わかりません」と言われている(悲しい)
CWL User Guide 10: Array Outputs をやってみた

# CWL User Guide 10: Array Outputs

[Common Workflow Language User Guide: Array Outputs](http://www.commonwl.org/user_guide/10-array-outputs/)

今回は配列形式や、ワイルドカードで出力を指定できることについて書かれています


# この回にでてくる主なキーワード
* glob

# CWLファイル、array-outputs.cwl

```array-outputs.cwl
#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
baseCommand: touch
inputs:
  touchfiles:
    type:
      type: array
      items: string
    inputBinding:
      position: 1
outputs:
  output:
    type:
      type: array
      items: File
    outputBinding:
      glob: "*.txt"
```

# パラメータファイル

```array-outputs-job.yml
touchfiles:
  - foo.txt
  - bar.dat
  - baz.txt
```

# 必要なファイル

# 実行

## 実行方法

```
cwltool array-outputs.cwl array-outputs-job.yml
```

## 実行結果

```
$ cwltool array-outputs.cwl array-outputs-job.yml
/usr/local/bin/cwltool 1.0.20171107133715
Resolved 'array-outputs.cwl' to 'file:///home/vagrant/cwl_user_guide_work/10-array-outputs/array-outputs.cwl'
[job array-outputs.cwl] /tmp/tmpXAVRki$ touch \
    foo.txt \
    bar.dat \
    baz.txt
[job array-outputs.cwl] completed success
{
    "output": [
        {
            "checksum": "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709",
            "basename": "baz.txt",
            "location": "file:///home/vagrant/cwl_user_guide_work/10-array-outputs/baz.txt",
            "path": "/home/vagrant/cwl_user_guide_work/10-array-outputs/baz.txt",
            "class": "File",
            "size": 0
        },
        {
            "checksum": "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709",
            "basename": "foo.txt",
            "location": "file:///home/vagrant/cwl_user_guide_work/10-array-outputs/foo.txt",
            "path": "/home/vagrant/cwl_user_guide_work/10-array-outputs/foo.txt",
            "class": "File",
            "size": 0
        }
    ]
}
Final process status is success
```

## 実行結果確認

以下の２つの点が確認できます

* `baz.txt` `foo.txt` が存在すること
* `bar.dat` が存在しないこと

```
$ ls
array-outputs.cwl  array-outputs-job.yml  baz.txt  foo.txt
```

# 今回使ったファイル

[cwl\_user\_guide\_work/10\-array\-outputs at master · manabuishii/cwl\_user\_guide\_work](https://github.com/manabuishii/cwl_user_guide_work/tree/master/10-array-outputs)
UE4でVR空間にカノジョを錬金 14日目

[UE4でVR空間にカノジョを錬金する Advent Calendar 2017](https://qiita.com/advent-calendar/2017/ue4vrgame-create) 14日目の記事です。

12/1～25日までに一人で、UE4を用いてサ○○レッスンとかVR○○ジョっぽいゲームを作って仮想彼女を生み出すことにチャレンジします。

今回も前回に続き、ゲーム全体の流れを制御するゲームマネージャークラス作成です。

#GameManagerロジック実装

視線入力による選択後の処理は7日目に記述しているので、ここでは省略します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/5ce9a594-b732-89b4-b180-f369682a2fa1.png)

GameManagerクラスに視線入力選択後のカスタムイベントを作成します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/1efdd5d5-99a2-4819-afce-7cdfc3c5abb5.png)

このカスタムイベント呼出し後、一つボイスを流してゲーム終了です。

最後にDelayが付いているのは、OpenLevel処理を呼び出していたためです。
ここでは諸事情で削除しています。

これでXR GameJam in Japan 2017 Autumnで実装した処理は以上になります。

# XR GameJam in Japan 2017 Autumnでのまとめ

読み手の方に伝わったかどうかはわかりませんが、2日目～14日目の処理を実装すると以下のようになるハズです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">今回作ったものです。「クリスマスカノジョ」、例のアドカレのネタです<br>UE4で作りました。 色々と遅く始めたので作りが甘いのは仕方ないといいうことで <a href="https://twitter.com/hashtag/XRGJ?src=hash&amp;ref_src=twsrc%5Etfw">#XRGJ</a>　<a href="https://twitter.com/hashtag/XRGJGinza?src=hash&amp;ref_src=twsrc%5Etfw">#XRGJGinza</a>  <a href="https://twitter.com/hashtag/ue4?src=hash&amp;ref_src=twsrc%5Etfw">#ue4</a> <a href="https://t.co/fuaRsR6muc">pic.twitter.com/fuaRsR6muc</a></p>&mdash; 荻野雄季 (@YuukiOgino) <a href="https://twitter.com/YuukiOgino/status/934709537428221952?ref_src=twsrc%5Etfw">2017年11月26日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

たった２日で作ったので、ブループリントのロジック含めて色々とガバガバなのはご了承ください。

他にもUE4からFBXエクスポート、アニメーションのリターゲットとか色々とやっています。
この部分はプログラムに関係なく、Qiitaに書いて良いのかちょっと判断が付かなかったので、一旦省きます。

※どうしても書くネタに困ったら書くかもしれません

次回以降は何をしようか考えていませんが、25日までに改良や追加機能を入れれるだけ入れていきます。
オープンソースのAndroidライブラリ 5選

GitHubで公開されているオープンソースのAndroidライブラリの紹介です。

# No.1
#### wasabeef/awesome-android-libraries
![92388408666075213094a7d7c18388ed.png](https://qiita-image-store.s3.amazonaws.com/0/200848/37c7c8bc-fec6-9885-3bda-fdccdd0bb67c.png) 
積極的に活用されているAndroid開発用のライブラリのアルファベット順のリスト。  
https://twitter.com/wasabeef_jp  
Star:3,976🌟  
[https://github.com/wasabeef/awesome-android-libraries:embed:cite]

# No.2
#### codepath/android_guides  
![687474703a2f2f646576656c6f7065722e616e64726f69642e636f6d2f696d616765732f66756e64616d656e74616c732f667261676d656e74732e706e67.png](https://qiita-image-store.s3.amazonaws.com/0/200848/70e02c32-a3cc-ab4d-a32d-fb3ab47fa97e.png)
 
Android用のサードパーティのライブラリがたくさんありますが、  
ほとんどのAndroidプロジェクトでよく使用されるライブラリが必要です。  
それぞれに異なる目的がありますが、  
それらのすべてが開発者としての生活をはるかに楽しくします。  
主要なライブラリはカテゴリ下にリストされています。   
Star:20,412🌟  
[https://github.com/codepath/android_guides/wiki/Must-Have-Libraries:embed:cite]

# No.3  
#### stfalcon-studio/ChatKit
![HEADER.jpg](https://qiita-image-store.s3.amazonaws.com/0/200848/ff460baa-e132-b636-dc05-9557b4c6f116.jpeg)
 
Androidライブラリ  
スタイリング、カスタマイズ、データ管理に柔軟に対応できる、  
チャットUI実装のための柔軟なコンポーネント  
[http://stfalcon.com:title]    
Star:1,476🌟  
[https://github.com/stfalcon-studio/ChatKit:embed:cite]

# No.4  
#### JStumpp/awesome-android
![awesome-android.png](https://qiita-image-store.s3.amazonaws.com/0/200848/13077a86-e790-999a-a4bf-a26a9acdb800.png)

すばらしいAndroidパッケージとリソースの一覧表。  
Star:4,723🌟  
[https://github.com/JStumpp/awesome-android:embed:cite]


  
# No.5  
#### facebook/fresco 
![og_image.png](https://qiita-image-store.s3.amazonaws.com/0/200848/ae708c93-56a6-9d79-833f-eeedc6790c1d.png)

画像やそれらが使用するメモリを管理するためのAndroidライブラリ。  
[http://frescolib.org/:title]  
Star:13,775🌟  
[https://github.com/facebook/fresco:embed:cite]
自社サービスで行っている画像最適化について

```
ページ読み込みが3秒以上かかると53%のユーザーが離脱
```

※[Google Developers Japan](https://developers-jp.googleblog.com/2017/03/new-industry-benchmarks-for-mobile-page-speed.html)より引用

自社サービスも計測した結果、読み込みにに10秒以上かかっていて、[PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/)での点数では30点台と低い数値となっていました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/73749/acbaa1c3-0efa-78ae-cf4d-a8c8d339ee78.png)
※PageSpeed Insights図

システム・クリエイティブの少数精鋭でサイト最適化・高速化の改善を半年以上かけて行い、ウェブサイトの表示速度を2秒台まで縮め、最適化の点数も最大で80点台を出すことに成功しました。

その中で改善項目の一つでもあった**「画像最適化」**について簡単にお話しをしたいと思います。


# **画像最適化**
webページ上のダウンロード容量を調べたところ、ほとんどが画像で占めていました。
最適化することでwebページの容量の大幅な削減やパフォーマンス改善に繋がります。


## 画像圧縮はコマンドラインで
これまで外部webサービスの**「TinyPNG」**を利用して画像圧縮を行ってきましたが、コマンドラインを使用したフローに変更しました。


```lang:メリット
導入が楽
引数にオプションつければなんでもできる
作業スピードの短縮にも大きく繋がった
```


## 圧縮しよう
- 拡張子pngは`pngquant`を使用。
- 拡張子jpgは`jpegoptim`を使用。

## インストール

```
brew install pngquant //PNG
brew install jpegoptim //JPG
```

## 使い方

### **pngquant**

sample.pngを圧縮してみる。

```
pngquant --ext .png --force sample.png
```

`--ext`と`--force`はオプションです。
`--ext`は拡張子等。
`--ext -new.png`にすると、sample.pngが`sample-new.png`として保存されます。
`--force`は上書きオプションです。

### **jpegoptim**

sample.jpgを圧縮してみる。

```
jpegoptim --max=80 sample.jpg
```

`--max`はオプションです。
上記例の`--max=80`は品質80%で圧縮してくれます。


## 圧縮前・後の画像を比較
横幅150px 縦幅94pxの画像をコマンドラインにて圧縮した比較が以下になります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73749/d6a02621-58d3-a146-346a-66748aefa838.png)

見栄えもほぼ変わらず、容量を-2 KB縮めることが出来ました。
今回、例にあげた画像は容量が低めでしたが、500 KB近く容量がある画像などもあったりします。その場合は画像サイズを縮め、そこから圧縮することによって5〜6 KBほど圧縮するようにしています。
この作業を画像サーバーにアップした段階で自動で圧縮する仕組みも考えましたが、画像によっては荒くなって見えづらくなる問題もあったため、地道に手作業で一つ一つ圧縮し、目視で画像を確認するようにしています。

地道にこういったフローを踏みつつ、画像最適化の作業を進めています。地味な作業かもしれませんが、大幅にサイトパフォーマンスを改善することが出来ました。
サイトが重いと感じた方は、ぜひこのフローを取り入れてみてもよいかもしれません。
fastlane matchの簡易使い方

# fastlane matchの使い方

ドキュメントとかはここを読むといいです。
https://docs.fastlane.tools/actions/match/

## 概要
matchは「Easily sync your certificates and profiles across your team using git」と説明されている通り。
チームでProvisioning Profile等の管理を簡単にするためのツールです。

1. 管理者が証明書とProvisioning Profileを作る（そしてgitに証明書等が上がる）
2. ほかの人はreadonlyでコマンドを一回たたけばgit上の証明書とProvisioning Profileがインストールされる

という手順になります

CIなんかでもいちいち証明書の更新しなくちゃーとかいうのがなくなるので楽になります。
っていうか今は個人アカウントでもdevelopの証明書使えるのでこっちの用途が強いかも

## 使い方

### 初期設定
ドキュメントにあるように
以下のコマンドたたいてgit_urlをいれればおしまいです。

```
fastlane match init
```

### 証明書とprovisioning profilesの作成

以下のコマンドをたたくと証明書作成が始まります。
基本的にはユーザー名入れてログインして…
とかコンソール通りにやっていけばいいのですが、途中で【**Passphrass for Git repo**】とパスワードを聞かれる場所があります。
ここは、gitのパスワードとかではなく**新しく作る証明書のパスワード**になってます。
また、これはチームに共有する必要があるので注意してください。

このパスワードは環境変数「MATCH_PASSWORD」で先に設定しておくこともできます。

```
fastlane match development
```
※developは各必要なmethod_typeに置き換えてください。adhocとかenterpriseとかapp-storeとか

さてこれで証明書とprovisioningprofileが作成できました。
ちなみに新しく増やしたりしたい場合は同じコマンドで追加していけばOKです。

~~このコマンドたたいた時点で古いprovisioningは作り直してくれそうなこと書いてありました。(未確認です)~~
~~spaceshipが有効期限切れのprovisioningを返せないようなので作り直せないみたいです。~~
正しく期限切れのprovisioningを更新してくれるようになったようです


ちなみにこんな形でコマンド内で効かれる内容を引数で指定してあげることもできます。

```
export MATCH_PASSWORD="itunesのパスワード"

fastlane match development --git_full_name gitのユーザー名 --username itunesのユーザー名 --app_identifier ${AppId} --git_url 管理用のgitのurl 
```

### チームに共有とインストール

後はチームに共有したりCi回すときに以下のコマンドたたいたりするだけです。

readonlyオプションを入れるとgitへのアクセスだけになるのでDeveloperProgramへのログインが必要なくなります。
（＝パスワードを知る必要がなくなる）

証明書のパスワードは必要なのでちゃんと共有しましょうね。

```
# Git リポジトリ設定
fastlane match init
fastlane match development --readonly

```

## gymと組み合わせて

match使ってからgym使うと証明書のインストールとかの手順がスキップされるのでとても楽ができます。
Xcode9からはこれが必要になりました。

## 新しいapp idを作るとき

新しいapp idでprovisioning profileを作りたいときはproduceと合わせます。

```
fastlane produce -a ${app_identifier} --skip_itc
```

このようにすることで新しいapp_identifierが作られるのでそのあとに再度matchをするとよさそうです。
（ちなみにエラー文にちゃんとのっています。）

## 注意

このmatchで作られたprovisioning profileやcerファイルは
なんかよくわからないけど加工がしてあって
手動でインストールしても動きません。
読込失敗するはずです。
これに関してはドキュメントに詳しい記述が追記されているのでそちらを参照してください。


手動でインストールする用のprovisioning profileがほしい場合以下のコマンドで取得できます。

```
fastlane sigh download_all [--team_id チーム名] -o . -u itunesユーザー名 [--skip_install]
```
UE4でVR空間にカノジョを錬金 13日目

[UE4でVR空間にカノジョを錬金する Advent Calendar 2017](https://qiita.com/advent-calendar/2017/ue4vrgame-create) 13日目の記事です。

12/1～25日までに一人で、UE4を用いてサ○○レッスンとかVR○○ジョっぽいゲームを作って仮想彼女を生み出すことにチャレンジします。

今回も前回に続き、ゲーム全体の流れを制御するゲームマネージャークラス作成です。

#GameManagerロジック実装

前回の続きです。うなずきアクションで選択したら、ボイスを再生後、視線入力の選択肢を表示します。

うなずきアクション自体の選択後処理は10日目に紹介しているので、その部分は省略します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/34a4fe1e-389f-9f2f-698d-3453a2f0f734.png)

GameManagerにYES、NO用のカスタムイベントを作成します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/58478bd6-db05-6afb-4310-cd2fc520c79a.png)

最後に選択肢を表示しています。選択肢の表示自体はレベル上に配置しているため、タグをつければ取得できます。

今回、選択肢のブループリントに「Select」というタグをつけています。
そこで全選択肢表示のロジックを呼んでいるだけです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/bcadae93-e6e3-3879-1fae-8e13baac4e77.png)

これで選択肢の表示ができました。
今回はここまでです。

#次回
次は視線入力の選択後の処理を書きます。
XR GameJam in Japan 2017 Autumnで実装した処理は次で最後になります。
JIRAの issue id を gitのコミットメッセージに含める

## やりたいこと

- コミットログを見た時に、どの問題の修正なのかを把握したい。
- JIRAの issue id があると分かりやすいのでコミットメッセージに含めておきたい
- ブランチ名に issue id が含まれていたら その issue id をコミットメッセージに含めるようにしておく

## やること

- branch 切る時に issue id を含めるようにする
    - DEV-1101-fix-hoge みたいな感じ

- 下記のファイルを .git/hooks/commit-msg として配置
- chmod +x する。

```bash
# !/bin/sh
#
# .git/hooks/commit-msg
#


COMMIT_FILE=$1
COMMIT_MSG=$(cat $1)
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
JIRA_ID=$(echo "$CURRENT_BRANCH" | grep -Eo "[A-Z0-9]{1,10}-?[A-Z0-9]+-\d+")
MSG_WITHOUT_COMMENT=$(grep -v '^\s*#' $COMMIT_FILE |grep -v '^\s*$')

if [ -n "$JIRA_ID" -a -n "$MSG_WITHOUT_COMMENT" ]; then
    echo "[$JIRA_ID] $COMMIT_MSG" > $COMMIT_FILE
    echo "JIRA ID '$JIRA_ID', matched in current branch name, prepended to commit message. (Use --no-verify to skip)"
fi
```

コミットすると下記のようにissue id が挿入される。

```
[DEV-1101] Fix typo
```

### 引用元

- https://gist.github.com/robatron/01b9a1061e1e8b35d270
    - このままだとコメントしなくてexitしたときにもコミットされてしまうので少し修正
取れなかった電話に対して、クリック１回で折り返す方法。

#結論
がんばればできるけど、頑張ってやるより、できるようになるのを待っていたほうがいい。

#理由

Amazon Connect インスタンス全体の情報をとるAPIがありません。
画面で言うと、
https://makxas.awsapps.com/connect/real-time-metrics/landing
上記AWSの中の人が明確にないと言っていた画面
と
https://makxas.awsapps.com/connect/ctr/
です。

Amazon Connectは外部から買ってきたサービスなので、APIがない珍しいサービスとなっています。
上記APIがない問題については、中の人も把握しており、そのうち解決されるのではないかとのことです。

もし現段階で強引にやりたいなら、各エージェントのCCPから 公式のJSライブラリを使って、情報を取得して、その結果を各Clientからアップロードして、そのデータをもとに折り返すということになりますが、現実的ではないです。

なので、しばらく待ちましょう。
[AWS] Lambdaの内部処理結果をキャッシュする（Python3.6）


# やりたいこと
AWS Lambdaで何か処理をするとき、DynamoDBやS3などからデータを取得するケースがあると思いますが、変更されることが少ないマスタデータを参照する場合にDynamoDBやS3から毎回Getしていると処理コスト（速度・料金）の無駄が多くなります。
そこで、そのようなリアルタイムで最新化されている必要性が薄いデータをLambda内部でキャッシュし再利用することで、処理コストを削減します。

# 前提
言語バージョン：Python3.6

# サンプルコード
```py
# coding: utf-8

# キャッシュ変数（global）
cache = {}

# AWS Lambda メイン処理
def lambda_handler(event, context):
	count	=	event["count"]
	print("{0}: ".format(count), end="")

	# キャッシュに"test"があればキャッシュから取得、無ければ計算
	result	=	get_cache("test", (lambda:func_addition(10000, count)), 4)
	print(result)

# 結果をキャッシュしたい処理
def func_addition(a, b):
	result	=	a + b
	print("*", end="")
	return result

# キャッシュ処理
def get_cache(key, func, expiration_seconds = 60):
	import datetime
	global cache

	# キャッシュから取得
	if key in cache:
		now = datetime.datetime.now()
		if (cache[key]["updated"] + datetime.timedelta(seconds=expiration_seconds)) > now:
			return cache[key]["value"]

	# キャッシュ更新
	value	=	func()
	cache[key]	=	{
		"updated" : datetime.datetime.now(),
		"value"   : value
	}
	return value

# テスト用のMain処理
if __name__ == '__main__':
	for i in range(1, 16):
		lambda_handler({"count": i}, None)
		import time
		time.sleep(1)

```

## 実行結果

上記サンプルコードを AWS Lambda Function としての実行ではなく、ローカルで実行した場合。

```
$ python lambda_cache.py
1: *10001
2: 10001
3: 10001
4: 10001
5: *10005
6: 10005
7: 10005
8: 10005
9: *10009
10: 10009
11: 10009
12: 10009
13: *10013
14: 10013
15: 10013
```
こちらのサンプルでは４秒間キャッシュされます。
キャッシュしたい処理が実際に動いたときだけ、`*`付きで出力されています。


# 利用方法

* グローバル変数「cache」を宣言

```py
# キャッシュ変数（global）
cache = {}
```

* キャッシュ処理ファンクションを定義

```py
# キャッシュ処理
def get_cache(key, func, expiration_seconds = 60):
    ...
    （サンプルコード参照）
    ...
```
* キャッシュ処理をコール

```py
result	=	get_cache(<cache_key>, lambda:<function(args)>, <expiration_seconds>)
```
&lt;cache_key&gt; ... キャッシュキー。任意の値
&lt;function(args)&gt;  ... キャッシュしたい処理
&lt;expiration_seconds&gt; ... キャッシュ有効期間。「0」でキャッシュ無効化。

ポイントは、get_cacheをコールするときにキャッシュしたい処理を lambda で定義すること。AWS の Lambda ではなく、Python の lambda式 です。
ここを `lambda:function_name(args)` ではなく `function_name(args)` にしてしまうと、get_cacheをコールする時点、つまりキャッシュを利用するかどうか判定する前に実行されてしまい、キャッシュ処理関数を通す意味が無くなります。

# 説明

* キャッシュの持ち方。
グローバル変数に入れているだけです。[こちらの記事](https://qiita.com/NewGyu/items/44b4c384f3cef27598ae) で説明されている通り、Lambdaのインスタンスは再利用されています。
同じインスタンスを使用している間はグローバル変数は初期化されませんので、次回に引き継げます。
値と更新日をセットで保存し、キャッシュ有効期限を判定できるようにしています。

* 指定した時間、必ずキャッシュが利用されるわけではない。
別のインスタンスに切り替わるタイミングはAWS任せになるため、有効期限前でもインスタンスが切り替わることでキャッシュがクリアされることがあります。

* キャッシュをクリアしたいときは。
運用中のLambdaにおいて、キャッシュをクリアしたいケースもあると思います。そのときはlambdaを更新しましょう。
何か１つ設定（たとえばlambda環境変数）を更新すれば、以降は新しいインスタンスで実行されるようです。（公式に謳われているわけではないので保証はできませんが）
また、グローバル変数に保存しているだけですので、コード内で何か条件を付けて `cache={}` または `del cache[key]` とするだけでもキャッシュはクリアできます。


# 別案
DynamoDBの場合は[『Amazon DynamoDB Accelerator (DAX) 』](https://aws.amazon.com/jp/blogs/news/amazon-dynamodb-accelerator-dax-in-memory-caching-for-read-intensive-workloads/)というサービスがありますので、そちらを利用したほうが良いかもしれません。
ただし個人で使うにはちょっと料金がちょっとお高めですが。
UE4でVR空間にカノジョを錬金 12日目

[UE4でVR空間にカノジョを錬金する Advent Calendar 2017](https://qiita.com/advent-calendar/2017/ue4vrgame-create) 12日目の記事です。

12/1～25日までに一人で、UE4を用いてサ○○レッスンとかVR○○ジョっぽいゲームを作って仮想彼女を生み出すことにチャレンジします。

今回はゲーム全体の流れを制御するゲームマネージャークラスを作成します。
とはいっても、実質ボイス再生制御のブループリントになってますがｗ

GameManagerも下手に作ったのでちょっと長くなってしまっているため、分割して紹介します。

#GameManagerロジック実装

まず、最初の処理です。ボイスはユニティちゃんの公式ボイス素材から適当に引っこ抜いています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/77c41bea-ac6d-8cf1-9d04-894b2a74e8e5.png)

ボイス（サウンド）ファイルの長さはSoundのDurationから取得できるので、その値をDelayにかけて待ちます。

ただ、ユニティちゃんボイスをそのまま流すと後ろの余白がないせいか、変なしゃべり方になってしまうので、Delayの秒数をある程度加えるのもいいかもしれません。
ゲームジャム中は調整の時間がなかったので、Durationの値そのままを使っています。

一通りボイスの再生が終わったら、最後にPlayerタグからMotionControllerPawnにうなずきアクション表示イベントを参照して、表示するように実装します。

MotionControllerPawnに追加処理を書きます。　
カスタムイベントを作成し、うなずきUIにUIのスポーンをするようにメソッドを呼びます。

スポーンのブループリントには「Action」タグをつけているので、そのタグ経由で参照できるように実装しています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/c9575771-06c0-bc57-d1b9-39945e9cebd1.png)


スポーンの詳細は9日目で紹介したので省きます。
今回はここまで。

#次回

次はうなずきアクション後のボイス再生、および視線入力の選択肢表示を実装します。