OmniAICreator/Qiita-1.07M huggingface dataset:
EgretEngineの統合開発環境EgretProが3/1リリースされる & ロードマップが発表される

# 元の記事
https://mp.weixin.qq.com/s/Uwi26GeOhS_VgA_r7ZFZxQ

# Egret Proとは？

EgretEngineの3Dエディター

Egret2D/Egret3Dはゲームエンジンそのもので、EgretProは統合開発環境という位置づけ

## 特徴1 ECSアーキテクチャに基づいた開発ワークフローを採用

## 特徴2 インクリメンタルコンパイル速度が20倍高速に

## 特徴3 npmエコシステムをフルにサポート
下記のライブラリをサポートしますしもちろんこれ以外のnpmライブラリに対応します

1. Underscore
2. jQuery
3. axios
4. socket.io
5. vue

EgretPro自体もnpmのもとバージョン管理およびメンテナンスできます。

## 特徴4 さらに様々なゲームプラットフォームにも対応
WeChat, QQ, 百度, Facebook Instant Game に加えて、Huawei, Xiaomi, OPPO, VIVO にも対応します。


# 今後のロードマップ

## 2019.3.1 Egret Pro 0.9
Egret2D 5.3.2 と Egret3D 1.4 と共にリリースされますがいくつか制約があります。
1. インストール手順が複雑：3Dエディタ、Eget 5.3.2、paper-cliを個別にインストールする必要がある
2. インクリメンタルコンパイル速度は遅い
3. 編集モード(特に編集モードとブラウザプレビューが同時に有効になっている場合)に、GPUリソースが過剰に食われる
4. 2DゲームをECSで開発することはできませｎ

## 2019.4 Egret Pro 1.0
1. APIの変更の影響を可能な限り少ない状態でEgret2DでECSを利用可能に
2. ビジュアルエディタで2Dシーンの編集ができる

## 2019.5
1, JavaScriptのランタイムメモリの利用削減。重たいゲームでも最低限必要なメモリ容量が50Mから20Mまで削減されます。
2. EUIにMVVMフレームワークが採用されます。ゲームのビジネスロジック部分のソースコードが大幅に削減できます。
3. ゲームのローディングスピードが改善されます。リソースのサイズの最適化は不要ですが速度が25%改善されます。
Linuxを簡単に理解しよう

