おがさわらなるひこのオープンソースとかプログラミングとか印刷技術とか

おがさわらなるひこ @naru0ga が技術系で興味を持ったりなんだりしたことをたまーに書くブログです。最近はてなダイアリー放置しすぎて記事書くたびにはてな記法忘れるのではてなブログに移行しました。

クリエイティブ・コモンズ・ライセンス
特に断りがない場合は、本ブログの筆者によるコンテンツは クリエイティブ・コモンズ 表示 - 継承 4.0 国際 ライセンスの下に提供されています。

docker-android + AppImage版Appium DesktopでAndroidテスト自動化の環境をさっくり作る

うっすいネタ、いわゆる「使ってみました」ネタで恐縮です。あと、タグSeleniumってつけてますが兄弟?プロジェクトのAppiumネタです。

私の本業はいちおうソフトウェア自動テストアーキテクト*1 なわけです。主にSeleniumを使ったWebの自動テストが得意領域ってことになってるんですが、その周辺領域であるAppiumを用いたモバイルの自動テストはあんまり手を動かした経験がなく、教科書レベルのことは言えるけど……ってのがコンプレックスでした。

最近いろいろあって残業することなく早く帰るようにしてるので、自由になる時間をYouTubeの動画*2 観て溶かしてないで、ちったー手を動かしてみますかーってことで、マイパソコンでAppiumのテスト自動化開発環境を作ろうと思い立ちました。仕事ではJava + Selenide*3 なんですけど、まあ個人の遊びなので違う言語ってことでRubyで。

ご存知の通り?私は個人ではUbuntuしか使ってないので、Ubuntu上で環境を作りたい。なのですが、AppiumってNodeアプリなので、Nodeを入れなきゃなのですが、NodeもまたこれがLinuxディストリビューションのパッケージングポリシーと合わないことおびただしい*4 のでコンテナに閉じ込めたりしたい。さらにいうとAndroid SDKとかの管理もめんどくさい。なんかいいのないかなーとググっていたら。素晴らしいものがありましたよ。

GitHub - butomo1989/docker-android: Android in docker solution with noVNC supported and video recording

AndroidのAVDとAppiumを封じ込めたコンテナ。docker run一発で全部入り環境が立ち上がる。AVDの操作ははVNCとか入れずにブラウザーで確認可能。動画記録機能まである。これは最高なのでは……。

ということで使ってみました。

Ubuntuのバージョンは18.04 LTS(bionic beaver)です。

docker-android使ってみよう

むっちゃ簡単です。

docker run --privileged -d -p 6080:6080 -p 5554:5554 -p 5555:5555 -p 4723:4723 -e DEVICE="Samsung Galaxy S6" -e APPIUM=true --name android-container butomo1989/docker-android-x86-8.1

-e APPIUM=true でAppiumサーバーも一緒にあげてます。

ちょっとコンテナサイズでかくて、初回実行時にはpullにしばらく待たされました*5 けど、あっさり動いた。ちょっと感動。

f:id:naruoga:20180713222744p:plain

AppImage版Appium Desktopからつなぐ

Appiumサーバーちゃんと動いてること確認したいですね。

そのためには(もちろん、今後使うからでもありますけど)Appiumの開発ツールであるAppium Desktopも使いたい。しかしこいつも依存関係汚すのはやだなー。そう思いつつ公式の配布先↓ 見に行ったら。

github.com

あるじゃん。AppImage版。

AppImageについては深入りしませんが*6、よーはファイル取ってきて実行権限つけるだけで、インストール不要で使えるパッケージ。これなら環境汚さないしもう使わないと思ったらファイル消すだけでOKです。

早速取ってきて(依存関係全部抱いてる関係でちょっとでっかいです)、実行権限つけて起動。

f:id:naruoga:20180713223522p:plain

今回はdocker-android内でAppiumサーバー動いてるので「Start Server」は押さずに、メニューから「File」>「New Session Window」を起動。セッション画面を起動します。

で、Desired Capabilitesを以下のようにして*7、単に設定画面を開いてみます。

{
  "platformName": "android",
  "deviceName": "device",
  "appActivity": "Settings",
  "appPackage": "com.android.settings",
  "takesScreenshot": false
}

Start Session! うりゃ!

f:id:naruoga:20180713224510p:plain

ちゃんと動いてる! やったね。

スクリプトから起動してみる

