nbld
寒くなるこの時期、冬野菜が美味しい。筆頭は白菜。
地元の野菜コーナーで、大玉が200円、小玉が108円と庶民的な値段。大玉はお一人様2個って制限付き。中には、一家総出で買いに来る家族が居る。韓流ブームでキムチでも漬けるんでしょうかね? 柿の皮やらリンゴの皮やら、和唐辛子を入れて、日韓協力だったりして。
生憎、オイラーは鼻の曲がるようなキムチは大嫌い。よって、大量に買う事は無い。鍋用に週に1個も有れば十分。
鍋と言えば、貧乏鍋が定番。1個100円のさばの缶詰があれば、材費200円で腹一杯になる。が、この所安いさば缶が手に入らなくなっている。
どのスーパーへ行っても、さば缶のコーナーには、某TVの番組の影響でさば缶の品不足が続いています、供給が不安定な為ご了承下さいって言う張り紙が目立つ。
そのくせ、1個400円とかの高級さば缶は、誰も買わないせいか大量に陳列されている。 これって、さばマフィアの暗躍かな?
アベーちゃんよ、ちゃんとご指導宜しく。
CentOS Desktop login fail
いつの間にかCentOS7のDeskTopへ入れない状況になってた。sshでCUI端末では使えるのだけどね。管理者の癖を学習して、GUIはOS自らloginをしない設定にしちゃったの?
ええ、ちゃんとgdmの画面は出てるので、パスワードを入力すると、暫く待たされてGnomeが動き出すかと思いきや、元のgdmな画面に戻ってしまう。
但し、gdmに戻る時の画面のちらつき具合が、logout時のちらつき具合に似てる事に気が付いた。ログインした瞬間に追い出されてしまった感じがする。
ネットを検索するも、こんな症例にはお目にかかれなかった。ひょっとして症例の訴え方が不適切だったかも?どうやったら修復出来るのだろう? 色々なプロセスが動いているし、ログを見ても、手がかりになりそうなものは書かれていなかった。だから、GUIって嫌いなんだよなー。
で、一つやる事を思い付いた。Home下にあるGUIに関係してそうなフィアルやらDirを片っ端から消してみる事。やったけどだめだーーー。OSごと消してしまいたいぞ。
まてまて、新しいDeskTop環境を作ってみるって言う手があるな。どうやって? そんなの簡単。新しいユーザーを作れば良い。
adduser ham って叩いたよ。そしたらpasswordって聞いてきたんで返答。これで、/home/hamが出来上がって、/etc/passwdを見る限り、新規ユーザーが出来た風。
早速GUIでログイン。が、何度トライしてもアクセスが拒否された。何でかなーーー。ええい、こうなったら得意のCUI戦法だな。
ssh ham@localhost したよ。パスワードを入れると、Permission denied って言ってきた。
えっ、新規ユーザーを登録した時に、ちゃんとパスワードを登録したはず。念のために、sudo cat /etc/shadow してみた。そしたら、本来パスワードが置かれるべき所が、-Uなんていう不適文字になってたぞ。
しょうがないので、sudo passwd ham して、再設定。これでCUI/GUI共に無事にログイン出来た。adduserで登録されるのはロックされてるのね。manを見ればちゃんと書いて有るんだろうけど、見る気Nothing。
と言う事で、新規ユーザーでは無事にDeskTop login出来る事が確認出来た。後は、既存のユーザーのdeskTopの何処かが壊れてるって事になるけど、どこをどうつつけば良いものか? 皆目見当が付きませんよ。
ham pts/0 xxx.xxx.xxx.xxx Thu Nov 22 14:09 still logged in sakae :0 :0 Thu Nov 22 14:08 gone - no logout
ひょっとして、この見慣れないlastの出力が、手がかりになるかなあ?
まあいいや、先に進もう。んで、取り合えずでもDeskTopを動かしたかったか? それは次節に続く。
method chain
昔書いた血圧グラフソフト。golangを使って入力。haskellを使ってgnuplotに渡すデータの抽出。データが揃った所でバッチでgnuplotスクリプトの実行って流れになってる。haskellでやってた所はnewlispで書いていたりもした。まるで、言語の入れ喰い競争みたいだ。
今後の事も有るんで、なるべくgolang一本にしておきたい。(とはいえ、gnuplotのスクリプトはそのまま使う。気の迷いで、githubから、グラフパッケージなんかを拾ってくるなよ)
かの昔には色々な(フィルター)機能を付けていたけど、今はさっぱり使っていない。だったら、機能を整理しよう。直近のデータについてグラフ化出来れば十分。
多機能化のために、たとえば
func tl(n int, ds AAy) AAy { if len(ds) < n { fmt.Println("Warnning: Req size is to big, apply possible size.") return ds } return ds[len(ds)-n:] }
こんな風に、加工すべきデータを関数の引数として受け取っていた。パイプを多段に渡って組み立てる方式。
でも、実現すべき機能が固定なら、メソッドにしちゃえ。そうすれば、 オブジェクト指向っぽく出来るぞ。ああ、オブジェクト指向ってのは、「自分自身の振る舞いを知っているのがオブジェクト」って事ね。
上記の例なら、渡ってくるデータdsの尻尾の部分n個を返すってやつ。(ds AAy)ってのを前にくくり出せば、オブジェクト指向っぽくなる。
そうすれば、rubyみたいにメソッドチェーンが簡単に実現出来るぞ。んな訳で、機能を絞ったものに改造した。(ソースは、後掲)
今回の理屈を要領よくまとめた記事が出てた。
ちゃぶ台返し
喜んでいたら、以下のような記事を目にした。ちゃぶ台返しである。
Go における FunctionalOptionPattern と MethodChaining について考える
Go言語のFunctional Option Pattern
nbld
// blood PNG(pdf) by gnuplot // Using gnuplot script toPNG.plt topdf.plt package main import ( "encoding/csv" "flag" "fmt" "io/ioutil" "os" "os/exec" "strconv" "strings" ) const dbfile = "current.csv" type AAy [][4]int // main data type var bld AAy // blood data const ( // rows index name 0 .. 3 ymdh = iota hi low pls ) func failOnError(err error) { if err != nil { panic(err) } } func mycsv(csvfile string) { var rows [4]int fd, err := os.Open(csvfile) failOnError(err) defer fd.Close() reader := csv.NewReader(fd) all, err := reader.ReadAll() failOnError(err) for _, el := range all { for i, v := range el { rows[i], err = strconv.Atoi(v) failOnError(err) } bld = append(bld, rows) } } func savecsv(csf string) { buf, _ := ioutil.ReadFile(csf) _ = ioutil.WriteFile("Backup.csv", buf, 0666) fd, err := os.OpenFile(csf, os.O_CREATE|os.O_WRONLY, 0666) failOnError(err) err = fd.Truncate(0) failOnError(err) defer func() { fd.Close() }() w := csv.NewWriter(fd) for _, el := range bld { rows := make([]string, 0) for _, v := range el { rows = append(rows, strconv.Itoa(v)) } w.Write(rows) } w.Flush() } func ire(ym int) { var a, b, c, d string var rs [4]int for { a, b, c, d = "", "", "", "" fmt.Printf("%d> ", ym) fmt.Scanln(&a, &b, &c, &d) if a == "fin" { break } rs[ymdh], _ = strconv.Atoi(a) rs[hi], _ = strconv.Atoi(b) rs[low], _ = strconv.Atoi(c) rs[pls], _ = strconv.Atoi(d) if rs[ymdh] > 3123 || rs[hi] < 80 || rs[low] < 40 || rs[pls] < 40 { fmt.Println("Bad data") continue } rs[ymdh] += (ym * 10000) if rs[ymdh] <= bld[len(bld)-1][ymdh] { fmt.Println("Bad seq.") continue } bld = append(bld, rs) } savecsv(dbfile) } func (ds AAy) pp(fn string) { xf,_ := os.Create(fn) defer xf.Close() for _, el := range ds { fmt.Fprintf(xf, "%d %d %d\n", el[ymdh], el[hi], el[low]) } } func (ds AAy) tl(n int) AAy { if len(ds) < n { fmt.Println("Warnning: Req size is to big, apply possible size.") return ds } return ds[len(ds)-n:] } func (ds AAy) am() AAy { var rs AAy for _, el := range ds { if el[ymdh]%100 < 12 { rs = append(rs, el) } } return rs } func (ds AAy) pm() AAy { var rs AAy for _, el := range ds { if el[ymdh]%100 >= 12 { rs = append(rs, el) } } return rs } func main() { var vire *int = flag.Int("ire", 1811, "Input YYMM's data") flag.Parse() args := "" flag.Visit(func(f *flag.Flag) { args += fmt.Sprintf(":%s: ", f.Name) }) mycsv(dbfile) // output is bld if strings.Index(args, ":ire:") >= 0 { ire(*vire) } sz := 70 bld.am().tl(sz).pp("am.dat") bld.pm().tl(sz).pp("pm.dat") exec.Command("gnuplot", "toPNG.plt").Run() exec.Command("gnuplot", "topdf.plt").Run() }
toPNG.plt topdf.plt
gnuplot用スクリプト
debian:blood$ cat toPNG.plt # blood graph set terminal pngcairo mono font "Ryumin-Light-90pv-RKSJ-H,10" size 21cm,28cm set output "./zzz.png" stats "am.dat" using 2:3 amh = sprintf(" 最高血圧(平均=%.1f 標準偏差=%.1f)", STATS_mean_x, STATS_stddev_x) aml = sprintf(" 最低血圧(平均=%.1f 標準偏差=%.1f)", STATS_mean_y, STATS_stddev_y) stats "pm.dat" using 2:3 pmh = sprintf(" 最高血圧(平均=%.1f 標準偏差=%.1f)", STATS_mean_x, STATS_stddev_x) pml = sprintf(" 最低血圧(平均=%.1f 標準偏差=%.1f)", STATS_mean_y, STATS_stddev_y) set grid set yrange [50:160] set ytics 10 unset key # no label on right top set xdata time set timefmt "%y%m%d%H" set format x "%m/%d" # m/d/y -> m/d set multiplot layout 2,1 set title '起床時: ' . amh . aml plot "am.dat" using 1:2 with lines, "am.dat" using 1:3 with lines set title '就寝時: ' . pmh . pml plot "pm.dat" using 1:2 with lines, "pm.dat" using 1:3 with lines unset multiplot set terminal dumb
debian:blood$ diff -u toPNG.plt topdf.plt --- toPNG.plt 2018-11-25 06:11:49.384280556 +0900 +++ topdf.plt 2018-11-25 06:12:29.440119619 +0900 @@ -1,13 +1,13 @@ # blood graph -set terminal pngcairo mono font "Ryumin-Light-90pv-RKSJ-H,10" size 21cm,28cm -set output "./zzz.png" +set terminal pdfcairo mono font ",20" size 21cm, 29cm +set output "./zzz.pdf"
good code by golint
golangのコードを書く時、お勧めのスタイルがあるとか。それを外れた場合に文句を言ってくれる、golintって言うツールが有るそうな。そういうのは、早い段階で導入して、独りよがりにならないようにしよう。
下記は、その実行例
sakae@usvr:~/go/src/blood$ go get github.com/golang/lint/golint sakae@usvr:~/go/src/blood$ ~/go/bin/golint nbld.go nbld.go:18:6: exported type AAy should have comment or be unexported nbld.go:178:11: should omit type *int from declaration of var vire; it will be inferred from the right-hand side
上に載せたコードを点検して貰った所、2点注意された。こうして金太郎飴みたいになっていくんだな。まるでPythonみたいにね。
;; To install golint, add the following lines to your .emacs file: ;; (add-to-list 'load-path "PATH CONTAINING golint.el" t) ;; or golint.el into lisp dir ;; (setq load-path (append '("~/.emacs.d/lisp" ) load-path)) ;; (require 'golint) ;; ;; After this, type M-x golint on Go source code. ;; ;; Usage: ;; C-x ` ;; Jump directly to the line in your code which caused the first message.
おまけが付いていた。コンパイルエラーの修正方法と同じ扱いになってて便利。vim屋さん用のプラグインも同梱されてたな。(使わない、オイラーには使えないけど)
auto-complete
前回入れた、golang用のGUI版開発環境、liteideにも補完機能が付いていた。 今emacs上で使ってるcompany-goと挙動が違う。はてな?と思ったら、emacs上で補完を提供するのには、2つの流派が有るのね。知らんかった。
もう一方の補完は、auto-complete派。ネットを調べたら、 「Emacsのトラノマキ」連載第09回「auto-completeを使おう」(松山智大)なんてのが見つかった。日本製を使ってみるべし。go-autocompleteも合わせて入れる。下記がその設定。
(with-eval-after-load 'go-mode ;; auto-complete (require 'go-autocomplete) (require 'auto-complete-config) (ac-config-default) (setq ac-use-menu-map t) (set-face-background 'ac-selection-face "blue") ;; godef key bindings (define-key go-mode-map (kbd "M-.") 'godef-jump) (define-key go-mode-map (kbd "M-,") 'pop-tag-mark))
これで、挙動がliteideと同一になった。めでたしめでたし。