fyneによる画面レイアウトの仕方

Go言語製のGUIライブラリ Fyne で画面レイアウトを作るための方法について書きます。

fyne でレイアウトを行う際には、fyne.CanvasObject、fyne.Container、fyne.Layout の3種類を使います。

fyne.CanvasObject はcanvasに加えられる全てのオブジェクトが満たすインターフェースです。 fyne.Container は、fyne.CanvasObject をまとめて扱うためのオブジェクトです。 fyne.Layout は、fyne.CanvasObjectの集合のサイズや位置を管理し、それらを配置するために必要な最小サイズを定義します。

fyne は、fyne.Container がもつfyne.CanvasObjectをグループ化します。そして、fyne.Layout に従って、子オブジェクトを配置します。

2019年振り返り

Web開発関連の技術を多く触った年でした。 あまり多くのことはやっていないと思っていましたが、意外といろんなことをやってい たようで忙しくしていた理由がわかりました。インターンシップに行ったことで自分の IT技術について、自信を持てるようになりました。 いくつかのOSSに貢献ができましたが、Vim のヘルプ翻訳はできずじまいとなってしまい ました。

新しく触った技術

Go言語

2018年度からさわり始めた言語で、やっと手に馴染んできた感覚があります。能動的に 自分の主力として使うことを決めた初めての言語です。 シンプルさを保ちつつ、平行処理が書きやすいこと、周辺ツールが非常に充実しており テキストエディタのみでも十分にコーディングできることが強みだと考えています。 Web API クライアント Package を書いたことが勉強になりました。

Elm

JavaScriptコンパイルする関数型の言語です。 Elm を使用すると The Elm Architecture というパターンでウェブアプリケーションを構築することになります。 Model, Update, View の3つの要素に分けてプログラムを設計することが保証されます。 v0.19とv0.18で変更点があることに注意すれば、Elm guideとコードを読めばだいたいかけるようになります。 フロントエンド開発で今後も積極的に使っていきたいです。 個人的には Vue.js や React などよりもシンプルに書ける点が魅力です。 ポートフォリオを Elm を使って書き直しています。

TypeScript

型がついた JavaScript という感じでした。 すでに開発環境が整えられたプロジェクトであればつかえるレベルになったと思っています。

HTML/ CSS

Flexboxをつかってレスポンシブなレイアウトを作る方法を学びました。

ちゃんとはやれなかった言語

Scala, Kotlin, Python, R
特にScalaは, せっかくeraさんに教わったので今年はもっと書きたいです。

Docker

インターンに参加させていただいた際に使ってから学び始めました。 メインOS側の環境を汚さず環境構築ができ、汚してもすぐ作り直せる点がすばらしいです。 徐々に Docker を使った開発環境構築をメインにしていきたいです。 現在は、自分用の Redmine を立ち上げるのに使っています。

Arduino/ 曲げセンサー, 加速度センサー

ものづくりコンテストに参加した際, 手を出しました。 向きによって反応の仕方が違ったりとセンサーの特性がよくわかっていないまま使おうとしたので苦戦しました。

M5StickC / M5StickV

昨年度から注目しているボードです。 入手はしたものの, まだデモしか動かすことができていないので今年はこれを使ってなにか1つプロダクトを作りたいです。

Language Server Protocol

テキストエディタと通信をして補完情報や定義ジャンプ等の機能を提供するためのプロトコルです。 テキストエディタがLSPをサポートしていれば、IDEと同等のサポートが受けられるようになります。 LSPが広まるとよりテキストエディタで書きやすくなっていくと思われるため, 非常に期待しています。

SELinux

audit2allow を使って機械的にフラグをつけることはできるようになりました。 また、SELinuxがどういう機能をもつものなのかの概念的な部分についてはだいぶ理解できたと思います。

中古タブレット

Nexus5, Nexus7を買って, ルート取得、ROM焼をしました。 Ubuntu touch をインストールして遊びました。

Inkscape / Gimp

ちょこっとだけ画像を編集したいということがあったので基本の部分だけ勉強しました。 Twitter 等で使用しているアイコンも Inkscape で描き直しました。

イベント

Code Blue, July Tech Festa, GDG Dev Fest, Kyoto.なんか, Golang.tokyo に参加しました。 学生の内にいくと、参加費が安くなったりと参加しやすいので積極的にいくよう意識しました。 また、何回か参加したことでやっとこういったイベントへの参加に抵抗感がなくなってきました。

資格, その他

応用情報技術者試験に合格しました。 資格は必要ないとは言われますが、少なくとも勉強するための目標としての意味はある ので、今後スペシャリスト系の資格もとっていきたいです。

ブログは、インターンシップ後はそれなりに書くことができたがなかなか継続的かつ頻繁に書くことができませんでした。 更新頻度をあげていけるように頑張ります。