ではRubyスクリプトから起動してみましょうか。せっかくなので今度はアプリケーションをサイドロードして起動して、それを操作してみたいですね。

っと、その前に、apkを導入するときには、apkのあるフォルダを /root/tmp にマウントしろとドキュメントに書いてあるので、動いてるコンテナを止めて再起動します。スクリプトを作るフォルダにapkは置くことにして、雑に $PWD をマウントします。

docker stop android-container
docker rm android-container
docker run --privileged -d -p 6080:6080 -p 4723:4723 -p 5554:5554 -p 5555:5555 -e DEVICE="Samsung Galaxy S6" -e APPIUM=true -e CONNECT_TO_GRID=true -e APPIUM_HOST="127.0.0.1" -e APPIUM_PORT=4723 -e SELENIUM_HOST="172.17.0.1" -e SELENIUM_PORT=4444 -e MOBILE_WEB_TEST=true -v $PWD:/root/tmp  --name android-container butomo1989/docker-android-x86-8.1

あれ、コマンド履歴見直すと CONNECT_TO_GRID*8 はいらんのでは……。まあいいや。

アプリは、わたくし普段からAndroidアプリ開発してるわけではないので*9 手持ちのapkはなく、ので、Appiumのサンプル からApiDemos-debug.apkを取ってきて手元のディレクトリに置きました。

で、次のようなRubyスクリプトを書きます。

require 'test/unit'
require 'appium_lib'

class SimpleTest < Test::Unit::TestCase
    def setup                 
        desired_caps = {
            caps: {
                platformName: 'android',
                deviceName: 'device',
                app: '/root/tmp/ApiDemos-debug.apk',
                appActivity: '.ApiDemos',
                appPackage: 'io.appium.android.apis', 
                takesScreenshot: false,
            },
            appium_lib: {
                server_url: 'http://localhost:4723/wd/hub'
            }
        }

        driver = Appium::Driver.new(desired_caps, true)
        Appium.promote_appium_methods self.class
        driver.start_driver.manage.timeouts.implicit_wait = 20
    end
    
    def teardown
        driver_quit
    end

    def test_sample
        puts "hello"
    end
end

これでさくっと動いてしまいました。いやーすばらしい。

f:id:naruoga:20180713232604p:plain

今のところテスト本体は空っぽなので、単にアプリ起動できたところまでしか確認できてませんけど。

これから、テストちょろちょろ書いていこうと思います。今回は 'test/unit' 使ってるけど、このテストフレームワークがいいよ! という推薦があれば教えていただきたいです。かなり昔に教えてもらったTurnipが気になってますが……。

まあともかく、docker-androidおすすめです。あとLinux使うならAppImage版Appium Desktopもチョー推薦です*10

以下おまけあり。読みたい方は「続きを読む」をクリックしてください。

*1:自動テストがprofessionであって、自動がつかないテストについては不勉強の至りです……。

*2:高田馬場ゲーセンミカドの動画がお気に入りです。

*3:Selenideいいですよねえ。機能も実装も素敵。もしJavaで素のWebDriver使って苦労してるならぜひ試してみましょう。

*4:言語系パッケージシステムのライフタイムと、Linuxディストリビューションのそれとは大きく違うのでそれはしょうがないですよね。

*5:というか、待ちきれなくて寝てしまいました。うちはあんまりネットワーク太くないので……。

*6:公式サイト参照。

*7:AppiumのRubyサンプルコード から拝借。

*8:こいつの意味は続きがあればそこで書くかも。さしあたりは公式読んでください。

*9:この活動の一環として将来は作ってみたいなとは思ってますけど……いつになるかは不明。

*10:というか一般にAppImageは便利。LibreOfficeとかでも。

続きを読む

【執筆報告】うぶんちゅ!まがじん ざっぱ〜ん♪ vol.8(ゲストページ)

ちょっと出遅れてしまいましたが、うぶまが*1の元執筆陣など豪華なメンツが書かれている同人誌「うぶんちゅ! まがじん ざっぱ〜ん♪」の最新号、vol.8のゲストページに記事を書かせてもらいました。

私が書いた内容は「国際イベントの招致を手伝ってみましたよ」ということで、openSUSE.Asia Summit 2017 Tokyoの舞台裏的な話。数百人規模の人員が集まってスポンサーがたくさんつく言語系カンファレンスについてだとけっこう巷に情報ありますけど、完全手弁当で小さいけど国際イベントってノウハウそんなに表に出てない気がして、そういうのまとめる場を提供してくださったTeam ZPNのいくやさんほか皆様には感謝感謝です。

