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と同一になった。めでたしめでたし。