日常

花譜を好きになったことがきっかけで他のVirtual Singer / YouTuber に興味を持つように なり、勢いで Dive XR Festival に行きました。

スキーを初めてやりました。結構楽しかったです。

今まで暇な時間はコードを書いているか雑多な本を読んでいるかでしたが、やっと エンジニアリングと関係なく楽しめる趣味を作ることができました。

2019年度に向けて

大学の勉強がおろそかになってしまった感が多少なりともあることは否定できないので、 今年度は大学をメインにしていきたいです。 また、個人開発のCLIツールで未完成なものがあるので完成させたいと考えています。 エンジニアリング的な面ではインフラに限らず多くの技術に挑戦してきました。 あと数年間は同じ方針で勉強していこうと考えていますが、コーディングや作ることに 偏っていた気がするので2019年度は数学的な理論の学習も増やしていきたいです。

Go言語で無線局情報を取得するAPIのクライアントライブラリを書いた

概要

この記事は、Go3 Advent Calendar 2019 の22日目の記事です。 21日目は@mikkegtさんによる「qiita.com」でした。

私は、アマチュア無線を行うサークルに属しているため、無線局の情報を調べることが多くあります。1局や2局なら手で調べてもよいが数が多くなってくると面倒極まりありません。数が多くなってくると、やはりプログラムの力を借りる必要があります。 幸いにも日本の無線局情報は総務省APIを提供しているため、APIを叩けば情報を取得できます。そこで、毎回APIのリクエストを組み立てるのは面倒なので、Go言語の練習を兼ねてクライアントライブラリを作成することにしました。

できたものは次のリポジトリで公開しています。

github.com

cli, err := soumu.NewClient("")
if err != nil {
    os.Exit(1)
}

opts := soumu.NewNumOptions(soumu.License, soumu.Amateur)
result, err := cli.GetNum(nil, opts)
if err != nil {
    os.Exit(1)
}

fmt.Printf("%+v", *result)
// ↓の感じで無線局の登録件数が取得できます。
// -> {Musen:{Count:404542} MusenInformation:{TotalCount:404542 LastUpdateDate:2019-11-03}}

APIの仕様は総務省のウェブサイト内で公開されています。

総務省 電波利用ホームページ|免許関係|Web-API機能(無線局等情報検索)について

APIクライアントの作り方は、 GolangでAPI Clientを実装する | SOTAを参考にしました。 APIのクライアントの部分については、ほぼ上のとおりになっています。

デバッグ用のロガーについては、logger.goで宣言をしており、仕様する側でSetLogger()で自前のLoggerを指定するか、DebugEnable()でロガーを有効化してログを出力できるようにしています。

また、APIから取得できるJSONデータではタブ文字や改行がそれぞれ\tや\nとしてエスケープされていたり、周波数の表記がMHz、HzやkHzが混在しており扱いにくいので、そのためのヘルパー関数を作っていこうと思っています。 周波数と電波形式のリストは、オブジェクトの配列とかで表す仕様にしてほしかった....

また、作成したAPIクライアントの使い方が簡単にわかるようにexampleディレクトリに使用例としていくつか簡単な実際に動くソースコードを置いています。 また、READMEにもざっくりとした使い方を書いています。 exampleディレクトリにあるサンプルコードとREADMEを参考にすれば使用方法はわかるようになっていると思います。

Go言語でコマンドラインツールを作成したことはありましたが、packageの実装はしたことがなかったため非常に勉強になりました。

References

mackerel-agent に PullRequest を出した話

この記事は、Mackerel Advent Calendar 2019 - Qiitaの15日目の記事です。

事前に書こうと思ってたことができなかったので、はてなインターン中に GitHub - mackerelio/mackerel-agent: mackerel-agent is an agent program to post your hosts' metrics to mackerel.io. に出した PullRequest の話をします。

インターン中に mackerel の開発用に mac book で mackerel-agent を動かす必要があったため、mackerel-agent init -apikey "${api key}"を実行したところ、設定ファイルの作成できないというようなエラーとなりました。 詳しく調べると、設定ファイルが保存されるディレクトリが存在している場合はファイルが作られ、そうでない場合はエラーとなり実行が停止されることが分かりました。 これは、init オプションのヘルプに書いてある動きと比べておかしいと感じたので、メンターの方々とも相談して下記の PullRequest を出しました。

PullRequest の内容としては、設定ファイルの場所として指定されているパスを見て、ディレクトリが存在していない場合は新規に作成するという処理を追加するものです。 また、これを追加するのに合わせて該当の場合に対するテストも追加しました。

github.com