私のことはおいておいても、よかぜさんのバイオニックで生物で白衣なビーパーおねえさんの表紙も素敵ですし、面白い記事が満載で、目次を引き写すと:

  • 表紙: よかぜ
  • Ubuntuではじめる楽しいゼミ運営: おしえたかし
  • ポメラDM200にUbuntuをインストールする: 柴田充也
  • Boomagaを使ってPDFを小冊子印刷する方法: あわしろいくや
  • NanoPi NEOで作成するテレビ視聴環境: ryunuda
  • いつでも始められるmpv: kazken3
  • らくごうさんちのノートPC事情: Rakugou
  • Ubuntuで心理学実験: はにゅう
  • 国際イベントの招致を手伝ってみましたよ(ゲストページ): おがさわらなるひこ
  • 技術書典4で冊子版『ざっクリわかる Ubuntu 18.04 LTS 』を頒布できなかった顛末(ゲストページ): いくや

個人的な趣味嗜好としては、おしえさんのゼミ運営の話(Mattermostでゼミ内コミュニケーション、いいですね)、いくやさんのBoomagaネタが特に面白かったです。もひとついくやさんのゲストページは涙涙の内容でございました。はにゅうさんの心理学実験の記事も、自分とはちょっと違う世界の話でよかったです*2

捨て記事なしの内容でこれが700円は安いと思うんだな。ということで、みなさまぜひに。購入サイト:Gumroad BOOTH

*1:リンク先がさびしい……。

*2:まったくの余談ですが、先日なぜだか高校生の甥っ子の進路相談などを受けまして。理系文系どっちのクラスに進むか悩んでる、興味があるのは心理学、って話を聞いて、今の心理学は数学できないとダメらしいよ、とこの記事を読んだ知識で吹き込んだりしました。そういう意味で役に?立ちました。

【執筆報告】日経Linux 2018年7月号 & 日経xTECH LibreOffice Kaigiレポート

たまには執筆報告など。報告がたまというわけじゃなくて、執筆のお話がそんなにあるわけじゃない(手持ちのコマ少ないですからね、わたくし……)ってことです。

日経Linux 2018年7月号にちろっと1ページ、LibreOffice 6.0のレポート記事を書きました。

何度も何度も何度も同じこと書きますがLibreOffice 3系とか4系とか5系とか6系ってバージョンはなくて、6.0でメジャーバージョンなんですよね。で、なんで5.4から6.0になったの?というと、はっきりとブランディングですよと断言してしまいました。LOOLとかもそうだししばらくご無沙汰なモバイル版とかもそうだけど、これからいろんな取り組みしてくからよろしくってことですね。

で、超豪華付録「Ubuntu 18.04 LTS 日本語 Remix 使い方が全部分かる本」にも、ありがたーーーーいことにお声がけいただきまして、ドライバーレス印刷についての記事を加筆修正して再録していただきました。前に書いたときに書きすぎて盛大にボツになった内容も、これを機に復活することができました。

記事にも書いたとおり18.04 LTSからドライバーレス印刷で自動生成されるPPDが言語設定を反映するようになったのですが、これが盛大にバグっており、バグレポしたんですけど見事にスルーされておるな……ふむ。Upstreamにレポートしたほうがいいのかなあ。

私の記事はともかくめちゃくちゃ力の入った別冊なのでUbuntuユーザーは買って損はないです。Ubuntuユーザーじゃない人も買いましょう。

ついでというわけではないですが、先日行われましたLibreOffice Kaigi 2018(ご参加いただいた皆様、ありがとうございます!)のレポートを日経xTECHさんに掲載いただきました。FacebookとかTwitterでは告知しましたけど。

tech.nikkeibp.co.jp

よかったら読んでくださいませ。あなたのクリックが、次のレポート掲載の助けになるのです。はい。

BrowserMob Proxyを用いて認証プロキシありの環境下でSeleniumによるChrome自動操作を行う

みなさん、認証プロキシはお好きですか?

私はもちろん嫌いです。が、まあそういう環境がまだまだ多数あるということも知っておりますし諸事情を考えるとやむを得ないこともあるのかなーとは思います。

