Mastodonインスタンス立ち上げ後にやること

なんとなくDockerでMastodonインスタンスを作れるが、まだやるべきことがあります。
デイリー、ウイークリー、マンスリーでやるべきタスクがあるのでこれをcronに登録する必要があります。
ユーザーがいる場合、サービスが止まらないか気にする必要があるので予めやっておくほうが良いです。

mastodon:dailyのcron設定

mastodon:dailyというコマンドがここでやれと言われているコマンドをまとめてやってくれています。
documentation/Maintenance-Tasks.md at master · tootsuite/documentation · GitHub
dailyで実行するものなのでcronに登録しましょう。

@daily cd /your/gitcloned/mastodon && /usr/local/bin/docker-compose run --rm web rake mastodon:daily | logger -t mastodon -p local0.info

mastodon:media:remove_remoteのcron設定

1週間以上前の添付ファイルのキャッシュを消します。

@weekly cd /your/gitcloned/mastodon && /usr/local/bin/docker-compose run --rm web rake mastodon:media:remove_remote 2>&1 | logger -t mastodon -p local0.info

docker-composeへのパスは絶対パスで指定しておくか、cron実行時のPATHを確認したうえで指定してください。
cron実行時とsshのときのPATHは異なる場合が有ります。

Let's Encryptの証明書の更新のcron設定

Let's Encryptの証明書の期限は90日です。
公式で60日での更新を奨めています。
FAQ - Let's Encrypt - Free SSL/TLS Certificates
monthlyで更新しましょう。
以下は最初にwebrootでやった場合です。standaloneの場合は一度nginxを止める必要があると思います。

@monthly /your/gitcloned/letsencryption/certbot-auto renew && /bin/systemctl reload nginx

一度手元でdry-runで実際に動作するのか試しておいたほうが良いです。

certbot-auto renew --dry-run

私の環境だとはnginxのconfが雑だったため動きませんでした。
大体下のリンクからパクったconfですが、rootの場所を設定していませんでした。
documentation/Production-guide.md at master · tootsuite/documentation · GitHub
nginxのインストール->証明書取得->mastodonインストールの順で作業してるとなんとなくうまく行ってしまうポイントなのでアレ。


ちなみに立ち上げたインスタンスです。
mastodoll.net

JuliaImagesで画像の平行移動をする

Julia v0.5.1 + JuliaImages/ImageTransformations.jl v0.2.2で画像の平行移動を行う。

using Images 
using CoordinateTransformations

img = Gray{Float64}[                                                                                                                                                          
 0.0 0.0 0.0 0.0 0.0;
 0.0 0.5 0.5 0.5 0.0;
 0.0 0.5 1.0 0.5 0.0; 
 0.0 0.5 0.5 0.5 0.0;
 0.0 0.0 0.0 0.0 0.0;]

tfm = recenter(Translation(2,0), center(img_pyramid))
translated_img = warp(img, tfm)

このとき、以下のように表示され、なんか移動してなくね?となる。

 3:7×1:5 OffsetArray{Gray{Float64},2}:
 Gray{Float64}(0.0)  Gray{Float64}(0.0)  Gray{Float64}(0.0)  Gray{Float64}(0.0)  Gray{Float64}(0.0)
 Gray{Float64}(0.0)  Gray{Float64}(0.5)  Gray{Float64}(0.5)  Gray{Float64}(0.5)  Gray{Float64}(0.0)
 Gray{Float64}(0.0)  Gray{Float64}(0.5)  Gray{Float64}(1.0)  Gray{Float64}(0.5)  Gray{Float64}(0.0)
 Gray{Float64}(0.0)  Gray{Float64}(0.5)  Gray{Float64}(0.5)  Gray{Float64}(0.5)  Gray{Float64}(0.0)
 Gray{Float64}(0.0)  Gray{Float64}(0.0)  Gray{Float64}(0.0)  Gray{Float64}(0.0)  Gray{Float64}(0.0)

だが、この行列はOffsetArrayで表現されており、これでちゃんと平行移動している。
1行目の型情報にオフセットの情報が書いてあり、この値域の情報だけが下に表示されている。
ちなみにtranslated_img[1, 1]でアクセスするとBoundsErrorになるのでindicesなりで座標の値域をとってからアクセスする必要がある。


私がOffsetArrayに気付かず、テストコードやサンプルも回転移動のものしかないため少し詰まったのでメモ。
関係ないが、スーパーpre記法がjuliaに対応していた。
はてなブログ最高。