[未来電子テクノロジー](https://www.miraidenshi-tech.jp/intern-content/program/)でインターンをしているryota_miraidenshiです。
今回課題でLinuxについて学ぶ機会がありました。
大学でもLinuxを触る機会がありましたが、どのようなものか理解していなかったので今回ここでまとめておきたいと思います。

#そもそもLinuxとは？
LinuxはMacOSやWindowsなどと同じいわゆる**OS**の一つで、主にサーバー用として使用されます。
このLinuxですが、他のOSと違ってたくさんあるのが特徴です。
というのもLinuxは大きく分けてLinuxカーネルとLinuxディストリビューションの二つに分けられます。
Linuxカーネルはリーナス・トーバルズ氏が開発した大元で、これを元に派生させたのがLinuxディストリビューションです。
つまり、後者が多くあるということになります。
例えば、Red Hat Enterprise Linux、Fedora、CentOSなどがあります。
(余談ですが、スマホのAndroidはLinuxをベースに新しくGoogleが作ったスマホ用OSです。)

#Linuxを使うメリット一部
- 無料
WindowsやMacはそれぞれのOSが入っているPCを購入するか、OS自体をインストールすることはできるが数万円必要です。
一方でLinuxはどのようなPCにも無料でインストールすることができます。

- 中身をいじることができる
Linuxはオープンソースであるため、Windowsなどと違ってOS自体をいじることができます。
何か間違えて重大なエラーになってももう一度インストールし直せばいいだけです。
このように好きなようにできるOSは様々なところで利用されています。
例えば、家電や車、大学の研究、スパコンなどが挙げられます。

- サーバを自由に建てられる
なぜ自由に建てられるのか。
それはLinuxはどれだけ使っても無料だからです。
クラウド技術もLinuxがあってこそ成り立っています。

#終わりに
以上を知った上でこれからLinuxの勉強をしていくと整理しやすいはずです。
プログラム初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正しますのでどんどん指摘してください。
protect_from_forgery with: :exceptionについて調べたまとめ

ログイン機能をdeviseで作成する際、appコントローラーに下の記述をすると
ネットに書かれていてどういう意味だろうと思って軽く調べて見た

```ruby:application_controller.rb
protect_from_forgery with: :exception
```

何故入れるのか？

・CSRF対策(クロスサイトリクエストフォージェリ)

サイトに攻撃用のコードを仕込むことで、アクセスしたユーザーに対して意図しない操作を行わせる
攻撃のことです。

自分の日記や掲示板に意図しない書き込みがされたりといった被害を受ける可能性がある。

対策
Appコントローラーとレイアウトに以下のコードを記載

```ruby:application_controller.rb
protect_from_forgery with: :exception
```

```ruby:applicaiton.html.erb.rb
<%= csrf_meta_tags %>
```
TWAの挙動をPWAに寄せていく（起動編）

先日、TWAサポートライブラリを使用してPWAをAndroidアプリ化してPlayストアから配信する方法を紹介しました。

[【実践】Google Play Store でPWA配信 (TWA)
](https://qiita.com/zprodev/items/181c1c8f19bc0beb1183)

**PWAをPlayストアから配信する**という目的は達成しましたが、起動時の見栄えがあまり良くないなぁ・・・という状態だったので、少しのコード追加で起動時挙動をPWAに寄せる方法を紹介したいと思います。

## PWAとTWAの起動時挙動はどう違うか

PWAとTWAの起動時挙動を比較してみます。

### PWAの挙動

![pwa.gif](https://qiita-image-store.s3.amazonaws.com/0/142643/abf0b524-783a-2bab-9d5e-f19b7e26af14.gif)

### TWAの挙動

![before.gif](https://qiita-image-store.s3.amazonaws.com/0/142643/eb7db969-efb3-d536-7694-a602c95265fd.gif)

### 差分

 - 起動時のスプラッシュページがない
 - 起動時の画面でActionBarが表示されている（QRとだけ表示されているヘッダー）
 - Webページがフェードインじゃなくスライドインで表示される
 - Webページ表示中のステータスバーが白くて浮いている

## PWAに寄せていく

GitHubのcommitログと共に変更箇所を説明します。

### ActionBarを消す

アプリのテーマをDarkActionBarからNoActionBarに変更することで、ActivityのActionBarを消しています。

https://github.com/zprodev/QR-TWA/commit/6d8732fb94840b89792f3b33836fc3f17cad4601

### TWAのステータスバーにテーマカラーを反映

元はTWAサポートライブラリで提供されているLauncherActivityをそのまま使用していましたが、LauncherActivityを継承した自前のActivityを使用するよう変更し、ChromeCustomTabのIntentを生成しているメソッドをオーバーライドします。
https://github.com/zprodev/QR-TWA/commit/fb93ee7b87827627f03e7258904333003f3cec7b

その上で、[リソースとして定義済み](https://github.com/zprodev/QR-TWA/blob/v1.2/QR/app/src/main/res/values/colors.xml)のcolorPrimaryDarkをsetToolbarColorでTWAに設定しています。
https://github.com/zprodev/QR-TWA/commit/3944385ce235c405788a0879ef23b13e23dfce3c


### TWA起動時のトランジションを変更

ステータスバーの色変更と同様に起動時アニメーションを設定することができるので、Alpha変更アニメーションを定義してsetStartAnimationsでTWAに設定しています。
https://github.com/zprodev/QR-TWA/commit/b0ba980f52a8a028ed23ecc8f814662cd0404579

## 結果

変更後の起動時挙動は以下ようになります

![after.gif](https://qiita-image-store.s3.amazonaws.com/0/142643/a6a7ec3f-8420-8bc4-cd1e-8b82b16e7aa7.gif)

スプラッシュページに関しては若干面倒なので省きましたが、デフォルトの状態よりかなりPWAに近づき違和感がなくなったかなと思います。

実機で見てみたい方は↓から試してみてください :thumbsup: 
PWA: https://qr.zpro.app
アプリ: https://play.google.com/store/apps/details?id=app.zpro.qr
ActiveStorageのファイルをアップロードするタイミングについて

ActiveStorageを使うにあたって、アップロードできたかどうかを調べるために、アップロードをどの処理で実施しているか調べたので、覚書として。（アップロードできたかどうかについては、これから改めて調査）

アプリケーションコードに近い方から遠い方へ順に追っていきます。

## 前提条件
* [activestorage](https://rubygems.org/gems/activestorage/versions/5.2.2) のバージョンは5.2.2を使用する
* 属性の定義に `has_one_attached` を使用する
* attachするファイルはHTMLからアップロードしたファイルを使用する
* ファイル保存サービスはローカル(S3やGCSではない)を使用する

## ActiveStorage::Attached::Macros

https://github.com/rails/rails/blob/v5.2.2/activestorage/lib/active_storage/attached/macros.rb#L37

ActiveRecord::Baseを継承するモデルクラス内に定義した`has_one_attached`の属性に対して、値が代入された時に`attach`メソッドを実行します。

## ActiveStorage::Attached::One

https://github.com/rails/rails/blob/v5.2.2/activestorage/lib/active_storage/attached/one.rb#L24

`ActiveStorage::Attached::One.attach` メソッドが `create_blob_from` を実行します。

## ActiveStorage::Attached

https://github.com/rails/rails/blob/v5.2.2/activestorage/lib/active_storage/attached.rb#L23

`ActiveStorage::Attached. create_blob_from` メソッドで、attachableのクラスによって処理を分けています。
今回はアップロードされたファイルを属性に指定したので、
`ActiveStorage::Blob.create_after_upload!` を実行します。

## ActiveStorage::Blob

https://github.com/rails/rails/blob/v5.2.2/activestorage/app/models/active_storage/blob.rb#L65

`ActiveStorage::Blob.create_after_upload!`が`ActiveStorage::Blob.build_after_upload` を実行します。

https://github.com/rails/rails/blob/v5.2.2/activestorage/app/models/active_storage/blob.rb#L57

`ActiveStorage::Blob.build_after_upload` が `ActiveStorage::Blob`を`new`して、`upload` を実行します。

https://github.com/rails/rails/blob/v5.2.2/activestorage/app/models/active_storage/blob.rb#L159

`ActiveStorage::Blob#upload` が `service`インスタンスの`upload`を実行します。
この`service`は、[公式ガイド](https://railsguides.jp/active_storage_overview.html#セットアップ)のセットアップで `service` に指定した `Disk`や`S3`が [ActiveStorage::Service::DiskService](https://github.com/rails/rails/blob/v5.2.2/activestorage/lib/active_storage/service/disk_service.rb)や[ActiveStorage::Service::S3Service](https://github.com/rails/rails/blob/v5.2.2/activestorage/lib/active_storage/service/s3_service.rb)をnewしたインスタンスが格納されています。

今回はローカルディスクを保存サービスに指定しているので、`ActiveStorage::Service::DiskService`の`upload`を実行します。

## ActiveStorage::Service::DiskService

https://github.com/rails/rails/blob/v5.2.2/activestorage/lib/active_storage/service/disk_service.rb#L20

`ActiveStorage::Service::DiskService.upload`で [IO.copy_stream](https://docs.ruby-lang.org/ja/latest/method/IO/s/copy_stream.html) でファイルを `Rails.root/storage/`にコピーして、アップロード処理が終わります。

`instrument` のブロックで囲まれていますが、これは `ActiveSupport::Notifications.instrument` をラップするためのメソッドです。
ログを見ると、

```logs/development.log
Disk Storage (31.0ms) Uploaded file to key: fH4PhWtse6qwM6hBqsoqqmtz (checksum: ci+Mp/YmvV385qYcTJnlgg==)
```
こんな感じのログが、アップロードファイルを属性に代入、またはattachの処理あたりで流れてくると思います。


## 感想

調べ終わってから記事を書いたので思考とは逆順になっています。

調べ始める前は、モデルクラスを`save`するタイミングで`upload`的なメソッドをアプリケーションコードに近いところで実行していると予想していたので、`attach`がそれに相当すると気づくまで時間がかかりました。
`save`に合わせてファイルを保存するようにしたい場合は、直接属性に代入するのではなく、`after_save`かそれに近いタイミングで`attach`してあげると良さそうです。
DropboxのAPIを利用して、ファイルアップロードと共有リンクの作成と共有リンクの取得を行う

# DropboxのAPI利用について
　前回[Google Hangout Chatに画像を付けてメッセージを投稿する](https://qiita.com/Fortinbras/items/7d96ae4d7cd61d4e630e)まわりを調べましたが、その際メッセージに付与する画像をWeb上に置いてURLを指定する必要があるので、今回はDropboxに任意の画像をアップロードして、共有リンクを作成してその共有リンクのURLを取得して、Google Hangout ChatのCard形式のJSON文字列の中で、IMAGEウィジット内のURLなどに指定する箇所について調べてみました。

　DropboxにはAPIが用意されているので、「**Dropboxに画像アップロード** → **共有リンクの作成**  → **共有リンクURLの取得**」のプロセスをDropboxのAPIを利用して実現します。

```python:sample.py
import dropbox
ACCESS_TOKEN = 'ABCDEFG12345HIJKLMN678OPQRSTU90'

local_path = 'fox.jpg'
path = '/images/' + local_path  #dropbox直下に「images」フォルダを作成

# ファイルをDropboxにアップロード
f = open(file_from, 'rb')
dbx.files_upload(f.read(),path )
f.close()


# ファイル名取得
#for entry in dbx.files_list_folder('/images/').entries:
#    print(entry.name)
        
# 共有リンク作成       
setting = dropbox.sharing.SharedLinkSettings(requested_visibility=dropbox.sharing.RequestedVisibility.public)
link = dbx.sharing_create_shared_link_with_settings(path=path, settings=setting)

# 共有リンク取得
links = dbx.sharing_list_shared_links(path=path, direct_only=True).links
if links is not None:
    for link in links:
        url = link.url 
        url = url.replace('www.dropbox','dl.dropboxusercontent').replace('?dl=0','')
        print(url)

```
・DropboxのAPIを利用するには、DropboxのConsole画面でApp登録をして、Token情報をメモして利用します。
・Dropoboxのアップロードした画像を共有参照する場合、リンクURLは、末尾の「<font color="blue">?dl=0</font>」を削除して、また「www.dropbox.com」の文言も「<font color="red">dl.dropboxusercontent.com</font>」に置き換えてあげると、URLをブラウザ上で参照可能になります。

　変更前：`ttps://www.dropbox.com/.../hogehogefugafuga/fox.jpg?dl=0`
　　　 ↓
　変更後：`ttps://dl.dropboxusercontent.com/.../hogehogefugafuga/fox.jpg`

# 補足
・いろいろ調べてみると、どうやら**Raspberry Pi**(≒ Linux OS)を室内や温室などに設置して、室内ペットや温室栽培の野菜などを対象にカメラで定期的に撮影して、撮影した画像ファイルをDropboxにアップロードして、その画像の共有リンクを作成してURLを取得してSlackに投稿するといった定点観測用の簡易監視システムを構築するといった文脈で、この「**Dropboxに画像アップロード** → **共有リンクの作成**  → **共有リンクURLの取得**」のプロセスを、<font color="red">DropboxのAPI</font>を使って実装している方がちらほらいらっしゃる模様。さもありなむ。

・最初Googleドライブに画像を置いて共有URLを取得できるかどうかを試そうかとも思いましたが、今回はDropboxでの方法について調べてみました。（おそらくはGoogleドライブでも同じことができるはず。。。<strike>だと思うけど、根気がないから調べないです</strike>）

・[再掲]自分がやりたいのは、Google AnalyticsなどのKPI数値をグラフ化してまとめたもの(画像)を、Google hangout chatに定期的に投稿して、チーム内でのディスカッションを促進するといったことです。今回はそのGoogle hangout chatのチャットルーム(Webhook)に投稿する画像を、Dropboxにアップロードして、共有リンクURLを作成して参照可能な状態にするまわりのプロセスを調べてみました。

これを踏まえて次回に続く。。。
機械学習論文読みメモ_159

[Low-Latency Video Semantic Segmentation](https://arxiv.org/abs/1804.00389)
ビデオに対するlow latencyなsemantic segmentationを実現するネットワークを提案する。
このネットワークは２つの要素から成り立つ。
１つは時間方向の特徴伝搬モジュールで、CNNを拡張して実現する。
もう一つは動的なスケジューラ機能で、これは予測精度を予測する事で、
適切な予測精度を保つのに十分な計算リソースを動的に決定する。

[On the iterative refinement of densely connected representation levels for semantic segmentation](https://arxiv.org/abs/1804.11332)
最新のsemantic segmentation手法ではCNNの受容体を大きくさせるために
ダウンサンプリングを行ったり、dilated convolutionを採用するなどしてきた。
しかしながら、どちらの手法がより性能向上に寄与しているのかは分かっていなかった。
本論では、その比較を通して新たなネットワークであるFully Convolutional DenseResNet (FC-DRN)
を提案する。
FC-DRNはResNetで構成されるdensely connectedなネットワークをバックボーンに持つ。
またその合間には受容体拡張を行う層は挟まれている。
この組み合わせにより、マルチスケール特徴表現とresidual構造によるgradient flowが
同時に実現できる。
このモデルに基づいて実験を行った所以下の事がわかった：
1.モデルをfrom scratchで学習させた場合、ダウンサンプリングがdilationの利用よりも高性能を実現できる。
2.finetuneで学習させる場合、dilationを利用する方が高性能を実現できる。
3.よりcoarceな特徴表現を利用する場合、後段のrefinementステップは多くは必要とならない。
4.ResNetは正則化機構として効果的である。

[How Does Batch Normalization Help Optimization? (No, It Is Not Abbout Internal Covariate Shift)](https://arxiv.org/abs/1805.11604)
Batch Normalization (BN)は高速で頑健なDNN学習を実現するために汎用的に利用される。
しかし未だその効果の理由については完全に理解がされていない。
一般的に言われている説明は、層のパラメータ変化に影響され後段の特徴分布が
変化してしまうinternal covariance shiftの影響を低減できるため、というものである。
本論では、BNはそうしたinternal covariance shiftの低減への寄与が小さい事を示す。
代わりに、BNは最適化したい空間の構造を有意にスムーズにする事ができるからである事を示す。
このスムーズ性が、学習時のgradientを安定化させ、学習を高速化できる。
機械学習論文読みメモ_158

[Interior Point Methods with Adversarial Networks](https://arxiv.org/abs/1805.09293)
非凸かつ陽に定義されないような解領域で条件つけられる最適化問題を
解くための手法としてGANと内点法を組み合わせたIPMANを提案する。
提案手法はepsilon optimalな解を生成可能であり、解領域は実現可能解の
例をもとに学習される。
提案手法は内点法のようにバリア関数を導入し、GANにおけるdiscriminatorにその役割を
代替させ、一方のgeneratorが逐次的に解を改善させていく事になる。
またもし複数の全所最適解が存在する場合には、それらoptimal setを
通して分布が学習される。

[Self-Attention Generative Adversarial Networks](https://arxiv.org/abs/1805.08318)
本論では、attention構造を利用して長期間の依存関係をモデリングする画像生成GANモデルを提案する。
従来のGANは低解像度の特徴空間においてその局所的情報のみを用いて高解像度の画像生成を試みてきた。
提案手法ではすべての特徴点からの情報を用いる。
さらにdiscriminatorは画像の離れた部分同士の一貫性についても確認するようにする。
また従来研究によりgeneratorに対する条件つけが性能向上のために重要である事がわかっている。
この事実に基づき、generatorに対してspectral normalizationを適用する事で学習挙動を改善する
事ができた。

[AutoAugment: Learning Augmentation Policies from Data](https://arxiv.org/abs/1805.09501)
本論では、画像向けのdata augmentationについて考える。
本論で提案するAutoAugmentは探索的に改善されたdata augmentation policyを発見する。
この手法では、data augmentation policyの探索空間を定義し、
特定のpolicyにおける対象のデータセットに対する評価を直接的に行う。
この実装では、あるpolicyは複数のsub-policyから成り立つ。
それぞれのsub-policyは２つのoperationから成り立ち、
一つはtranslationやrotationといった画像処理関数で、もう一つはそれが適用されるかどうかをランダムで決める機構である。
AutoAugmentを利用する事で、ラベルなしサンプルを使わずに、それらを使うsemi-supervised手法と
同等の性能を発揮できる。
またAutoAugmentで学習されたpolicyは他のタスクにも汎用に性能向上が期待できる。
機械学習論文読みメモ_157

[IGCV2: Interleaved Strucrured Sparse Convolutional Neural Networks](https://arxiv.org/abs/1804.06202)
畳み込みカーネルの効率化を通した高効率なCNNを提案する。
構造化スパースカーネル、低ランクカーネル、低ランクカーネルの積を用いたカーネル表現に加えて、
構造化スパースカーネルの積は最近提案されてきているinterleaved group convolution (IGC)や
Xceptionのカーネルを理解するためのフレームワークとして注目されてきている。
本論ではIGCで構成するgroup convolutionは構造化スパースカーネルの積を用いて分解できる
事を利用する。
これにより、さらなるカーネルの余分を取り除く事が可能になる。

[Image Inpainting for Irregular Holes Using Partial Convolutions](https://arxiv.org/abs/1804.07723)
従来のDNNベースのimage inpainting手法は欠損した画像に対して通常の畳み込みを適用してきた。
この際、欠損された部分は平均値などで置き換えた形で前処理がされた。
しかしながらこうした手法はblurやcolor discrepancyなどの問題を生んだ。
本論ではこの問題に対応する手法としてpartial convolutionを提案する。
この手法では、陽に欠損情報を利用して、欠損していない部分のみを利用した畳み込みを行う。
本論はさらに深い層における特徴空間に対応した欠損情報を得るための手法をあわせて提案する。

[Tempered Adversarial Networks](https://arxiv.org/abs/1802.04374)
GANは現実的なサンプル生成のためのモデルとして優秀であるが、
その学習は困難である。
この困難さはGANを構成する２つのネットワークの間にある不均衡が
原因であると考えられる。
つまり、discriminatorはrealとfake双方のサンプルを用いて学習されるが、
generatorはfakeサンプルのみから学習される事である。
これは、real sampleが与えられた訓練データに制限される事に起因している。
本論ではこうした問題に対して、generatorにreal sampleに対してもコントロール
を与える事で解決する。
このコントロールを行うモジュールはlensの呼ぶ。
このlensモジュールの利用でreal samplesの特徴を少しずつ明らかにしていく形でdiscriminatorへ
提供し、これにより学習のバランスを取る。
lensの例としては、はじめにreal sampleへblurをかけるようにし、徐々にそれを取り除いていく
ような学習過程である。
提案するモジュールはまた、学習しているモデルの性能に合わせて自動的に調整がなされる。
機械学習論文読みメモ_156

[CalibNet: Self-Supervised Extrinsic Calibration using 3D Spatial Transformer Networks](https://arxiv.org/abs/1803.08181)
3D Lidarと2Dカメラは認識タスクにおいて組み合わせて用いられる事が一般的である。
しかしそのためにはintrinsic/extrinsicのキャリブレーションが必須である。
そしてこのキャリブレーションは多大なコストがかかるためスケーラビリティを落とす
原因となっている。
本論ではこの問題に対する手法として、self supervisedなDNNを用いた3D Lidarと2Dカメラ間の
rigid transformをリアルタイムに予測する手法を提案する。
この手法はキャリブレーションターゲットを用意する必要がなく低コストである。
DNNの学習時には、Lidar point cloud, 2D camera input, camera intrinsicのみを要求し
直接的なsupervisionは要求しない。
代わりにdense photometric errorとdense point cloud distance errorをself supervisionとして
最小化する事で学習を行う。

[Large Scale Distributed Neural Network Training Through Online Distillation](https://arxiv.org/abs/1804.03235)
ensemblingとdistillationを組み合わせた手法はほとんどのbase modelに対して、性能の向上が期待できる。
しかしensemble手法はtest timeが増加してしまう問題、distillationは学習プロセスが複雑になる
問題がある。
本論では、新たなオンラインdistillation手法としてCodistillationを提案し、
これは従来のmulti-stageな学習プロセスやたくさんのパラメータチューニングを要求しない。
この手法を提案するにあたってまず、本論はCodistillationを行う事で
より高速な学習が可能になる事を主張する。
特に重要な事に、従来の分散stochastic gradient descent学習手法におけるworker数の増加が
性能向上にこれ以上寄与しない状況に対しても提案手法はさらなる性能向上が望める。
この手法は各ノードでの独立なモデル学習を行う従来のアンサンブル学習において、
さらにその損失関数へ他モデルの平均精度に対する乖離を最小化させるような制約を加える。
これによりさらなる学習ステップを追加する事なくdistillationを組み込む事が可能になる。

[Universal Planning Networks](https://arxiv.org/abs/1804.00645)
複雑なvisuomotor controlタスクでは有用な特徴表現を獲得する事が
大事になってくる。
本論で提案するuniversal planning networks (UPN)はpolicyモデルに
微分可能なplannerを埋め込む。
このplannerは特徴空間上でgradient descentによる最適化を利用した
プランニングを行う。
こうした勾配ベースのプランニングモデル及び利用される特徴空間は
end to endで学習する事が可能である。
機械学習論文読みメモ_155

[Semi-parametric Image Synthesis](https://arxiv.org/abs/1804.10992)
semi-parametricなphotographic image synthesisをその画像のセマンティックな
レイアウト情報より出力させる手法を提案する。
提案手法はparametricとnon-parametricの強みを統合する。
そのnon-parametricな部分は学習データから得られる画像セグメントの
記憶を示す。
この記憶はテスト時にDNNが用いる素材として使われる。
DNNはそうした素材の重ね合わせの関係などを含めた自然なアラインメントを行う。

[Blazingly Fast Video Object Segmentation with Pixel-Wise Metric Learning](https://arxiv.org/abs/1804.03131)
ユーザーからobject of interest情報が与えられた場合のvideo object segmentation手法を提案する。
本論では問題をpixel wiseのsegmentationタスクで考え、
同じインスタンスに属するpixelが近傍に集まるような空間へDNNを用いて入力を写像する。
このDNNは類似度関数を学習する際に用いられるtriplet lossを修正したものを用いて学習を行う。
画像の中でアノテーションされたピクセルはreferenceとして用いられ、その近傍点を分類するために
用いられる。
このアノテーションはセグメントマスクから単純なクリックアノテーションまでをサポートできる。

[Multi-Task Learning Using Uncertainty to Weigh Losses for Scene Geometry and Semantics](https://arxiv.org/abs/1705.07115)
多くのDNNはマルチタスクの目的関数を用いる事で性能向上を図っている。
本論では、そうしたマルチタスク学習は、タスク間の重み付けに強く依存
している事を示す。
そうした重み付けのチューニングは人手で行うには困難な作業である。
本論で提案するアプローチでは、各タスク毎に固有な不確かさが
ある事を考慮した重み付けを学習する。
この事で、各分類、回帰タスクが持つ異なったスケールの組み合わせを
同時に学習させる事を可能にする。
3Dプリンタ/金属加工不要、サーボ代込み5000円でつくる2軸2足歩行ロボット筐体

***■やりたかったこと***
電子工作やIT界隈で生きているけど、いつかはロボットを歩かせてみたい。そんな夢、みんなありますよね。でも、既製品は5万以上するし・・・部品かき集めの組み立ても、結局数万かかるし・・・手作りするにしても、3Dプリンターや金属加工する機器も技もないし・・・・でもでも、死ぬ前に一回は歩かせてみたい。

そこで、
**足2軸の2足歩行ロボットを簡単に安く作る方法**を紹介します。センサー類なしのサーボモーターだけの機構です。3Dプリンタや金属加工も不要で、**TAMIYAの工作用のユニバーサルプレートのみ**で作ります。金額は**6台のサーボモーター込みでも5000円を切ります。**

歩行プログラムはは**obnizで作った**のですが、情報量が多くなるのでプログラム編は別途として、本記事では**ロボットの筐体の組み立てのみ説明**します。汎用的な筐体ですので、**他のCPUボードでも使えます。**


***■まずは動作映像から***
・左脚左右回転→右脚左右回転→左足首内外回転→右足首内外回転→左腕前後移動→右腕前後移動→前進
https://youtu.be/PO2DKRRJIBA


***■組み立て手順***

![組み立て 2足歩行ロボット-1.png](https://qiita-image-store.s3.amazonaws.com/0/234533/f3cef45b-daaf-4ba5-c9ab-520bb845d7ac.png)
![組み立て 2足歩行ロボット-1-2.png](https://qiita-image-store.s3.amazonaws.com/0/234533/035ab943-a2d3-3942-ef79-16b65b80e91a.png)
![組み立て 2足歩行ロボット-2.png](https://qiita-image-store.s3.amazonaws.com/0/234533/50d023b4-689c-8dee-977e-0e0d86786258.png)
![組み立て 2足歩行ロボット-3-1.png](https://qiita-image-store.s3.amazonaws.com/0/234533/6fc305bd-ebd6-e1c0-61da-c61fd52ac626.png)
![組み立て 2足歩行ロボット-3-2.png](https://qiita-image-store.s3.amazonaws.com/0/234533/50d0dfeb-7950-4b61-08f2-dcc542e71ba4.png)
![組み立て 2足歩行ロボット-4.png](https://qiita-image-store.s3.amazonaws.com/0/234533/c793500a-e0d3-c5c8-334f-9b1bcdd62291.png)
![組み立て 2足歩行ロボット-5.png](https://qiita-image-store.s3.amazonaws.com/0/234533/622e51e2-5cfd-1c4a-05c9-58a17dcec194.png)
![組み立て 2足歩行ロボット-6.png](https://qiita-image-store.s3.amazonaws.com/0/234533/f8c180cd-553f-d6ab-5b64-50013b6d075d.png)
![組み立て 2足歩行ロボット-7.png](https://qiita-image-store.s3.amazonaws.com/0/234533/66cccb97-16d3-f3c9-fdc2-1dda3f722af5.png)

■まとめ
とても簡単に安く2足歩行ロボットを作ることができました。近日中にobnizの歩行プログラムも投稿しようと思います。obniz以外の方もこのロボット筐体でチャレンジしてみて下さい。
Tableau Desktop から Azure Databricks に接続する

#Azure Databricks とは
https://docs.microsoft.com/ja-jp/azure/azure-databricks/what-is-azure-databricks
---引用---
*Azure Databricks は、Microsoft Azure クラウド サービス プラットフォームに最適化された Apache Spark ベースの分析プラットフォームです。 Apache Spark の創始者たちと共に設計され、Azure に統合された Databricks では、ワンクリックでのセットアップと効率的なワークフローのほか、データ サイエンティスト、データ エンジニア、ビジネス アナリストが共同作業できるインタラクティブなワークスペースが実現されています。*
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246284/3ea4bb5d-1754-1304-1486-c11d3e7a692a.png)
---ここまで---

#Tableau からの接続
##Tableau がサポートするデータソース
###すべての技術仕様
https://www.tableau.com/ja-jp/products/techspecs
Spark SQL (Apache Spark 1.2.1 以降が必要)

2019/11 追記: Tableau 2019.3 から、Databricks のネイティブコネクタがリリースされました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246284/ba178d4c-71dc-f9a2-fd85-5feebfb88335.png)


~~###Spark SQL~~
~~https://onlinehelp.tableau.com/current/pro/desktop/ja-jp/examples_sparksql.htm~~
~~---引用---~~
~~*Spark SQL コネクタを使用して、Azure HDInsight、Azure Data Lake、Databricks、または Apache Spark 上の Spark クラスターに接続できます。*~~
~~---ここまで---~~


##必要なドライバー
https://www.tableau.com/ja-jp/support/drivers
~~上記ページから Spark SQL のドライバーを取得、インストール~~
~~SimbaSpark1.2-64-bit.msi~~
Simba ODBC ドライバーバージョン2.6.4 以上

##token の作成
Azure AD 認証には対応していないため、Azure Databricks の管理コンソール上で token の作成が必要です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246284/e302081a-6b14-2718-f1c6-be8497629645.png)
User Settings から Generate New Token を選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246284/f16735b4-fda4-0b7f-f47c-21b62d23893d.png)
適当な名前をつけます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246284/b1050ebf-7d0b-a849-d80a-dc934c3c983d.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246284/5ad8acb7-d0b4-926e-a7fc-ea0e7775e0f0.png)
作成した token は忘れずにコピーしておいてください・・・①

##HTTP パスの確認
クラスタの管理画面から Advanced Options を開き、HTTP パス (下記赤枠部)をコピー・・・②
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246284/b8457f2c-4f78-b472-85e3-a7021be4d884.png)

##Tableau Desktop からの接続
サーバーへ の その他... メニューから Spark SQL を選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246284/bad49844-e788-4675-25f8-b9e1b514229a.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246284/4e57a813-4164-ab74-08d0-6adfa4aa362f.png)

サーバー: *regionname*.azuredatabricks.net (東日本リージョンであれば japaneast.azuredatabricks.net)
ポート: 443
タイプ: SparkThriftServer (Spark 1.1 以降)
認証: ユーザ名とパスワード
転送: HTTP
ユーザ名: token
パスワード: ①
HTTP パス: ②
SSL が必須 に☑

![image.png](https://qiita-image-store.s3.amazonaws.com/0/246284/c3dac0a1-caee-06b4-d054-da6024f830f2.png)
接続完了

#参考資料
[Databricks user guide -Tableau](https://docs.databricks.com/user-guide/bi/tableau.html)
[Databricks user guide -Generate New Token](https://docs.databricks.com/api/latest/authentication.html)
[Azure Databricks を使ってみよう](https://blogs.msdn.microsoft.com/dataplatjp/2018/06/19/azure-databricks/)
[Azure Databricks 知ってますか?](https://qiita.com/emshimon/items/fb9e92a3c708c7ecb9d3)
JenkinsでBitbucketにプッシュ時にシェルを実行

#概要
Jenkins on RaspberryPi3 & bitbucket でプッシュをトリガーにシェルを実行させたいと思います。

#１. Javaをインストール
```
$ sudo apt-get install openjdk-8-jre
```

#2. Jenkinsをインストール&初期設定
##インストール
公開鍵の追加、リポジトリの追加をしてからインストールします

```
$ sudo wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
$ sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
$ sudo apt-get install -y jenkins
```

##初期設定
###ポート変更

```config:/etc/default/jenkins
#HTTP_PORT=8080
HTTP_PORT=8008
```

通常はフロントをプロキシなどでApacheにするのですが、自分の場合だとjenkinsがネットワークに繋がらなくなってしまったため、直接アクセスします。

###ログイン
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280075/68bd32e6-73ab-da1f-baf2-83be80bde541.png)


初回起動時にadminのパスワードを聞かれてきます。書いてある通り
`/var/lib/jenkins/secrets/initialAdminPassword`
に初期パスワードが保存されているのでそいつを持ってきて入力します。

```
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
```

###初期プラグインインストール
左の`Install suggested plugins`を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280075/2c2e82a2-9ac7-392d-dd32-0abb3bfe71e7.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280075/fa300f15-1135-76df-401b-c33ba381c279.png)
こんな感じでプラグインが正常にインストールできなかった場合、Retryするか、**Jenkinsのバージョンが最新か確認**してください。

###アカウントの作成
アカウントを作ります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280075/3e1cc238-a171-62ff-7d61-f74de357e212.png)

### サーバーURLの入力
Jenkinsを稼働しているサーバーのURLを入力します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280075/5155d143-21a7-ffed-d58c-caa63f7f0dce.png)

#3.Bitbucketと連携
今回はお家の22ポートが空いてなかったため、HTTPS接続します。

## Bitbucket
### Webhookを設定
Titleを適当に設定し、
URLに
`http://(JenkinsサーバーURL)/git/notifyCommit?url=(gitリポジトリURL)`
を入力します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280075/0209a971-3494-c561-5b78-c05439f3b9a4.png)

# Jenkins
## プロジェクトの作成
**フリースタイル・プロジェクトのビルド**を選択してOK。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280075/b837a3db-3900-dd51-580f-7ff85cc5caf4.png)
### プロジェクト設定
`ソースコード管理`にて、`git`を選択後、対象のリポジトリのURLを貼り付け。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280075/e1b3e39f-b160-1139-a0e9-8f72e661cf3b.png)


認証情報はHTTPS認証なので、`ユーザー名とパスワード`でBitbucketのユーザ名とパスワードを入力
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280075/b5e33cfa-acd2-7840-5607-e8cd4b1c217b.png)

ビルド・トリガで`SCMをポーリング`にチェックを入れる。
ビルド`ビルド手順の追加>シェルの実行`を選択し、デプロイ用のシェルスクリプトを入力
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280075/b8a68b83-47e3-7dd5-0d40-b6ef09a597c6.png)

保存し、対象リポジトリでコミット&プッシュを行うとJenkinsプロジェクトが立ち上がります。
`ビルド履歴>コンソール出力`でプロジェクトを実行した際のコンソール出力を見ることができます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280075/9bbd216a-40ea-b8d6-6833-119082e6f2a1.png)
RevPi Core3にJessieをインストール

##RevPi Core3にプリインストールされているOS
本体右側のステッカーを見ると、大きく書かれた「REVOLUTION PI」の文字の下にOSのバージョンがあります。写真のRevPiは「2018-07-17-revpi-stretch」とあるので、Stretchがインストールされていることがわかります。
<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/350867/c638f68e-827c-cd14-2bd3-3619975ab249.jpeg">

##イメージの書き換え
動作させたいものがまだStretchに対応していない場合など、RevPiでJessieを使用することができます。
この記事では RPi Boot(Windows Installer)とWin 32 Disk ImagerでJessieをインストールする手順を記します。

今回は書き換え方法のみの紹介になりますが、必要に応じて書き換え前のイメージのバックアップを取るようにして下さい。
##イメージファイルとソフトウェア
次のイメージファイルとソフトウェアをダウンロードしインストールします。

**1.Jessie イメージファイル**
ダウンロードには登録（無料）が必要です。 [アカウント登録ページ](https://revolution.kunbus.de/shop/en/customer/account/create/)で氏名とメールアドレスを登録します。登録したアカウントでログインし、[ダウンロードページ](https://revolution.kunbus.de/shop/en/jessie)からファイルをダウンロードし、解凍します。

**2.RPi Boot(Windows Installer)**
ファイルをダウンロードしてインストール：[[ダウンロードリンク]](https://github.com/raspberrypi/usbboot/raw/master/win32/rpiboot_setup.exe)

**3.Win32 Disk Manager**
ファイルをダウンロードしてインストール：[[ダウンロードリンク]](https://sourceforge.net/projects/win32diskimager/)

##RevPiをWindows PCと接続
RevPiの電源を入れる前に、RevPiのフロントにあるMicro USBポートとWindows PCをUSBケーブルで接続します。USB Type A～Micro USBのデータ転送用ケーブルを使用します。Androidの充電ケーブルに同じ形状のものがありますが、データ転送には使用できないものがあります。
<img width="400" src="https://qiita-image-store.s3.amazonaws.com/0/350867/ca438a1c-d14e-4186-9c44-b672604263f5.png"> <img width="93"src="https://qiita-image-store.s3.amazonaws.com/0/350867/2480f958-d2d6-29f9-bb46-65cae299493a.jpeg">
##RPiBootプログラムを起動
Windows PCでインストールした`RPiBoot.exe` を起動します。RPiBoot.exeファイルの場所が分かりにくい場合は、[Ctrl]+[s]→Windowsの検索→rpibootと入力して検索すると出てきます。起動すると下のような画面が出ます。（ここまでRevPiの電源は入れません）
<img width="350" src="https://qiita-image-store.s3.amazonaws.com/0/350867/6df7bd1c-7932-a79e-f2ee-47f8c9a3604c.png">

##RevPiに電源投入
電源の配線方法については[こちらの記事](https://qiita.com/htg_ns/private/eb666e7b12fafb1e7dfb)を参照ください。

##RPiプログラムでeMMC接続

RevPiに電源を入れると、RPiBootプログラムでRevPi内部のeMMCが接続されます。RPiBootの画面に下のような表示がでます。
<img width="350" src="https://qiita-image-store.s3.amazonaws.com/0/350867/3980aa81-4e2b-681c-6fc1-403aa792a471.png">
「ドライブをフォーマットしますか」という表示が出たら 「キャンセル」します。このウィンドウは複数出る場合がありますが、すべてキャンセルしてください。また、フォーマットしないためエラー表示が出ますがOKを押して表示を消し、そのまま進めます。
<img width="350" src="https://qiita-image-store.s3.amazonaws.com/0/350867/ff2676ec-79fa-6fcd-0e81-cbfa96464eeb.png">
<img width="350" src="https://qiita-image-store.s3.amazonaws.com/0/350867/7ae4704e-891c-23eb-3b66-fe2cff03fe94.png">

##eMMCにイメージを書き込む
インストールしたWin32 Disk ImagerでJessieのイメージを書き込みます
・Win32 Disk Imagerを起動し、イメージを書き込むドライブを選択します。Exploreで見ると「boot」という名前で表示されています。
・フォルダのアイコンをクリックしてJessieのイメージファイルを選択します。
・「Write」をクリックします。
<img width="350" src="https://qiita-image-store.s3.amazonaws.com/0/350867/6e16f50a-eab2-91c7-e8c8-3d7751bcd33e.png">

書き込み先のドライブに誤りがないか最終確認し、書き込みます。数分～十数分かかります。
<img width="350" src="https://qiita-image-store.s3.amazonaws.com/0/350867/08bf10bb-3274-1a55-b33c-6c7a2de7ae20.png">
Write Successfulと表示されたら完了です。Windows PCから接続を外し、電源を落とします。<img width="350" src="https://qiita-image-store.s3.amazonaws.com/0/350867/a1cf50fa-c2ad-aacb-91f8-2bd058f1b6cb.png">

##初期セットアップへ
イメージを書き換えた後のセットアップ方法は、購入時のOSのまま起動する場合と同じです。
[セットアップの記事](https://qiita.com/htg_ns/private/4b484dc60f23e6ea686e)を参照ください。
Zabbix Proxy on Raspberry Pi3

# Zabbix ProxyをRaspberry Pi3に入れる

本記事では、自前でZabbix Proxyをコンパイルしていますが、どうも最近はパッケージで導入が出来るみたいです。
時間が合ったら、記事を書き直す予定です。

## 前提条件

- OS
    - Raspbian GNU/Linux 9
- データベース
    - SQLite 

RasPiにMySQLは重たいかな。と思っていたので、SQLiteで動くのは好印象

## ユーザを作成

```
# groupadd zabbix
# useradd -g zabbix -d /dev/null -s /sbin/false zabbix
```

## 必要なパッケージを追加

```
# apt update
# apt install make fping sqlite3 libsnmp-dev libcurl4-openssl-dev libiksemel-dev libsqlite3-dev libxml2 libxml2-dev libopenipmi-dev snmp  snmp-mibs-downloader libssh2-1-dev snmpd libevent-dev libpcre3-dev libgnutls28-dev
```

## Zabbix Proxyをインストール

```
% wget https://sourceforge.net/projects/zabbix/files/ZABBIX%20Latest%20Stable/4.0.3/zabbix-4.0.3.tar.gz/download
% tar xvzf download
% cd zabbix-4.0.3/
% ./configure --enable-proxy --enable-agent --with-sqlite3 --with-net-snmp --with-libcurl --with-openipmi --with-ssh2 --with-libxml2 --enable-ipv6 --with-gnutls
% make
# make install
```

```
mkdir /var/log/zabbix
mkdir /var/run/zabbix/
chown zabbix.zabbix /var/log/zabbix
chown zabbix.zabbix /var/run/zabbix/
touch /var/log/zabbix/zabbix_proxy.log
chown zabbix.zabbix /var/log/zabbix/zabbix_proxy.log
```

```/etc/systemd/system/zabbix-proxy.service
[Unit]
Description=Zabbix Proxy
After=syslog.target
After=network.target

[Service]
EnvironmentFile=-/etc/sysconfig/zabbix-proxy
Type=forking
Restart=on-failure
PIDFile=/var/run/zabbix/zabbix_proxy.pid
KillMode=process
ExecStart=/usr/local/sbin/zabbix_proxy
ExecStop=/bin/kill -SIGTERM $MAINPID
RestartSec=10s
TimeoutSec=0

[Install]
WantedBy=multi-user.target
```

```
# systemctl start zabbix-proxy
# systemctl status zabbix-proxy
```

## 設定

Raspberry Pi特有の設定はないため、普通にですが手元の環境ではこんな感じ

```/usr/local/etc/zabbix_proxy.conf
Server=###zabbix_server###
Hostname=###self_ip###
LogFile=/var/log/zabbix/zabbix_proxy.log
PidFile=/var/run/zabbix/zabbix_proxy.pid
DBName=/var/lib/zabbix/db/zbxproxy.db
DBUser=zabbix
Timeout=4
FpingLocation=/usr/bin/fping
Fping6Location=/usr/bin/fping6
LogSlowQueries=3000
```

## 注意点

Zabbix Frontend上ではProxyを選ぶところがあるため、問題無いと思いますが、
Zabbix AgentからはZABBIX ProxyがServerに見えるため、注意が必要
BOT作成プラットフォームBotpress詳解(1)

#Botpresss(1)


弊社ではAIチャットボット・プラットフォーム「バーチャルエージェント」の開発をしています。そのため、オープンソース界ではこの領域でどのようなプロダクトがあるかを調査したりします。その中で、社内で完成度が高い！と話のあがったbotpressについて、調べて行きたいとおもいます。

**2021/5/11追記** 参考リンクに[botpressのchannelモジュール作成方法(1)](https://zenn.dev/mkanashiro/articles/1643bddd8dc696f6321b)を追記しました。
**2021/5/7追記** 参考リンクに「[Chatbot Today](https://chatbot.today/)」を追記しました。

##Botpressとは？
TypeScriptで書かれたオープンソースのBOT作成プラットフォームです。
https://github.com/botpress/botpress


コミットログを見ると開発が始まったのは2016年頃ですね。githubで「bot」というキーワードで検索し、言語をjavascriptで絞り込むと上位に表示されるのでなかなかの注目度なのではないかと思います。今回は下記のデベロッパーズガイドを見ながらどのような機能があるのか概要を見ていきます。
Developer's Guide　https://botpress.io/docs/introduction

#Botpressの備える機能
下記のような機能を備えていて、botpressを使用すれば簡単にBOTを構築できるようです。

- NLU Engine
- Administration dashboard
- Visual flow editor
- chat emulator / debugger
- Support for multiple messaging channels


##NLU Engine
watsonやluisなどを使用しなくてもbotpressだけで自然言語理解を行うエンジンを含んでいるようです。どれくらいの精度があるのでしょうか。また日本語はOKなのでしょうか？？

## Administration dashboard
管理画面ですね。返答に使用するテキストや画像を登録できるようなUIが見受けられますね。
<img width="1111" alt="Botpress Studio – WelcomeBot 2019-02-22 08-21-11.png" src="https://qiita-image-store.s3.amazonaws.com/0/356515/e2cea6da-469e-514b-63e8-915b19f7f609.png">


## Visual flow editor
FlowEditorという画面ですが、応答内容や次に質問する内容などをドラッグ&ドロップで作成でき簡単に作成できそうですね!!
<img width="1109" alt="Botpress Studio – WelcomeBot 2019-02-22 08-22-16.png" src="https://qiita-image-store.s3.amazonaws.com/0/356515/94e3c08b-f12a-eb86-c6c2-b87804a85f38.png">

## chat emulator / debugger
構築中のbotを試して、期待した応答になっているかチェック/デバッグできる機能のようです。(画面右上にあるアイコンから起動できます)

<img width="1105" alt="Botpress Studio – WelcomeBot 2019-02-22 08-27-33.png" src="https://qiita-image-store.s3.amazonaws.com/0/356515/bc0f44dc-a64d-ffd3-1c71-5cc8da16adc4.png">


## Support for multiple messaging channels
Webのチャット用画面からの入力だけではなく、SkypeやSMSからの入力も受け付け可能なようです。SlackはLINE等はどうなのでしょうか。





##次回
botpressの11.x系を使用したボットの作成方法や、せっかくのオープンソースですからモジュールの構成や、データ構造について調査していく予定です。


#参照
Introduction · Botpress | Developer's Guide　https://botpress.io/docs/introduction
参照時は11.5.0のドキュメントでした


[ソースコード解析の環境構築 - Botpress詳解(2)](https://qiita.com/kanashiro/items/ad802e5ff75b761656fd)
次の記事です

[Chatbot Today](https://chatbot.today/)
『チャットボットの教科書』の読者サポートページです。4章からはbotpressを使ったチャットボット構築方法が記載されていてオススメです。


[botpressのchannelモジュール作成方法(1)](https://zenn.dev/mkanashiro/articles/1643bddd8dc696f6321b)
カスタムモジュールの作成方法をまとめています。

----
###We're hiring!
AIチャットボットを開発しています。
ご興味ある方は<a href="https://www.wantedly.com/projects/266837">Wantedlyページ</a>からお気軽にご連絡ください！
Git BashでSDKMAN!を使う

# TL;DR

[Git for Windows](https://gitforwindows.org/) に付属しているGit Bash(MINGW64)やMSYS2などを利用する際は、以下を `.bashrc` などに追加することでSDKMAN!の利用が可能になります。

```bash:.bashrc
export MSYS=winsymlinks:lnk
```

インストール自体は以下の通りなので割愛。

https://sdkman.io/install

# 蛇足

## なぜSDKMAN!を使おうとしたのか

JDK、様々なベンダーやコミュニティがビルドし、提供されるようになってきているので、「気軽に切り替えられるようにしておきたい」と思うと思います。(思いますよね？)

上記のようなことを行う場合、JDKなどのバージョンを管理するツールが必要になってきます。
JVM系ではSDKMAN!というツールがあるので、これを利用します。

* [SDKMAN\! the Software Development Kit Manager](https://sdkman.io/)

SDKMAN!を利用してインストールできるSDK(と書かれているので表記。言語、ツール、アプリケーションフレームワークなど様々なものがインストール可能)は以下を参照してください。

* [Available SDKs \- SDKMAN\! the Software Development Kit Manager](https://sdkman.io/sdks)

## Git BashでSDKMAN!を利用する際の課題

以下を見るとGit Bashでふつうに利用できそうなのですが、JDKのダウンロードは出来るものの、デフォルトに設定しようとするとエラーになってしまいます。

https://sdkman.io/install

```bash
$ sdk default java 8.0.202.hs-adpt
SDKMAN: No update needed. Using existing candidates cache: ant,asciidoctorj,bpipe,ceylon,crash,cuba,cxf,gaiden,glide,gradle,grails,groovy,groovyserv,infrastructor,java,jbake,kotlin,kscript,lazybones,leiningen,maven,micronaut,sbt,scala,spark,springboot,sshoogr,vertx,visualvm
Not refreshing version cache now...
Validate java 8.0.202.hs-adpt for MINGW64_NT-10.0: valid
Validation URL: https://api.sdkman.io/2/candidates/validate/java/8.0.202.hs-adpt/mingw64_nt-10.0
rm: cannot remove '/c/Users/tenten0213/.sdkman/candidates/java/current': Is a directory
ln: failed to create symbolic link '/c/Users/tenten0213/.sdkman/candidates/java/current/8.0.202.hs-adpt': File exists
```

↑はデバッグモードを有効にしています。( `~/.sdkman/etc/config` の `sdkman_debug_mode` を `true` に)


コードを見てみると、以下の `rm -f` している箇所でエラーになっているようです。

https://github.com/sdkman/sdkman-cli/blob/b63ee15c8885b89ea09dee4f965fbd48167398d1/src/main/bash/sdkman-path-helpers.sh#L85

なぜエラーになるのかというと、冒頭の設定をしていない場合、 `ln -s` ではシンボリックリンクは作成されず、コピーが作成されます。シンボリックリンクではなくディレクトリになるので、 `rm -f` でエラーになってしまいます。

…ということで、冒頭に戻り `MSYS=winsymlinks:lnk` とすることでコピーではなくシンボリックリンク(Windowsのショートカット)が作成されるようになり、無事利用できるようになりました。

### 参考
* [MSYS2小ネタ集 \- Qiita](https://qiita.com/ubnt_intrepid/items/0d9ea1c792dd2049d71c)
* https://cygwin.com/cygwin-ug-net/using-cygwinenv.html
【PHP】count() メモ

# PHPの型まわりのメモ
## 実行環境
PHP 7.0x

## count()
型まわりの注意点まとめ。

```php
$array1 = false;
$array2 = 'str';
$array3 = [
    'a',
    'b',
];
$array4 = [
    ['a'],
    ['b'],
];
$array5 = null;

echo count($array1); // 1
echo count($array2); // 1
echo count($array3); // 2
echo count($array4); // 2
echo count($array5); // 0
echo count((array)$array1); // 1
echo count((array)$array2); // 1

```
※コメントいただきました通り、型がおかしい場合にPHP7.2でWarningが表示されるようになりました。
https://www.php.net/manual/ja/migration72.incompatible.php#migration72.incompatible.warn-on-non-countable-types
macOSにThe Sleuth Kitをインストールする

#環境
OS : macOS Mojave(version 10.14.3)
Java : OpenJDK(version 11.0.2)
Homebrewを使ってインストールします。
#Javaをインストールする
The Sleuth KitをインストールするのにJavaが必要なのでインストールします。

```
$ brew cask install java
```

実行するとOpenJDKがインストールされます。
下記のコマンドでバージョンが確認できます。

```
$ /usr/libexec/java_home -V
Matching Java Virtual Machines (1):
    11.0.2, x86_64:	"OpenJDK 11.0.2"	/Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home

/Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home
```

パスを通す必要があるので.bash_profileに下記のものを追記します。

```bash:.bash_profile
export PATH=$PATH:/Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home/bin
export JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home
```

.bash_profileを更新します。

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

#The Sleuth Kitのインストール
次のコマンドを実行します。

```
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/null
```

インストールの準備ができたのでインストールします。

```
$ brew install sleuthkit
```

.bash_profileに追記します。

```bash:.bash_profile
export LDFLAGS="-L/usr/local/opt/libpq/lib"
export CPPFLAGS="-I/usr/local/opt/libpq/include"
export PKG_CONFIG_PATH="/usr/local/opt/libpq/lib/pkgconfig"
```

これで使えるようになります。

```
$ icat -V
The Sleuth Kit ver 4.6.5
```

```
$ fls -V
The Sleuth Kit ver 4.6.5
```
jsオフでも変にならないように年を自動更新

```hogehoge.html
<span id="copyright-year">2019</span>
```

```hogehoge.js
var date = new Date();
var y = String(date.getFullYear());
var getCopy = $('#copyright-year');
var tx = getCopy.text();
var t = tx + ' - ' + y;

if (tx !== y) {
  getCopy.text(t);
}
```

htmlには公開年、もといjs無効の時に見せたい年を書いておく。
jsが動けば、公開から現在までを`2018 - 20XX`といったように表示。
※要jquery

兼投稿テストでした。
回収できなかった案件の恐怖

回収できなかった案件についてお話しよう

#はじめに
今からｘ年前の事。某技術者が多く集まるSlackにて
C++でWebクローリング出来る人はいないか？
とのことで、以前より Boost.Asioの記事をかいてる私に話がきた
まず案件をくれた人について、はじめての取引なので周辺の人に話をきいたが
少し甘いという意見はあるが、誠実で良い人という意見だったので請けた

#プロジェクト開始
案件を紹介してくれた人の友だちよりメッセージがきてChatworkに入った
具体的な案件に関しては担当の技術者と話をしてほしいとのことで
金額は時給1万円で月末精算、働いた時間を申請してほしいと言われた

#案件内容
作業者と話をした
今までC言語でWebのクローラーを作っていたが、C言語だとOpenSSLがメモリリークしていてすぐ落ちる
だからC++でクローリング部分だけ作って欲しい。内部はC言語のシステムがあると
すかさずツッコミを入れる
それはOpenSSLの問題じゃなくC言語のコードの不具合があるからそちらを直すべきだと
担当者は、OpenSSLの不具合なんだ。でもC++にするのはそれだけが理由ではない
Boost.Asioにすることで、圧倒的に速度向上するからお願いしたい （私のスライドを見てくれてました）
一応ツッコミ。Boost．AsioもHTTPSの実装はOpenSSLを叩いていて、仮にOpenSSLに不具合があるなら同じかもしれませんよ？
しかし担当者は OpenSSLはC言語から叩くとメモリリークすることは調査済でC++ならメモリリークしないことが判明している

前々から気がついていたけど、要はこういうことだ

**C言語でクローラー作ったがメモリリークのバグを直せないので OpenSSLのバグって事で会社に説明し、C++で助けて**

その心の叫びを察して、これ以上（StackOverFlowにC言語でリークする情報あったか？ メモリリークする最小コードくれ。　　C++ではリークしないというのはどう確認したか？）
という尋問をやめた

#開発
Boost.Asioの知見はあったし、サンプルコードもついているので20時間ほどで、HTTPとHTTPSをクローリングするライブラリを作り
Google、Yahooなどをクロールするサンプルを提出した
40万ぐらい欲しかったけど20万でできてしまった。ので20万でいいや。

ところがいろいろな注文がきた

##C言語のインタフェースにしてほしい
いちおう、extern "C"したり、インタフェースもCから呼べる用にしているが
さらに内部のポインタがほしいという要望を叶えた・・

##呼んだらデータNullだった
非同期なんでサンプルのようにコールバック作って受け取ってくれよ
Boost.Asioだと速度が上がるといってたのはこの非同期によるものだよ！
と思ったが、どうやっても理解してもらえないので、同期メソッドも作った

##悩み事
担当者の彼はよく喋る人間だった
家庭の問題の相談やら、今まで自分がやってきた仕事の自慢だったり、今の会社の悪口
バブル時代の武勇伝とか聞けて楽しいではあったが
それが何十時間も続く
私時給1万でやってるけど、これ作業に計上してやろうか！とおもったがしなかった
計上してると彼の話だけで100万は超える
ただ、仕事上の質問をしても、彼の自分語りが入るので、業務の一部なんだよな・・

ま、話は楽しかったので、タダで相手した

#提出
３５万でクローリングしてC言語のインタフェースを望み通り作り提出したが
受け取り拒否された

##FacebookとTwitterに・・
提出物はC++でWebクローリングするライブラリだったのに
GoogleやYahooではなく、FacebookとTwitterを例にしてほしいと
Facebookでは、ちゃんとHeader設定工夫しないとBOT扱いされてはじかれるし、チャンク処理も必要だし、おそらくクロールいっぱいしたらBANられる・・
ので、GoogleやYahooにアクセスできるから問題ないと何度もいったが、認めてくれない

・・・なぜFacebookとTwitter？？？

##詐欺商材会社
担当者の身元を洗ったところ、FacebookやTwitterに自動でイイネしたり書き込みしたり友達申請したり
という業界では有名なソフトで暴利を得てる会社を経営していた
（この案件は違う名前の会社で行っていた）
最初からわかってれば請けなかったかもしれないが
すでに３５万の請求が拒否されてるのでお金回収するまで頑張るぞい！

#再提出
Facebook、Twitterに対応したものを再提出し７０万の請求を出した
金額が膨れ上がった理由は、Facebookはクローリング禁止していてBOT判定が厳しくそれを騙さなければならないからだ
もちろん、そのノウハウは誰にも語らないし、ノウハウのはいったコードは提出していない
（そもそも以前そのようなツールあるので、会社にもノウハウがあるはずだが）
しかし 返事がない！！

#その後
何度も連絡とったが返事がない
登録していた会社に内容証明おくったが返事がない
そもそも登記している北海道には会社なんてない
再び元ネット警察の力をつかい本当の事務所を探しあてる
新宿の某所であった
そこにも同じく請求をかけるが返事がない

担当技術者にも連絡をとったが、彼も怒っていた
数ヶ月給料が支払われておらず、さらに会社に被害を与えたと訴訟されるらしいと

その後何度か請求を送ったが、会社は引っ越していると、次に入った会社から連絡がきた

#詐欺ダメ！絶対！
私は７０万程度の被害
担当者は１００万オーバーの被害（訴訟されたか知らない）
他の作業者も給料未払い
そして　以前のツールも利用者から動かないなどのクレーム多数

それ以来、新規の会社と仕事するときは、役員全員の身元を洗って
なにか問題をおこしていないか確認するようにしている

あと、ネット上での仕事の紹介もちゃんと確認すべきだ。
TwitterAPIの申請に必要な英作文をユルく和訳してみた

TwitterAPIの申請が厳しくなって、https://developer.twitter.com/en/apply/usecase で書かされることになった英弱殺しの英作文。
こんなことでみんながbotを作らなくなっては世の中が楽しくなくなるので和訳しておきました。ご査収ください。


##### Describe in your own words what you are building

Please describe what you would like to build with Twitter’s APIs. Be sure to give detailed answers to the following questions. If the question does not apply to your solution, please explicitly state that. The more detailed the response, the easier it is to review and approve.

> Twitter APIで作りたいものについて、次の質問に答える形で詳細を記入してください。
もしあなたの制作物に合わない質問があれば、はっきりと記述してください。
詳しく書くほど、すぐに承認されるよ。

1．What is the core use case, intent, or purpose for your use of Twitter's APIs?

> 1．Twitter APIを使用する、主な用途・趣旨・目的はなんですか？

2．Do you intend to analyze Tweets, Twitter users, or their content? If so, share details about the analyses you plan to conduct and the methods or techniques you plan to use.

> ツイート・Twitterユーザー・他ユーザーのコンテンツを分析する予定はありますか？
もしあれば、分析結果の管理と技術的な用途について予定を教えてください。

3．Does your use case involve Tweeting, Retweeting, or liking content? If so, share how you will interact with Twitter users or their content.

> あなたの制作物は、他ユーザーのコンテンツに対してツイート・リツイート・いいねをしますか？
もしするなら、どのようにTwitterユーザーや他ユーザーのコンテンツに関わるか教えてください。
	
4．How will Twitter data be displayed to users of your solution? If you plan to display Twitter content off of Twitter, explain how and where Tweets and Twitter content will be displayed to users of your product or service. Will individual Tweets and Twitter content be displayed, or will information about Tweets or Twitter content be displayed in aggregate?

> どのようにTwitterのデータはあなたの制作物のユーザーに表示されますか？
もしTwitterのコンテンツを表示する予定があれば、どのように、どこで、ツイートとTwitterコンテンツがあなたの制作物 (製品・サービス) のユーザーに表示されるか記入してください。
個人のツイート・Twitterコンテンツや、ツイート・Twitterコンテンツの情報の集計が表示されることはありますか？


## あとがき
私自身も英強ではないので、なにかあればお気軽に編集リクエスト投げていただければと思います。
みなさんの回答をGoogle翻訳にブチ込んでどんどんTwitter botを作りましょう！！
[AWS]結局AWSの負荷テストに申請がいるのかいらないのか

# はじめに
SIer諸氏におかれては、いわゆる総合テストにおいて、
構築したシステムが要件通りの性能が出るかを確認する負荷テスト(性能テスト)を行うことが多いと思う。

AWS上に構築したシステムに対する、
侵入テストは申請が**必須**と明記されている[^1]が、
負荷テストについては、「あらゆるイベントは事前申請が必要」派と、「不要」派の記事が出てくる。
結局どっちかわからないのでAWSに申請して聞いてみた。

# たいていの人向けの結論
実際に申請してみたところ以下の返答をいただいた。（抜粋）
>Customers performing benchmark testing or low bandwidth testing 
>with expected bandwidth of less than 1Gbps and 1Gb PPS do not need to request approval.

ということで、1Gbps、また1Gb PPS以下のリクエストの**load or stress testing**は、申請不要とのこと。
当然、**vulnerability or penetration testing**は申請が必須。

※最近気づいたが、[EC2 Testing Policy](https://aws.amazon.com/jp/ec2/testing/)のページが更新されており、上記の数値について明記された。


# 1Gbps以上の負荷テストをしたい人
あまり無いこととは思うが、1Gbps、また1Gb PPS以上の負荷テストを行いたい人、
侵入テストや脆弱性テストがしたい人は、
以下の制約に留意した上で申請を行う必要があるようだ。

- テスト対象用アカウントとは別に、テスト実行用のアカウントを作成する
- テスト実行用アカウントは、本番用インスタンスを持ってはいけない
- テスト実行用アカウントが、本番用インスタンスを持たない限り、他のテストに流用しても良い
- テスト対象用アカウントは、実行用アカウントと同一の所有者[^2]である必要がある

実際の申請は、[aws-security-simulated-event@amazon.com](aws-security-simulated-event@amazon.com)へのメールか、
AWSの侵入テストの[申請フォーム](https://aws.amazon.com/jp/security/penetration-testing/)から申請する。

この際に、アカウントIDやターゲットの情報、なぜテストするのか等、いくつかの情報入力が必要になる。
また、依頼をしてメールの返答があるまで数営業日かかり、
状況次第では、より詳細なテスト方法について問い合わせがある。（ありました）

>Please be aware, network stress test requests must be submitted at least two (2) weeks
> in advance of your start date. Requests may take up to 5-7 business day for processing.

とある通り、余裕を持った申請が必要になる。

# その他
負荷テスト時に、ELB経由で実行する場合は、ELBの[暖気申請](https://dev.classmethod.jp/cloud/aws/elastic-load-balancing-pre-warming/)
CloudFront経由で実行する場合は、CloudFrontの[上限緩和](https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws_service_limits.html#limits_cloudfront)や[テスト方法](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/load-testing.html)
も併せて確認するべき。

# 侵入テストに関して(追記)
公式ドキュメントの[侵入テストに関するページ](https://aws.amazon.com/jp/security/penetration-testing/)が更新されていることに気づいたので追記する。
以前は、侵入テストに関してはほぼすべて事前に申請が必要だったが、以下に関するものは申請不要となったようだ。

- Amazon EC2 インスタンス、NAT ゲートウェイ、Elastic Load Balancer
- Amazon RDS
- Amazon CloudFront
- Amazon Aurora
- Amazon API Gateway
- AWS Lambda 関数および Lambda Edge 関数
- Amazon Lightsail リソース
- Amazon Elastic Beanstalk 環境

ただし、以下に関する行為は**禁止**であり、変わらず申請が必要になる。

- Amazon Route 53 ホストゾーン経由の DNS ゾーンウォーキング
- サービス妨害 (DoS)、分散サービス妨害 (DDoS)、シミュレートされた DoS、シミュレートされた DDoS
- ポートフラッディング
- プロトコルフラッディング
- リクエストフラッディング (ログインリクエストフラッディング、API リクエストフラッディング)

[^1]: 一部許可された。追記を参照
[^2]: AWS Organizationsの一括請求の関係にあるかどうか
Nuxt.js+Express.jsをPleskにデプロイしてみた

# Nuxt.jsとExpress.jsで作ったサイトをPleskにデプロイ

Nuxt.jsをPleskにデプロイする情報が少なかったので共有

## 環境
- Nuxt.js v2
- Express.js v4
- backpack.js
- Cent OS7
- Plesk Onyx
- Node.js v9
- axios module

# １．Nuxt.jsを導入
[Nuxt.js](https://ja.nuxtjs.org/guide/installation)

基本的には公式のインストール手順に沿ってやれば大丈夫です。


今回はサーバーサイドフレームワークをExpressに選択
Axios moduleも選択して導入してください。

勝手に環境を作ってくれるのは大分でかい！

# ２．必要なモジュールをインストール
今回利用するのは[backpack](https://github.com/jaredpalmer/backpack)

Nuxt1系のテンプレートでも使われていたやつですね。

これを導入することで、serverの設定時にES6が使えるようになり、build時に起動ファイルを生成してくれます。

下記コマンドで対象のフォルダに追加

``` bash
yarn add backpack-core
```

# ３．package.jsonを編集

Nuxtの起動スクリプトの修正をします。


下記の記述を

``` json:package.json
"scripts": {
    "dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
    "build": "nuxt build",
    "start": "cross-env NODE_ENV=production node server/index.js",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "npm run lint"
},
```
こちらに変更

``` json:package.json
"scripts": {
    "dev": "backpack dev",
    "build": "nuxt build && backpack build",
    "start": "cross-env NODE_ENV=production node build/main.js",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "npm run lint"
}
```
これでyarn run buildをしたときにbuildフォルダの下にmain.jsを書き出してくれます。

# ４．backpackを介してNuxtを起動する設定

backpack.config.jsファイルをフォルダ直下に作成します。

``` js:backpack.config.js
module.exports = {
  webpack: (config, options, webpack) => {
    config.entry.main = './server/index.js'
    return config
  }
}
```
これでNuxt起動時にbackpackが読み込むExpress側の起動スクリプトを読み込んでくれます。

# ５．Axios moduleの設定
Axiosの設定をしないとルーティングをした際にサーバーエラーがでます。

nuxt.config.jsからaxiosを設定しましょう！

きっとこういうのがあります。

```js:nuxt.config.js
axios: {
    // See https://github.com/nuxt-community/axios-module#options
},
```
これを自分なりに設定していくんですが、今回は最低限

```js:nuxt.config.js
axios: {
    baseURL: 'https://example.jp/', // ローカルでは必要ない本番環境にデプロイ時設定してください。
    credentials: false,
    browserBaseURL: process.env.BASE_APP_URL || '/'
}
```
このように設定すれば最低限OK!

# ６．いよいよデプロイする
gitとかftpなど何でもいいので、pleskの対象のフォルダにnode_modules以外をアップロードしてください。

Pleskの対象のWebドメイン下のNode.jsを有効にしてください。
![plesk.png](https://qiita-image-store.s3.amazonaws.com/0/368602/3b4bbed3-b12a-1a26-f5d8-2e3902f831bb.png)

package.jsonが右側に表示されたら読み込まれている証拠です。

これからやることは

- まずはNPM installしましょう！
- Run scriptからbuildコマンドを実行しよう

![build.png](https://qiita-image-store.s3.amazonaws.com/0/368602/a9f4f05e-b3a8-e7f0-469c-1113b854919e.png)

ここまで成功したら、Application Startup FileをNuxtフォルダのbuild/main.jsに設定する
これで右側にmain.jsが表示されます。

ここまで来たら、Restart Appを押して再起動します。
これでデプロイが完了です。

# 起動しない場合は
- PHP SettingsのPHPが有効になっていないかチェック
- そもそもbuildができないというときは

https://support.plesk.com/hc/en-us/articles/360000644114-Node-js-Run-Script-option-doesn-t-work-no-node-binary-in-the-current-PATH
ここら辺とか参考にするといいかも
SQLAlchemy Migrateで複合ユニークキーを作成する方法

# 失敗例
SQLAlchemy Migrateで、複合ユニークキーを作成しようとしたがうまくいかなかった。
以下はカラム`a`,`b`,`c`に対して複合ユニークキーを作成しようとした例。

```python
from sqlalchemy import *
from migrate import *
from sqlalchemy.dialects.mysql import BIGINT, INTEGER, VARCHAR

meta = MetaData()
mytable = Table(
    'ng_images', meta,
    Column('id', BIGINT(unsigned=True), primary_key=True, nullable=False, autoincrement=True),
    Column('a', INTEGER(unsigned=True), unique=True),
    Column('b', INTEGER(unsigned=True), unique=True),
    Column('c', VARCHAR(60), unique=True)
)
```

# 解決策
`UniqueConstraint`を使うことで解決できた。

```python
from sqlalchemy import *
from migrate import *
from sqlalchemy.dialects.mysql import BIGINT, INTEGER, VARCHAR
from migrate.changeset.constraint  import  UniqueConstraint

meta = MetaData()
mytable = Table(
    'ng_images', meta,
    Column('id', BIGINT(unsigned=True), primary_key=True, nullable=False, autoincrement=True),
    Column('a', INTEGER(unsigned=True), unique=True),
    Column('b', INTEGER(unsigned=True), unique=True),
    Column('c', VARCHAR(60), unique=True)
)
UniqueConstraint('a', 'b', 'c', name="unique_idx_mytable", table=mytable)
```