そういうところでSeleniumによるGUI自動操作を行いたいというニーズがありまして……Google先生に聞いてみるといくつか答えが得られるのです。が、仕様変更があったり条件がちょっと違ったりとかしてうまくいかない。しばらく煮詰まっていたのですが、うまくいったのでご紹介。

結論としては:

github.com

を使ってこんなコードで良さそうです*1。事前に次のような変数は初期化されているものとします。

変数名 意味
proxyServer プロキシのサーバー名
proxyPort プロキシのポート番号
username プロキシ認証ユーザー名
password プロキシ認証パスワード
// BrowserMob Proxyにて、認証プロキシにチェーンするプロキシを作成する
// 参考:
// https://github.com/lightbody/browsermob-proxy/blob/master/browsermob-core/src/test/groovy/net/lightbody/bmp/proxy/ChainedProxyAuthTest.groovy
BrowserMobProxy bmp = new BrowserMobProxyServer();
// Don't use InetSocketAddress.unresolved(), use new InetSocketAddress instead
bmp.setChainedProxy(new InetSocketAddress(proxyServer, proxyPort));
bmp.chainedProxyAuthorization(username, password, AuthType.BASIC);
bmp.setTrustAllServers(true);
bmp.start();

// 動作しているプロキシをSeleniumのProxyクラスに変換して登録
Proxy proxy = ClientUtil.createSeleniumProxy(bmp);
proxy.setNoProxy("localhost"); // Proxy除外設定もかける

DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability(CapabilityType.PROXY, proxy);

System.setProperty("webdriver.chrome.driver", "./driver/linux/chromedriver");
WebDriver driver = new ChromeDriver(cap); // 古いスタイルだというのは知っております……。

driver.get("http://www.google.com"); // サンプル

// ここにいろんな操作を書く

driver.quit();
bmp.stop();

探し方が良くないのかもしれないのですがBrowserMob ProxyのEmbeddedモード(Javaのコード内でライブラリとして利用する方法)がなんかいい情報がなくて、あーでもないこーでもないと試行錯誤していたのですが、コード片上にコメントで書いてあるとおり ChainedProxyAuthTest.groovy っていうズバリのテストコードがあって、それを参考にしました。

BrowserMobProxy.setChainedProxy() に渡すための InetSocketAddress をどうやって生成するかについては、BrowserMob Proxyの過去のIssueに答えがありました*2

枝葉ですが、私自身はSeleniumのラッパークラスであるSelenideを使ってるので、このときのプロキシ設定は DesiredCapabilities を使う代わりに WebDriverRunner.setProxy() すればうまくいきます。

試行錯誤の内容

  • 「自動テストスクリプトからは認証なしプロキシとして見えて、実際の認証プロキシにチェーンしてそちらに認証情報を渡す」小さなプロキシ(以下チェーンプロキシ)を立てるって方法が複数ヒットする。たしかにうまく行くのはわかるけど、いろいろあってすごくやりにくいのでこの方式は「どうしようもない場合の切り札」として検討後回し。
  • SeleniumProxy.setSocksUsername() / Proxy.setSocksPassword() を使えるって情報が複数ヒットするも、正しく動作せず。まあSocksって名前だしねえ……。もしかしたらプロキシ認証がBasic認証じゃない場合は通ったりするのかしら。
  • Chromeには --proxy-auth ってコマンドライン引数がある……という情報があったが、指定しても無視されるし、頼りのList of Chromium Command Line Switches にはそんなオプションはない。廃止された?
  • 環境変数 http_proxy で指定すれば……という意見もあったけど、今回、操作したい対象そのものはプロキシの中にあって、そこから呼ばれてるJSとかCSSが外部……という状態なので除外設定が必要。環境変数だとそういう制御ができない気がして、そっち側の調査はあまり深堀してない。
  • 手詰まりなのでSeleniumHQのSlackで聞いてみたところ、……Seleniumはそういう機能ないのでBrowserMob Proxyを使うといいよと助言をもらう。

f:id:naruoga:20180204222533p:plain

  • ふむふむと調べると……。テンパっていた中で超斜め読みして、うーんこれは結局チェーンプロキシを立てる話なのでは、と誤読して、ちゃんと調べるのは後回しにした。
  • 色々忙しくしてたら本件納期が差し迫っているのに解決のめど立ってなくてやばい。そんなわけでナナメ読みしたドキュメントを少し丁寧に読んだら、BrowserMob Proxyにはプロセスとして動作するモードとJava埋め込みできるモードがあって、後者ならプロセス別立て要らないのかも? しかも「Using with Selenium」なんて項目もあるし。ちょっと期待。
  • ざくっと調査すると次の記事がヒット。この記事のコード例は今のBrowserMob Proxyだとまったく通らない*3けど、やりたいことはできるようなので真面目に書き方を調べる。