実際のところ、この PullRequest でどの程度便利になったのかは分かりませんが、初期化の際にディレクトリを作らなくて良くなった点は個人的によかったです。 また、今回インターン中にだったので、はてなの方に困ったらいくらでも相談できるような状況で PullRequest を出せたのでかなり恵まれていたと思います。 せっかく関わったプロジェクトなので、今後もコミットしていけたらと考えています。

本当は新しくやったことを書こうと思っていましたが、想定以上に時間がとれなかったためインターンのときのことを書くことになってしまいました。。。

アドベントカレンダーも残すところ1週間と少しになってしまいましたが、これからどんな記事が投稿されるのか楽しみです。

Go言語でWeb Assemblyに入門した

この記事は、WebAssembly Advent Calendar 2019 - Qiita の 15日目の記事です。

友人に載せられて登録してしまったので、Go言語でWasmに入門しました。

単純にチュートリアルをやるだけだとつまらないので、ちょっとだけ実用的なボタンをクリックしてメニューをトグルできるようにしました。

はじめに、github.comの通りにして作成します。

次に index.html の body タグを次の内容に変更しました。 divの子要素をWasmから操作してメニューの表示非表示を切り替えます。

<button id="menu-toggle-button">Menu</button>
<div id="menu-root"></div>

また、ついでに遷移先のHTMLファイル (about.html, links.html)も適当な内容で作成します。

その後、メニューを表示するための関数ShowMenu()と非表示にする関数HideMenu()を実装しました。

menu型の配列に入れた情報を使ってメニューのDOMを生成しています。

// リンク情報を保存するための構造体
type menu struct {
    name string
    url  string
}

var document = js.Global().Get("document")

// メニューのトグル用ボタンを取得する
func getMenuToggleButton() js.Value {
    return document.Call("getElementById", "menu-toggle-button")
}

func createElement(elementName string) js.Value {
    return document.Call("createElement", elementName)
}

func appendChild(dom js.Value, elm js.Value) js.Value {
    return dom.Call("appendChild", elm)
}

// メニューを隠す
func HideMenu(this js.Value, args []js.Value) interface{} {
    menuRoot := document.Call("getElementById", "menu-root")

    for menuRoot.Call("hasChildNodes") == js.ValueOf(true) {
        child := menuRoot.Get("lastElementChild")
        menuRoot.Call("removeChild", child)
    }

    // toggle event listener
    toggleButton := getMenuToggleButton()
    toggleButton.Call("removeEventListener", "click", js.FuncOf(HideMenu))
    toggleButton.Call("addEventListener", "click", js.FuncOf(ShowMenu))
    return nil
}

// メニューを表示する
func ShowMenu(this js.Value, args []js.Value) interface{} {
    menuList := []menu{
        {name: "home", url: "/"},
        {name: "links", url: "/links.html"},
        {name: "about", url: "/about.html"},
    }
    // make menu dom
    menuListDom := createElement("ul")
    menuListDom.Set("id", "menu-item")
    for _, e := range menuList {
        li := createElement("li")
        a := createElement("a")
        a.Set("href", e.url)
        a.Set("textContent", e.name)
        appendChild(li, a)
        appendChild(menuListDom, li)
    }
    menuRoot := document.Call("getElementById", "menu-root")
    appendChild(menuRoot, menuListDom)

    // toggle event listener
    toggleButton := getMenuToggleButton()
    toggleButton.Call("removeEventListener", "click", js.FuncOf(ShowMenu))
    toggleButton.Call("addEventListener", "click", js.FuncOf(HideMenu))
    return nil
}

次に、作成した関数をmain関数でボタンのイベントリスナーに登録します。

func main() {
    // register event
    menuToggleButton := getMenuToggleButton()
    // register call back func
    menuToggleButton.Call("addEventListener", "click", js.FuncOf(ShowMenu))

    select {}
}

ビルドは次のようにします。

GOOS=js GOARCH=wasm go build -o main.wasm

HTTPサーバは、goexecが入っていなかったのでPythonで一時的に建てました。

python -m http.server 8000

この状態で localhost:8000をブラウザで開いてボタンをクリックするとメニューの表示・非表示を切り替えられます。

f:id:tomato3713:20191215021041p:plain f:id:tomato3713:20191215021037p:plain

以上、Wasmへの入門でした。 そういえば、これを書いてるときにvimplsにsyscall/jsが見えていなかったようなんですがどうしたらいいのだろう。 明日も、Go言語とWasmらしいので何が出るのか楽しみですね。

Debianを使い始めてから約1年経った

Debianをthinkpad x1 carbon 第一世代にインストールした。 - tomato3713’s blogDebianThinkpad にインストールしてから、メインのノートPCとして使い続けています。

LinuxをメインPCとして使うようになってから感じたことを紹介します。

どういった用途で使用しているか。

