Vimを毎日自分用にビルドするようにした

github.com

モチベ

さきっちょ追いかけてるおれかっこいいがしたかった。

何ができるか

github に上がってる vim をビルドして、kaoriya-vimのexeと差し替えます

何が必要か

どうしたらできるか

git clone https://bamchoh/build-my-vim してもらって build.bat を実行すればできます

ただ、ruby だとか mysys2 だとかのパスが固定なので、そこは自分の環境に合わせてもらう必要があるので

自分用にするならフォークしてもらったほうがいいかも。あくまで私のリポは参考程度で。

Windowsのシリアル通信でBREAK信号を送受信する

https://msdn.microsoft.com/ja-jp/library/cc429842.aspx

https://github.com/bamchoh/go-serial/commit/f74298f65a6834a06357510f1d208ff8df764c11

SetCommMask で EV_BREAK を設定しておくこと。そうしないと、エラーになる。

あと、立ち上がりは検出できるけど、立下りは検出できなさそう。

https://ja.stackoverflow.com/questions/41123/rs232c%E3%81%AEbreak%E4%BF%A1%E5%8F%B7%E3%81%AEon-off%E3%81%AE%E6%A4%9C%E5%87%BA%E3%82%92windows%E3%81%A7%E8%A1%8C%E3%81%86%E3%81%AB%E3%81%AF

一応、BREAK信号を送信するのと、受信(?)するののサンプルは以下のような感じで

package main

import (
    "bufio"
    "flag"
    "fmt"
    "log"
    "os"
    "time"

    "github.com/bamchoh/go-serial"
)

type SIO struct {
    port serial.Port
    txq  chan []byte
    rxq  chan []byte
}

func (sio *SIO) Start() {
    go sio.Write()
    go sio.Read()
}

func (sio *SIO) Write() {
    for {
        q := <-sio.txq
        log.Printf("send: %q", q)
        sio.port.Write(q)
    }
}

func (sio *SIO) Read() {
    err := sio.port.SetCommMask(0x0041)
    if err != nil {
        fmt.Println(err)
    }
    for {
        buf := make([]byte, 128)
        n, err := sio.port.Read(buf)
        if err != nil {
            fmt.Println(err)
            time.Sleep(1 * time.Second)
            continue
        }
        sio.rxq <- buf[:n]
    }
}

func (s *SIO) SetBreak() {
    s.port.SetBreak()
}

func (s *SIO) ClearBreak() {
    s.port.ClearBreak()
}

var port = flag.String("p", "COM3", "port name")
var baud = flag.Int("b", 9600, "baud rate")

func main() {
    flag.Parse()
    c := &serial.Mode{BaudRate: *baud}
    s, err := serial.Open(*port, c)
    if err != nil {
        log.Fatal(err)
    }

    txq := make(chan []byte, 5)
    rxq := make(chan []byte, 5)

    sio := SIO{
        s,
        txq,
        rxq,
    }

    go sio.Start()

    go func() {
        scanner := bufio.NewScanner(os.Stdin)
        for scanner.Scan() {
            text := scanner.Text()
            s.SetBreak()
            time.Sleep(10 * time.Millisecond)
            s.ClearBreak()
            txq <- []byte(text)
        }
    }()

    for {
        q := <-rxq
        if err != nil {
            log.Fatal(err)
        }
        log.Printf("recv: %v", q)
    }
}

余談だけど、LinuxだとBREAK信号の受信が\FF\00\00という3バイトに変換されてしまうみたい。 バイナリデータの送受信だと、このバイト列が来るようなプロトコルを使うようなものだと BREAK信号を送信できないという制限がかかってしまう。回避策ってないのかな?

https://stackoverflow.com/questions/14803434/receive-read-break-condition-on-linux-serial-port

追記(2018/7/17) Linux の BREAK信号の受信方法がなんとなくわかった。

Armadillo460シリアルとTFTP | アットマークテクノ ユーザーズサイト

ここによると、ioctlのTIOCGICOUNTを使うとできるらしい。 ラズパイで、確かにBREAK信号を受信するとカウントアップしていることが確認できた。 カウントが上がってることと、\xFF\x00\x00 のバイト列が来てることをダブルチェックして BREAK信号を認識できるかもしれない。O_NONBLOCKなので、ループがすごい回ってしまうのが どうにかしたいところ。

(追記2018/7/18) 非カノニカルモードにすることでブロッキングしていても、指定のバイト数を受信すれば 処理が戻るようにできた。後、残ってる課題は カウンタのクリアの仕方かなぁ