www.softensity.com

  • ドキュメントを読んでもいまいち使い方わかんないしGoogleで探してもずばりのページはないなあ……というかJavaDocとかはないのか、と思って調べたけど、考えてみればソース読めばいいんだよね。ということで読む。

https://github.com/lightbody/browsermob-proxy/blob/master/browsermob-core/src/main/java/net/lightbody/bmp/BrowserMobProxy.java

  • というかソース読んでるぐらいならテスト見れば使い方わかるんじゃね? と思って、 src/test 以下を探したら正解!
  • 真面目に調べ始めてからコードをいじってあーでもないこーでもないってしてた時間はそんなには長くないかな。2〜3時間? 返す返すもテンパってたときにドキュメントをちゃんと読まなかったのが悔しい。
    • コード書くよりめんどくさかった作業は、検証用に手元に認証プロキシがある環境を作ることでした。結局 GitHub - sameersbn/docker-squid: Dockerfile to create a Docker container image for Squid proxy server こいつを使って、/etc/squid3/squid.conf はホストにマウントして認証設定書いて、/etc/squid3/.htpasswd はめんどくさかったのでコンテナ内部に直接作っちゃいましたが、これもホストにマウントすればよかったんだな。この話も気が向いたら書きます。

あとから考えるとBrowserMob ProxyをSeleniumから使うことについては:

定番のこの本に書いてあるので、もっと早く気づいてもよかった。BrowserMob Proxyはパフォーマンス測定とかにも使うやつなので、あんまり印象に残ってなかったんですよね(いいわけ)。

*1:このコード片はSelenium Grid非対応です。Grid化についてはBrowserMob ProxyドキュメントのUsing with Seleniumにちょろっと書いてあります。

*2:Javaの経験それほどちゃんとしてないので、こういうときにぱっと正しい書き方が浮かばないの困るんですよねえ。

*3:BrowserMob Proxyはバージョン2で大きく仕様変更したらしいです。

(メモ)Jenkins/GitLabをお試しする環境をDockerで構築する

最近、JenkinsとGitLabの連携機能とか、Jenkins Blue Oceanを試したりしています*1。 で、検証環境を手元にほしいのですが、GitLabの構築めんどくさそうだったので、Dockerだったら楽なんじゃないかなという*2。 docker-composeとかを使うところなのかもしれないですが、素朴なので手でコマンドを叩いてやってみました。

便利だったのでメモ。今更感アリアリですが。

ネットワークの作成

今回二つのコンテナを準備してそれぞれを名前解決したいわけですが、そのためにはネットワークを作るといいらしい。

参考:

qiita.com

ふむふむ、やってみましょう。

 % docker network create --driver bridge gitlab
 【ID文字列】
 % docker network inspect gitlab