Ubuntu16.04でKinnect v1を動かす

本日ThinkPadが届き、これまで放置してしまっていたKinnectでViolin演奏中の姿勢の確認する奴作るかということでubuntu16.04でKinnect v1の動作を確認した。
とく難しいことをせず動いてしまったので、動いたよという報告だけになる。

参考にしたのは以下のスライドである。参考というかこのままである。
https://staff.aist.go.jp/kanezaki.asako/pdf/SSII2016_AsakoKanezaki_tutorial.pdf

ROSインストール

以下のマニュアルに従ってインストールする。*1
kinetic/Installation/Ubuntu - ROS Wiki

freenectインストール

Kinectを扱うためのコンポーネントをインストールする。。

sudo apt-get install ros-kinetic-freenect-launch

これをインストールすることでfreenect(ドライバ)もついでにインストールされるので予めfreenectを入れないと〜ということに悩まされない。
入るパッケージはros-kinetic-libfreenectのバージョンが0.5.1とubuntuリポジトリ経由で入るlibfreenectの0.5.2より古い。
同じドライバが違うパッケージ名で競合してるの関わりたくない感じがしたので見なかったことにした。

動作

rvizでなんか写ってることを確認する。
点群だけ表示してもは???って感じなのでrvizでみたほうが良い。
ありがちなのだが、PointCloud2とか表示に加えないと左のメニューにも表示されない。
この手の、最初設定したらもう知らん系にちょいちょい悩む。

roslaunch freenect_launch freenect.launch
rosrun rviz rviz

おわりに

前日OpenNI入れろとかNiTEを闇から入手しろみたいなブログばかり見まくって死ぬか思った。
インターネット怖い。
手順的には産総研のスライドと同じなのでこんな記事いらないのだが、16.04でもうごいたで!ありがとや!という気持ちを伝えたかっただけである。

*1:そっからかよと思うかもしれないが、僕のThinkPadは今日届いたのだ。

Golearnとplotで散布図を書く

Go入門中です。
Goleanで読み込んだデータをgonum/plotでプロットします。

package main

import (
	"fmt"
	"image/color"
	"math/rand"

	"github.com/sjwhitworth/golearn/base"

	"github.com/gonum/plot"
	"github.com/gonum/plot/plotter"
	"github.com/gonum/plot/vg"
)

func main() {
	rawData, err := base.ParseCSVToInstances("datasets/iris.csv", false)
	if err != nil {
		panic(err)
	}

	_, rows := rawData.Size()

	spal_length_attrs := rawData.AllAttributes()[0].(*base.FloatAttribute)
	spal_length_spec, _ := rawData.GetAttribute(spal_length_attrs)

	spal_width_attrs := rawData.AllAttributes()[1].(*base.FloatAttribute)
	spal_width_spec, _ := rawData.GetAttribute(spal_width_attrs)

	species_attrs := rawData.AllAttributes()[4].(*base.CategoricalAttribute)
	category_values := species_attrs.GetValues()
	category_num := len(category_values)

	fmt.Println(category_values)
	fmt.Println(category_num)

	class_attrs := rawData.AllClassAttributes()[0].(*base.CategoricalAttribute)
	class_spec, _ := rawData.GetAttribute(class_attrs)

	category_vs_raw_map := make(map[string]plotter.XYs)
	fmt.Println(category_vs_raw_map)

	// plot
	for i := 0; i < rows; i++ {
		// category
		category_bytes := rawData.Get(class_spec, i)
		category_name := class_attrs.GetStringFromSysVal(category_bytes)
		fmt.Println(category_name)
		_, isExist := category_vs_raw_map[category_name]
		if !isExist {
			fmt.Println("Add ")
			fmt.Println(category_name)
			category_vs_raw_map[category_name] = make(plotter.XYs, 0)
		}

		spal_length_bytes := rawData.Get(spal_length_spec, i)
		spal_length := spal_length_attrs.GetFloatFromSysVal(spal_length_bytes)

		spal_width_bytes := rawData.Get(spal_width_spec, i)
		spal_width := spal_width_attrs.GetFloatFromSysVal(spal_width_bytes)

		append_xy := plotter.XYs{{spal_length, spal_width}}
		pts := category_vs_raw_map[category_name]
		category_vs_raw_map[category_name] = append(pts, append_xy[0])

	}

	p, err := plot.New()
	if err != nil {
		panic(err)
	}

	p.Title.Text = "Iris Spal Length vs Width"
	p.X.Label.Text = "Length"
	p.Y.Label.Text = "Width"
	p.Add(plotter.NewGrid())

	for name, xys := range category_vs_raw_map {
		fmt.Println(name)
		fmt.Println(xys)
		plot_data, _ := plotter.NewScatter(xys)
		r := uint8(rand.Float32() * 255)
		g := uint8(rand.Float32() * 255)
		b := uint8(rand.Float32() * 255)
		plot_data.GlyphStyle.Color = color.RGBA{R: r, G: g, B: b, A: 255}
		p.Add(plot_data)
		p.Legend.Add(name, plot_data)
	}

	// save pict
	p.Save(4*vg.Inch, 4*vg.Inch, "iris_spal.png")
}