The Linux Serial Programming HOWTO: $B%W%m%0%i%`Nc(B

以下にサンプルを例示しておく。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <linux/serial.h>

#define SERIAL_PORT "/dev/ttyAMA0"

int main(int argc, char *argv[])
{
    unsigned char msg[] = "serial port open...\n";
    unsigned char buf[255];
    int fd;
    struct termios tio;
    int baudRate = B9600;
    int i;
    int len;

    fd = open(SERIAL_PORT, O_RDWR|O_NOCTTY);
    if (fd < 0) {
        printf("open error\n");
        return -1;
    }

    tio.c_cflag += CREAD;
    tio.c_cflag += CLOCAL;
    tio.c_cflag += CS8;
    tio.c_cflag += 0;
    tio.c_cflag += 0;

    cfsetispeed(&tio, baudRate);
    cfsetospeed(&tio, baudRate);

    // non canonical mode setting
    tio.c_lflag = 0;
    tio.c_cc[VTIME] = 0;
    tio.c_cc[VMIN] = 1;

    ioctl(fd, TCSETS, &tio);

    // send break signal for 100 ms(?)
    tcsendbreak(fd, 100);
    tcdrain(fd);

    // write 2 bytes
    buf[0] = 'A';
    buf[1] = 'B';
    len = 2;
    write(fd, buf, len);
    tcdrain(fd);

    // waiting for receive any data
    while (1) {
        len = read(fd, buf, sizeof(buf));
        if (0 < len) {
            // check break detection count
            struct serial_icounter_struct icount;
            ioctl(fd, TIOCGICOUNT, &icount);
            printf("brk: %d", icount.brk);

            // print received data
            for(i = 0; i < len; i++) {
                if(i != 0) {
                    if((i % 8) == 0) {
                        printf("\n");
                    } else {
                        printf(":");
                    }
                }
                printf("%02X", buf[i]);
            }
            printf("\n");
        }
    }
    close(fd);
    return 0;
}

【ブロク読書感想文】→ テスト自動化の理論と技術と戦略:LINE Developer Meetup Tokyo #39 - Testing & Engineering

読書したブログ

engineering.linecorp.com

これを読んでてよくわからない単語があったので、調べてメモ。 後で考えるときの参考にできればいいなという感じ。

違和感のアンドン化

アンドン - Wikipedia

違和感を見える場所に書き出して、リスク的なものをみんなと共有できてイイネ。ということだろうか? リスク共有しても「そうだねー、そういうリスクあるよねー問題だよねー」みたいなので終わりがちなので注意していきたい。

フロントローディング

フロントローディングとは? |【エン転職】

「初期段階で品質の作りこみを綿密にする」という意味らしい。 でも、品質を作りこむのって時間がかかるし、試作からのブラッシュアップのほうが いいような気もするんだけど、早く品質を作りこむ手法みたいなのあるのだろうか? 気になる。

インダストリー 4.0

インダストリー4.0 - Wikipedia

「IoTやAIを用いることによる製造業の革新」という意味合いが強そう。 AIというか機械学習による不具合発見の効率化には興味がある。

デジタルツイン

Digital Twin(デジタルツイン) | IoT

「工場や製品などに関わる物理世界の出来事を、そっくりそのままデジタル上にリアルタイムに再現する」ということらしい。 仮想現実のようなものだろうか?物理的な制約がなくなるので、テストもしやすいよねってことなのかなー?

QAアーキテクチャ

QAアーキテクチャの設計による 説明責任の高いテスト・品質保証 Qaアーキテクチャの話 QAアーキテクチャはプロセスアーキテクチャか? by @YasuharuNishi - Togetter

まだちゃんと読んでない。後で読む(ほんとか?)

SaPID

ソフトウェアプロセス改善手法“SaPID”による自律改善実践セミナー| JUSE-SQiPセミナー

アドホックテスト

アドホックテスト(あどほっくてすと) - ITmedia エンタープライズ

俺が探索的テストだと思っていたものはアドホックテストだったのか...

VSTeP

VSTeP – Qualab

SPLIT

Cookpadエンジニアが解説 “テスト自動化”を実現する「SPLIT」とはなにか? - ログミーTech(テック)

Cookpad TechConf 2018

まとめ

こういう発表資料を見ると、なるほどなー。たしかになー。という気分になるんだけど。 じゃぁ、それをどう自分の関わっているプロジェクトに落とし込んでいこうか。ということを考えると まず上司を説得して、プロセスを改善して。。。みたいなことになるので、まず上司を説得するためには どうするればいいのか。みたいなのを学びたい気もする。

友達同士でもくもく会した

要約

友達同士でもくもく会して、意外と捗って良かった

もくもく会とは?

自宅には誘惑がいっぱいあるので、プログラミングとかやろうと思ってもなかなか捗りませんよね。でも周りに人が居るとよく見られようという意識が高まって誘惑に負けずに作業に集中できる。という効果があります。カフェで勉強すると意外と捗ったりするのはそういう理由ですね。でも、カフェだとガヤガヤしてて集中できない。という人も居ると思います。そこで「もくもく会」です。もくもく会では、静かな場所で集中して作業したい人が集まることで、集中力を高めながら、作業を捗らせる。ということを目的としています。また、同じ同志が集まることで、問題解決をみんなで出来るという強みもあり、一人で作業するよりも何倍も効率が上がる!というもくろみがあります。

友達同士でもくもく会

とはいえ、そういう会に参加するのは、結構ハードルが高いものです。私もその一人でした。ですが偶然、友達が「もくもく会」に興味があり、それに賛同したことから、あれよあれよと「友達同士でのもくもく会」が開催されることが決定しました。もくもく会といっても、上で述べたような効率よく作業しよう!という感じではなく、ゆるく集まって作業できたらいいよね。ぐらいの気持ちでした。現に、「もくもく会」ではなく、「もぐもぐ会」という名前になってて、一部のメンバーはお菓子を食べながら雑談をしたりしてましたし(笑)

なんしか、「もくもく会」というものがどういうもので、どれだけ効果があるのか?友達とやっても効果があるのか?という実験的な会だったと思います。

「もぐもぐ会」感想

日曜の13時から始まって、18時に解散でした。はじめは「5時間もするのかー」という気持ちでしたが、意外と集中して作業していたということもあってかすぐに時間が過ぎたなーという感想です。

開始する前に、みんなで今日やることを言い合ってからもくもく会開始、終了の30分前に何をやったかを発表して終わりました。発表といっても大したことではなく、「○○を実装しようと思ったけど、ここまで作って時間切れでした~」ぐらいの軽い感じです。これぐらい軽いほうが参加しやすいかな。とも思いました。

合計8人の参加者がいて、そのうち3人は「もぐもぐ会」を実施、5人は「もくもく会」を実施しました。「もぐもぐ会」メンバーは結構気を使って会話のトーンを落としてしゃべってくれたってのもあって、良いBGM感という感じでした。集中が切れたら、私ももぐもぐ会に10分ほど参加したりして、それなりのリフレッシュも入れられましたし。差し入れもうまかった。

作業自体は集中できたと思います。完全にYoutube/Twitterをシャットアウトできましたし、最初にやることを明確にしていたということもあり、ここまではやりきるぞ!という気持ちで作業ができたので、いつも以上に集中できたと思います。

今後

今回の会場はマンションの一室を借りて実施しました。(借りたのは友達ですが) 作業スペースはきれいでよかったのですが、トイレが普通に1ルームのトイレだったので、音漏れが気になったので、もし次やるならそういうところも気にしないといけないかなーと思いました。

友達同士でやるもくもく会はストレスフリーにもくもく出来ることがわかったので、これからも定期的に実施していけたらなと思います。

それとは別に、外部のもくもく会にも参加していくことで自分のスキル向上もあるのかなと思っています。 とりあえず、まずは、ネット上でもくもく会が開催されているようなので、それに参加しようかなぁ。

mockmock.connpass.com

JWTを生成/解析するときのsecret keyの生成方法

JWTについて調べてる。golangでちょっと使いたい用途があったので。

golang には JWT生成/解析するライブラリが結構あって、jwt-goってのが有名みたい。

github.com

func createTokenString(data *User, secretkey string) (string,error) {
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, data)
    return token.SignedString([]byte(secretkey))
}

こんな感じでトークンが生成できるんだけど、secretkeyの部分に何を入れたらいいんだろう?ってなってた。

railsの例を見ると、configハッシュのsecret_key_baseキーに入っている値を渡してるみたい。 値はランダムな文字列のようだ。

blog.naoshihoshi.com

それはどうやって生成されてるかっていうと、rake secret みたいなコマンドを打つと生成できるようだ。でも、どういうアルゴリズムで生成されているかわからない。

とおもったら、以下に答えが。というかソースが。

til.hashrocket.com

んで、secure random golang とかで検索すると、まんまの答えがqiitaに上がってた。

qiita.com

ということで、これを使わせてもらって、めでたくセキュアにJWTのデータを生成・解析できるようになりました。

めでたし、めでたし。

heroku の golang で http から https へリダイレクト

お名前.comで取得した カスタムドメインを使ってhttps化しようと思ったけど、なんか難しかったので、カスタムドメインはあきらめた。んで、herokuapp.com のサブドメインSSL化してhttps化完了とす。

でも、httpのほうもアクセスできちゃうので、そっちをどうにか閉じたい。herokuの機能としてhttpからhttpsへのリダイレクトはサポートされていないようなので、自前でリダイレクトしてあげないといけないっぽい。

Can Heroku force an application to use SSL/TLS? - Heroku Help

でも、↑のサンプルには go のサンプルがない... つらたん...

なので、色んなサイトを参考に以下のように作成。

func main() {
    var err error
    proto := os.Getenv("PROTO")
    if proto == "" {
        proto = "https"
    }

    engine := gin.New()
    engine.Use(func(c *gin.Context) {
        if proto != "https" {
            return
        }

        header := c.Request.Header
        isssl := false
        if params, ok := header["X-Forwarded-Proto"]; ok {
            if len(params) != 0 && params[0] == "https" {
                isssl = true
            }
        }
        if !isssl {
            req := c.Request
            loc := "https://" + req.Host + req.URL.Path
            if len(req.URL.RawQuery) > 0 {
                loc += "?" + req.URL.RawQuery
            }
            c.Redirect(http.StatusMovedPermanently, loc)
        }
    })

    engine.Run(":" + port)
}

抜粋なので、これだけではちゃんと動かない。 全体は こちら

ローカルでは http で動かしたかったので、環境変数PROTOがあるかどうかで判別している。 herokuでは、httpsの場合だと、X-Forwarded-Protohttpsが入ってくるらしいので、それをチェックして httpsじゃない場合はリダイレクトしている。