[
    {
        "Name": "gitlab",
        "Id": "【ID文字列】",
        "Created": "2017-12-20T05:45:30.1592604Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

Jenkinsの起動

さっき作ったネットワーク gitlab を使って構築するようにします。コンテナ内の /var/lib/jenkins はコマンド実行時のディレクトリ直下の jenkins-master というディレクトリにマウントするようにしました。コマンドは公式ドキュメントを参照。

-name で名前つけてあげないと、コンテナ間の名前解決できないようなので。

docker run --detach -p 8080:8080 -p 50000:50000 -v `pwd`/jenkins-master:/var/jenkins_home --name jenkins --net=gitlab jenkins/jenkins:lts

GitLabの起動

こっちも公式ドキュメントを参照。

docker run --detach \
    --hostname gitlab.example.com \
    --publish 443:443 --publish 10080:80 --publish 10022:22 \
    --name gitlab \
    --restart always \
    --volume `pwd`/gitlab/config:/etc/gitlab \
    --volume `pwd`/gitlab/logs:/var/log/gitlab \
    --volume `pwd`/gitlab/data:/var/opt/gitlab \
    --net=gitlab \
    gitlab/gitlab-ce:latest

接続確認

手抜きで片方向だけ。

docker exec -it jenkins /bin/bash
jenkins@3c121fdb1b14:/$ ping gitlab
PING gitlab (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: icmp_seq=0 ttl=64 time=0.386 ms
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.122 ms
^C--- gitlab ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.122/0.254/0.386/0.132 ms
jenkins@3c121fdb1b14:/$ exit

いけてますね。

GitLabの外部名変更

http://gitlab になってればいいらしいので。

 % docker exec -it gitlab /bin/bash
root@gitlab:/# vi /etc/gitlab/gitlab.rb
(編集)
root@gitlab:/# exit
## GitLab URL
##! URL on which GitLab will be reachable.
##! For more details on configuring external_url see:
##! https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-the-external-url-for-gitlab
external_url 'http://gitlab'

こんな感じで書き換えて docker restart すればうまくいきました。

Jenkins側の名前設定

こちらはGUIでポチポチ変えるだけ。[Jenkinsの管理] > [システムの設定] > [Jenkinsの位置] にて http://jenkins:8080 にします。「リバースプロキシの設定がおかしいようです」と言われますが無視して大丈夫です。

できた!

JenkinsにGitLabプラグイン入れて簡単な設定をしてみたらちゃんと二つのコンテナ間でやりとりできているようです。

ホストマシンをうっかりリブートしてコンテナが止まっていても docker restart すればさくっと再起動するので楽です。

ただ、手元の環境だとコンテナ2個上げるとホストマシン側が目に見えて遅くなるのが少し困りどころですね。まあ、我慢できなくはないですけど。

*1:何周遅れなんだよという気が自分でもしています。

*2:何周遅れなんだよという気が自分でもしていますAGAIN。

執筆報告: 日経Linux 2018年1月号

お声がけいただきまして、日経Linux 2018年1月号 特集1「大幅刷新!始めるなら今 新しいUbuntu完全ガイド」に記事を書きました。12月8日発売。

(上のリンクはアフィなので、踏みたくない人は自分で適当に検索してくださいませ)

この特集自体は読者として読んでもとっても面白いのですが、その中の1ページ……具体的にどこかってのはこのブログをお読みのかたは想像できるのではないかな……プリンターとスキャナについてですえ、を担当させていただきましたです。

筆者の役得としては、才人揃いのUbuntu Japanese Teamの皆さんに混ぜてもらって、その原稿やらゲラやらを先行してみられるというのがあって、いやーみなさん題材の選定から技術的な誠実さから最終的な読み物としての完成度も面白さ本当にすごいなあって思います(小学生みたいな文章ですみません)。その中に交じるのはプレッシャーもありますけどとてもハッピーです。私としては。

相変わらず字数数えられないやつで盛大にはみ出たのですが、そのはみ出た部分についてはまたいずれ。具体的には、ドライバーレス印刷対応の機種だけど俺はベンダー製ドライバーを使いたいんじゃ! という人向けの記述が落ちてます。まあそこ調べが足りなかった(例えばHPLIP対応機種でどうするかとか)ので、別の機会になったほうがよかったですね。

あと、ニュース欄にopenSUSE.Asia Summit 2017 Tokyoのレポートも載ってますが、こちらの執筆もちょっと手伝いました。

ついでにもう一つ、一つ前の号にもLibreOffice 5.4についてのニュースを1ページ書いたのここでお知らせするの忘れてたので。LOOLについてもほんのちょっとですが触れました。

そんなわけで、ぜひ購入お願いします!

(小ネタ)LibreOfficeと笑顔

adventar.org

5日目*1。4日目は Arachansan さん(さんが重複)が書いてくださいましたありがたやありがたや。

今日もまた超小ネタです。

TDFのブログにて「LibreOffice Community Smiles」という連載が始まっております。コミュニティメンバーの素敵な笑顔の写真を毎日紹介するというもの。

みんないい表情!

LibreOfficeコミュニティはそんなに大きくないこともあって家族的だとぼくは思うのですが、それらしい連載だなあって思ってます。過去にTDFブログではAdvent Tipsとかアドベントカレンダー的な連載があったので、これもその一環なのかな。いろんな笑顔がみられると嬉しいですね!

明日はtokyrahさんです。よろしくお願いします!

*1:今日の夜予定があるので、ササッと書いて公開して、Adventarにリンク貼ろうとしたら、 nogajun さんが立候補していただいていました。それならそれでいいやと思ったのですがnogajunさんに気を使っていただいてずらしていただいたので。すみませんすみません。