実験のレポートやプログラミング、Youtube の視聴などに使用しています。レポートは、OpenOffice ではなく、LaTeX でPDF を生成しています。 プログラミングでは、Visual Studio のような統合開発環境ではなく、プラグインを入れた Vim で Go言語開発をしています。CG やゲーム用ではないので快適に暮らせています。 また、表計算や発表用のスライドについては、inkscapeGimp で画像を編集し、ブラウザ上で使用できる Office Online で作成し、適宜友人と共有ができるようにしています。 Open Office で作成してもよいのですが、Power Point でも開けることが要求されることが多いのでこのような運用になっています。

環境の整備

Go や Vim といった個別のソフトウェアのインストールスクリプトは用意していますが環境全体を整えるためのスクリプトは用意していません。開発環境の整備は好きなので、壊れたときは環境をアップデートする良い機会と考えることにしています。

良かった点

  • リッチなコマンドが用意されてる

GNU Command が標準で簡単に使用できることが最も大きな利点だと感じています。普段から、Vim でプログラミングを行っており、ターミナル上で操作をしている時間がほとんどを占めています。なので標準で多くのリッチなコマンドを使用できることは重要な要素の1つです。

  • メモリを喰わない

使用しているPCのメモリが 8GByte と mac OSWindows の場合は、メモリ不足の不安がありますが Linux であれば Docker が軽く起動できることも嬉しいです。

不自由な点

  • 動かないアプリがある

Slack については問題なく使用できますが、SkypeLinux 版がないため使えず不便です。Wineを使用して動かすこともできるかも知れませんが、今のところ頻度が高くないため Skype で通話をするときのみ Windows を持ち出してきています。たまに Linux では動かない/動作が不安定なソフトウェアがあるので注意が必要です。ですが、多くのサービスは、ブラウザで利用できるためあまり困ってはいません。

  • キー配列が正しく認識されない

これは私の端末に固有の問題だと思われますが、デスクトップにログインする前は、英字配列として認識されてしまいます。一度ログインすれば日本語配列として認識されますがシャットダウンするとリセットされてしまうのでパスワードの入力の時に混乱するときがあります。

その他

他にもいくつか問題が起こったこともありますが、Linux をデスクトップにして良かったと思っています。人に進めるかというとその人のライフライフスタイルに依る部分が大きいので、積極的には薦めませんが聞かれたら可能な範囲で相談には載るつもりです。書ききれなかったこともありますが、残りはまたの機会に書こうと思います。

リポジトリ移動用のコマンドを作った

概要

だいぶ遅れてしまいましたが、UEC Advent Calender 2019 の1日めの記事です。 今日は、日常で使用しているリポジトリ移動用に作成したシェルスクリプト関数の紹介をします。

本文

ソースコードの管理は、Go言語のフォーマットに従って次のようなディレクトリ構造としています。 私は、ghq コマンドを使用して、リポジトリの管理をしているので、ghq のルートして、${gowork}を指定しています。

# 説明に不要なディレクトリは、省略しています。
${gowork}/
  +---  bin/         # 作成したバイナリファイル  
  +---  pkg/         # Go言語の依存パッケージ
  +---  src/         # すべての言語のソースコード
          +--- github.com/${github_user}/${repository}
          +--- golang.org/
          +--- ...

この方式は、ソースコードが1箇所にまとめられて管理が楽なのですが、リポジトリ間の移動が少々不便です。 ghq look で移動することも可能ですが、その場合新規にシェルのプロセスが起動してしまうので移動を繰り返すと自分がghq look して起動したプロセス内にいるのか、最初に起動したシェルのプロセス内にいるのか分からなくなってしまいSSH等でリモートから接続している際には誤って接続を切ってしまうことがあります。

これを防ぐため、シェルのプロンプトにghq look で起動されたシェルのプロセスのときのみ GHQ のような文字列を表示する方法もありますが、私は普段次のようなシェルスクリプト関数を定義して同一のプロセス内で移動するようにしています。

# Change Repository directory なので、cr としました。
cr() {
  local dir
  dir=$(find "${GOPATH}/src/" -name ${1:-.}  -prune \
                  -o -type d -print 2> /dev/null | fzf +m) &&
  cd "$dir"
}

関数の内容的には、findコマンドで${GOPATH}/src/以下のディレクトリのリストを作り、fzf コマンドに流し込んでいるだけの簡単なものです。

ターミナルで cr 関数を呼ぶと、fzf のファジー検索が始まるので、一致したディレクトリを選択して Enter を入力すればそのディレクトリに cdしてくれます。 本当なら、.gif ディレクトリを除いて検索をしたいのですが、うまくできなかったので今はこれで妥協しています。

cr 関数の実行中のgif
cr 関数実行の様子

その他

fzfghq コマンドは、はてなサマーインターンに行ってから使うようになりました。
gif 画像を作るために、ttyrec, ttygif, ttyplay コマンドを初めて使ったのですが便利ですね。