これで次のグラフがプロットされます。
f:id:YuK_Ota:20160427232438p:plain


Go、チュートリアル中なので微妙なところがあれば教えて欲しいです。

冪集合の空集合含まない奴は何ていうの?

プログラム書いていて冪集合なんだけど空集合はいらない。
できたら要素が多い順に出して欲しいって時は無いでしょうか。
私はさっきそう思いました。
空集合(power set)はitertoolsのレシピから

def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

とかけます。
コード書く上で空集合が邪魔かつ要素が多い順に出して欲しい場合はこうかなと思います。

@staticmethod
def _powerset(iterable):
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1, 0, -1))

で、空集合を含まない冪集合って何て言うんですかね…。
ありそうなもんですが。

What is shortest?

NetworkXでshortest_pathというメソッドがある。
shortest_path — NetworkX 1.10 documentation

weightのところを見るとweight=でweightを入れるとweight考慮しますと書いてある。
では
add_weighted_edges_from — NetworkX 1.10 documentation
を使って予めweightを設定した場合は?

少し試してみたが、weightは考慮されないようである。
shortest_pathの実装はshortest_path自体の引数がNoneか否かで呼び出すアリゴリズムを選択している。
https://github.com/networkx/networkx/blob/master/networkx/algorithms/shortest_paths/generic.py#L41

sourceとtargetのみ指定すると
bidirectional_shortest_pathが使用されるが、これがunweightedなモジュールの中に含まれている。
実装を見てもweightを自分で計算してそう。

まぁ、bidi rectional_dijkstraをshortest_pathの代わりに使用すればweightが考慮されるようになる。
こう、教訓としてはアルゴリズムは明示的に指定しましょうという。
まぁ、これくらいは見てくれてもいいんじゃないかな感はあるんですがどうなんですかね。

MacOSX Yosemiteでプロファイラを実行する

最近Mac上でC++を書いている。
プロファイラをかけようと思ったが意外に上手く行かなかったのでメモ。

上手くいった奴

Instruments

Apple純正。ビルド時のオプションは不要。
実行時に以下のようにする。

iprofiler -timeprofiler ./a.out

a.dtpsというディレクトリが生成される。
これをXcode付属のInstrumentsに読み込ませる。
Xcodeを立ち上げてメニューのXcode->Open Developer Tool->Instrumentsで起動するか、
Xcode.app/Contents/Applications/Instrumentsで直接実行するかして起動する。
先ほどのa.dtpsを読みこませればプロファイル結果をGUIで見れる。

上手く行かなかった奴

GNU gprof

g++ -pg main.cpp

で生成された実行体を実行してもgmon.outが生成されない。
clang、gccともに変わらず…。

gperftools

g++ -lprofiler main.cpp

a.outが生成される。
a.profにプロファイル情報を吐くようにする。

CPUPROFILE=a.prof ./a.out 

CPUPROFILE=a.profと./a.outを別々に実行するとa.profが生成されなかった。
このプロファイル結果をpprofでみるのだが、メソッド名が16進の文字列になる。

pprof a.out a.prof

原因はASLRにあるらしい。
コンパイル時に-Wl,-no_pieを追加。
これにより一部のメソッド名は正しく表示されるが大半は16進のまま。
そもそも呼んでないメソッド名が処理されていることになっているのでちょっとダメっぽい。

OS X Lion Heap profiling requires disabling Position Independent Executable · Issue #363 · gperftools/gperftools · GitHub
OS X requires disabling Position Independent Executable · Issue #565 · gperftools/gperftools · GitHub