【個人的メモ】openSUSE + LibreOffice Virtual Conferenceで何を見るか(Day1: 10/15)
表題のイベントの開催が、10/15-17と、そろそろ迫ってきました。
毎年秋にヨーロッパ圏で開催されているLibreOffice Conference:
が2020年はopenSUSEの年次カンファレンスopenSUSE Conferenceと共同開催で、openSUSEの本部があるドイツのニュルンベルク……だったはずなのですが、残念ながらCOVID-19の影響でバーチャルカンファレンスになったよというわけです。
いろいろあってそれぞれのコミュニティには顔と名前が一致する人も一方的にしかわからないけど発言気にしてみてる人もまあまあいるし、 リモートなので参加しやすいので、仕事に穴が開かない程度にできれば多くのトラックみたいなと思ってるわけです。時差つらいけど。
それで、これ気になるな、面白そうだなってプログラムをメモっておこうと思いまして。 そんな個人的なメモであっても誰かの何かの参考になるならと思って、記事にすることにしました。
書いてみたら結構長くなっちゃったので日付ごとに三分割。
なお同イベントのプログラムはこのカレンダーを参照してくださいませ。
免責事項(?)
私の立ち位置はこんな感じです。「両プロジェクトにうっすら好意を持っている他人」だと思ってください。
- LibreOffice
- プロジェクト発足から少し経ってから翻訳を手伝ったりして、あんまりリードしてない翻訳チームのリードだったりもしました
- イベントを手伝ったりコミュニティを代表するような形で登壇するようなこともしてました
- が、今現在あまりにも何もしてない(できない)自分にいやになったのが主な理由でまるっと辞めました。積極的にかかわるのも苦痛になってしまったので今は外から見ることもあまりしてません
- まだThe Document Foundationのメンバーではありますが、次の更新は多分しないと思います
- 言ってしまえば、もともとプロダクトとしてのLibreOfficeに限らずオフィスソフト自体にそんなに愛はないです
- ただ、LibreOfficeが目指す世界は私の理想と近いところがありますし、LibreOfficeがある世界の方が私には望ましいです
- 職業的ソフト屋としてはLibO/ODFを部品的に使うほうにむしろ関心が高いです
- 開発に挑戦してみたい気持ちは継続して一応持ってます。今年は初めての「意味がある」コミットもしたしね
- LibreOffice Conferenceは2012年のベルリンに参加したのが初めで、5回(あと現地に行ったけど参加できなかったのが1回)ほど参加してます。うち登壇は4回だっけか……
- なので顔と名前が一致する人たちもそこそこいて、その人たちの活動を応援したいなあとは思ってます
- openSUSE
- 実はちゃんと使ったことは一度もないです、ごめんなさい
- OSSにかかわるようになった最初期のころ(2008年~2009年ぐらい?)、openSUSEの週刊ニュースレターの翻訳手伝ったりしてました。たぶんこれが私の印刷系以外の初めてのOSSコントリビュートかな
- 私自身はUbuntuユーザーだけど日本のopenSUSEユーザーな皆様も知り合いにはそこそこいますし、まあ仲良くしてもらっていると思っていいのかな
- openSUSE.Asia summitというイベントがあって、理由はよくわからないけどグローバルチームの立ち上げメンバーだったりしました。東京開催のときにはお手伝いしたりもしましたよ
- ついでにいうと私はUbuntuも単なるデスクトップOSとしてしかほぼ使ってないので、Linux自体まったく詳しくないです
そんな中途半端な立ち位置な私によるこの記事は個人的なメモであり、何か役に立つ情報を皆様に提供しようとするものではありません*1。
「コミュニティの中の人」によるおススメを知りたければ、ぜひこのイベントへの参加をご検討ください。きっと面白いと思います!
では次から私が見るであろう、見たいなあ、ってプログラムをダラダラと書いていきます。LibreOfficeなトラックには [LibOCon]
、openSUSE Conferenceなトラックには [oSC]
というタグをつけます。時間は日本時間。
19:00-19:15 [LibOCon] Opening Session
まあオープニングですので。参加しやすい時間なのでお付き合いしましょう。15分ですし。
19:30-20:00 [LibOCon] Keynote from Collabora's Michael Meeks
LibreOfficeのサポートベンダーとして最大勢力であるCollabora Productivity(以下単にCollabora)を率いるMicheal Meeksによるキーノート。 スポンサーキーノートとはいえLibOの多くのコミットはCollaboraによるものですし彼の話は純粋に面白いので*2 これは普通に聞きたいです。
20:00-20:30 [LibOCon] State of CJK issues of LibreOffice, 2020 edition
榎さんの、毎度おなじみ、LibreOfficeのCJK問題についていろいろ説明するよって内容。これもLibOConの定番になりましたねえ。継続は力なり。すばらしい。
CJKの問題に興味がある人はQ&Aタイムで重ねて補足したりなんだりするチャンスですが、私はそういうのもうしんどいので隅っこでおとなしく聞いてますw
20:30-21:00 [oSC]Podman on Kubernetes Cluster Production Grade
裏番組の「高等教育用のLinuxディストロってどうなん需要あるん?」みたいな話もプチ気になりつつもお仕事的はこっち。
21:30-22:00 [LibOCon] Introduction of Libre Office and ODF in Aizuwakamatsu City
会津若松市の目黒さんによる会津若松市のOOo/LibO導入についてのプレゼン。 この話を世界でちゃんと発信できるというのはむちゃくちゃ有意義だと思うのです。 日本の事例は過去に私とか榎さんが小出しに紹介したことはあっても、 1セッション割かれるのはほぼ初めてなので*3。
内容は、正直な話、私にとって新しい話が出てくるとはそんなに思ってないんですが、質疑応答でみんながどんなことを聞いてくるのか気になるので、これは聞かなきゃですかね。 当然日本からの参加者いっぱいいるだろうしSNSとかで共有される気もしますけど、そこはほら、ライブ感ってのは大事なので。 裏番組のAsh氏のLOOLのサイドバーの実装の話も面白そうなんだけどね……。
22:00-22:30 [oSC] Monitoring and managing Containers using Open Source tools
これもお仕事的に。正直明るくない分野なのでぼーっと聞くだけになりそうではあるけど。って、ビデオついてるからこれ見ればいいのか……?w
裏番組の「Open Source Project Governance and Management Practices」ってのも少し気になったけど登壇者情報がカラだとか内容が一般的過ぎて具体性が全然ないとか微妙なので、まあこっちかなと。
22:30-22:45 [LibOCon] Bringing the Notebookbar to Online
単純にLOOLのUI関係の実装は聞いてて知的好奇心をくすぐられるので……。
23:00-23:30 [LibOCon] Implementing Vulkan-capable drawing using the Skia library
LibOのプラットフォーム共通ウィジェット描画ライブラリVCL(Visual Class Library)を新しいプラットフォームSkia/Vulkanで実装したよという話。 これはLibOの実装的にはかなり大きなトピックなんだけど私あんまり把握できてないので*4、まあ、聞いておきますかと。
これがState of the Project の裏番かーそうですかー。まあ、こっちは後でビデオで追いかければいいか……。
23:30-24:00 [oSC] Keynote from SUSE's Markus Noga
SUSEによるスポンサーKeynote。 すごい聞きたいわけじゃないけど(失礼)、スポンサー様のセッションのPVは回した方がいいのかなって。ただ、休憩タイムに充てちゃう可能性は多分にあります。
24:00-24:30 [LibOCon] ODF state of the union - ODF 1.3 ante portas 15:00
ODF標準化についてのあれこれ(だと思われる)。 ODF 1.3は2020年末にOASISの委員会標準になって、今年ISO化を目指すって話だったと思うけどCOVID-19の影響はあるんでしょうか(知らない)。
24:30-25:00 [LibOCon] Making Online trivial to setup 15:50 UTC
小規模環境におけるLOOLっつかCollabora Onlineのインストールを超簡単にしたよ、その技術解説するよって内容ですね。そろそろおねむの時間だけど、これは聞きたいなあ……がんばろう。
お仕事に影響がない範囲だとこの程度かなあ。この日はそれ以外にここら辺が気になるけど、さすがに参加できないです。
- Evaluation of new tooling and web applications for LibreOffice contributors 17:00 UTC = 26:00 JST
- LibOの貢献者向けWebインフラについてのディスカッション。 コミュニティメンバーとして活動してた、例えば去年なら仕事休んででも参加してたと思うけど、 今は自分のわがままで(特にローカルの)コミュニティと距離を置いているので、参加しても意味がある意見を言えないというのはあります。
- LibreOffice oss-fuzz, crashtesting, coverity 17:30 UTC = 26:30 JST
- この話去年のカンファレンスでもあって、本業的にも面白かったのでむっちゃ聞きたい! けど、次の日使い物にならなくなりそうだしなあ……ビデオで追いかけるかなあ……
- The ODF TC GitHub 18:00 UTC = 27:00 JST
- ODFの標準化関係のツールについて。Svanteの話面白いですしね。しかしさすがに……むむむ
……初日だけなのにクソ長いエントリになっちゃったのでいったん切って次行きます。
短期集中連載? LibreOfficeをWindowsで開発してみよう:補足その②パッチの提出 and more...
GWの間にLibO開発できる環境をWindowsで作ろうの連載をやりました。
そして、修正パッチ作って投げたのでその気づいた点を書いてたら長くなったので分割したのが:
この記事はその続きで、
- ユニットテストをどう書いてどう実行するか
- パッチをどうやって送るか
- ヘルプの更新の仕方
のうち 2. と、3. をほんのちょっと……です。
2. パッチをどうやって送るか
こいつについては例によって公式にとても丁寧に説明があるのでそれに従えばいいです。
LibreOfficeのソースコードは、コードレビューシステム Gerrit で管理されてます。
https://gerrit.libreoffice.org/:embed:site
Gerritの設定についてのドキュメントはこちら。
まずはGerritにアカウント作るところからですが、私大昔にアカウントだけは作ってあったのでそこは省略。アカウント設定で「ユーザー名」を確認、それとSSH鍵も登録しておきます。
そしたらあとは簡単で、 ./logerrit setup
すればよいはず……だったんですが、なんか私はうまくいかなくて (~/.ssh/confg
が正しく更新されなくて)、手で config 書いたらテスト通りました。
そしたら次はパッチの提出です。ドキュメントはこちら。
やることは、masterから分岐して変更コミットを持つブランチにて、
./logerrit submit master
ってするだけです。 前回の記事にもちろっと書きましたがCIこけたりして再度コミットやり直したりしたのですが、 そのときはamendまたはrebaseでコミット改変すればOK。コミットコメント見ると:
Change-Id: ???????056191
みたいなのがついてますが、Gerrit上の変更はこいつが維持されると反映されるみたい。
で、提出してJenkins通ったのち。 どうも自信がなかったのですが、たとえばコード修正して、その修正に対応したテストケース書いて、みたいな変更のとき、 コミットは分割するものかそれとも一つにまとめるものか悩ましかったのです。 ただ、ほかの人のコミットを見るとあんまり分割されてなさそうなので、えいっとrebaseで一つにしちゃいました。 このときは最後のコミットの Change-Id を残せばいいみたいですね。
こうやって再提出するときも:
./logerrit submit master
するだけです。簡単ですね。
それから、「こういう書き方でいいのかちょっと見てくれる?」みたいなときに、
Work In Progressなままあげるって機能もあって、その場合は ./logerrit submit-wip master
とすればいいですよと。
WIPで上げた変更をちゃんとした変更に昇格する方法もあるのかもしれないですが、 私は、この変更とは別に別にsubmitしちゃって、WIPのほうはabondon(取り下げ)しちゃったので、 よくわからないんですよね。 その点は各自適当にアレしてくださいませ。
3. ヘルプの更新の仕方
さてさて。
今はレビュー待ちでドキドキしてるところですが、それで終わりではありません。
今回は、仕様変更したのですが、この仕様はヘルプにも記述がありまして:
こいつも直さないといけないじゃないですか。
で、ヘルプ入りでビルドしないとだめなのかなー、と、
./autogen.sh
の実行時オプションに --with-help
を指定したんですけど、
今の時点では、これはいらんかったのではと思ってます。
というのは、LibOのソースツリーにおいてヘルプは helpcontent2
という submodule になってまして、
submoduleなので、このツリー上で変更したところでコミットするすべがないし、
Gerritにおけるパッチ管理も別。
いや、
ここにあるやりかたをすればいけるのかもしれないですが、
なにせ --with-help
するとビルド時間がめちゃくちゃ伸びるのです。
だったら、別のツリーとしてcloneして、そっちで作業した方がいいんじゃないか……? というのが、 今のところ思ってるところです。
最後に小ネタ: ./autogen.input
書こう
短期集中連載の、たとえば第1回とか第3回とかで、./autogen.sh
に引数こんなふうに渡して実行してました。
./autogen.sh \ --with-lang=ALL \ --enable-64-bit \ --with-jdk-home=/cygdrive/c/Program\ Files/AdoptOpenJDK/jdk-8.0.252.09-hotspot/ \ --enable-debug
それより、同じディレクトリに autogen.input
ってテキストファイルを転がしておく方がベターです。こんな感じ。
--with-lang=ja en-US ko zh-CN zh-TW --enable-64-bit --with-jdk-home=/cygdrive/c/Program\ Files/AdoptOpenJDK/jdk-8.0.252.09-hotspot/ --enable-debug
このファイルがあれば、 ./autogen.sh
と引数なしで実行したとき、ファイルに記載したパラメータありで実行されます。
autogen.input
の書き方はみたまんまなのですが一点だけ注意、--with-lang
みたいに複数のパラメータを取るとき、
コマンドラインで渡すときは ""
でクォートしますが、
autogen.input
の場合はクォートするとエラーになります。
直前に実行したautogenの引数は autogen.lastrun
ってファイルに保存されてるので、
こいつをもとに作るのがいいかもですね。
そんなわけで開発チャレンジはまだ始まったばかりですが、 この記事が、自分も開発やってみよう! ビルドするだけじゃなくてバグ直したり開発したりしてみよう! と思う人の参考になればいいなと思います。
LibreOffice Asia Conference 2019: LibreOffice CJK Bugs, Fixes, and Stories
(先日も紹介しましたけど)去年のLibreOffice Asia Conference 2019でMarkが言ってたように、 CJKの問題は非CJKな民が正しい動作を理解し修正することがとても難しいので、 我々自身で直せるものは直していきたいですよね。
求む! 同志!
短期集中連載? LibreOfficeをWindowsで開発してみよう:補足その①ユニットテストについて
GWの間にLibO開発できる環境をWindowsで作ろうの連載をやりましたが、あれからようやっと修正パッチ投げるところまでやりましたので、その中で気づいたことなど。
なお再度お断りですが、この一連の記事はLibreOfficeの開発について解説しようというものではないです。
というのは、解説記事をかけるほど自分詳しくないってことと、 LibreOfficeのように開発が活発なプロジェクトにおいて、 開発情報は将来において変わりうるので解説の寿命がそんなに長くないってことです*1。
あくまでも、Wikiにある公式情報:
を参照しつつ、私の記事は、 あーなるほどこんなところで引っかかったりするのかーみたいな一種のドキュメンタリーとして楽しんでいただけたら。
あともう一つ、第5回で、 問題のどこを直せばいいかというのはわかったつもりだけど、 どう直せばいいのか(仕様変更すべきなのか)がわかってないみたいに書きました。 それについては、メーリングリストに質問投げまして、 仕様変更になるかもだけど直した方がよかろうということに賛同いただきまして決着。 よかったよかった。
さてさて。前置き長くてすみません。本題。
実際に開発を進めていくにあたって、以下3点少し悩んだので。
- ユニットテストをどう書いてどう実行するか
- パッチをどうやって送るか
- ヘルプの更新の仕方
と、書いてたらむちゃくちゃ長くなったので、この記事はまずは①だけについて。②③は別記事にします。
1. ユニットテストをどう書いてどう実行するか
LibreOfficeのような、日々膨大な変更があって*2 リリース頻度も高いソフトウェアには、自動テストが欠かせません。
ロジックを何らか変えたら、 当然、テストを実行してリグレッション*3がないかどうかを確認し、 場合によっては、新たに実装したロジックが適切に動作するかどうかのテストを書かなくてはいけません。
LibreOfficeには自動テストのしくみがいくつかありますが、基本となるのはC++なロジックをC++なテストコードで確認するユニットテスト。 例によって公式Wikiに記載があります。
さて。「どう書いて」については、この記事ではお伝えできる情報あんまり情報がないです……。 今回のように既存のロジックを変えましたよという場合、そのロジックに関するテストを探して、 必要ならそいつに書き足す……ってな感じでしょうね。
で、前回同様「DBNum」でプロジェクト丸ごと検索かけて、今回は関係しそうなテストは二つ。
一つは sc/qa/unit/subsequent_export-test.cxx
の以下の部分:
void ScExportTest::testNatNumInNumberFormatXLSX() { ScDocShellRef xDocSh = loadDoc("tdf79398_NatNum5.", FORMAT_ODS); CPPUNIT_ASSERT( xDocSh.is() ); xDocSh = saveAndReload( &(*xDocSh), FORMAT_XLSX); // Convert [NatNum5] to [DBNum2] in Chinese CPPUNIT_ASSERT( xDocSh.is() ); xmlDocUniquePtr pDoc = XPathHelper::parseExport2(*this, *xDocSh, m_xSFactory, "xl/styles.xml", FORMAT_XLSX); CPPUNIT_ASSERT(pDoc); assertXPath(pDoc, "/x:styleSheet/x:numFmts/x:numFmt[3]", "formatCode", "[DBNum2][$-804]General;[RED][DBNum2][$-804]General"); xDocSh->DoClose(); }
こいつは:
- 名前の通りエクスポートのときに NatNum -> DBNum の変換がちゃんとおこわなれるかのテストで
- あらかじめ用意したODSファイルをXLSX形式で保存しなおして
- 出てる内容のXPathで正しさを確認する
ってものなのですけど…… うーん、データファイル作るの少し面倒だし、 XPathの書き方もよくわかってないので*4 こいつはいったん置きます。
もう一つは、 svl/qa/unit/svl.cxx
の以下のコード。
void Test::testUserDefinedNumberFormats() { ... { // tdf#79399 tdf#101462 Native Number Formats sCode = "[NatNum5][$-0404]General\\ "; // Chinese upper case number characters for 120 sExpected = u"\u58F9\u4F70\u8CB3\u62FE "; checkPreviewString(aFormatter, sCode, 120, eLang, sExpected); sCode = "[DBNum2][$-0404]General\\ "; checkPreviewString(aFormatter, sCode, 120, eLang, sExpected); ...
こいつはセルの書式画面にて書式コードを手で入力するときの「プレビュー」をもとに、 書式が期待通りに処理されるかということを確認。お、これはわかりやすいですね。
もうちょっと読んでみますと、書式指定文字列らしい [NatNum5][$-0404]General\\
、
この [$-0404]
ってなんじゃろ……と思って調べたら、
ヘルプ によると、
include/lang.h
にある:
#define LANGUAGE_CHINESE_TRADITIONAL LanguageType(0x0404) ... #define LANGUAGE_JAPANESE LanguageType(0x0411) ... #define LANGUAGE_KOREAN LanguageType(0x0412)
みたいですね。 今回の場合、 セル内の言語によって結果が変わることをテストしないといけないのでこれは大変に都合がよろしい。
で、 sExpected = u"\u58F9\u4F70\u8CB3\u62FE ";
ですが、
これは適当なツール*5 UTF-16 デコードすると 壹佰貳拾
となって、
あーなるほど、checkPreviewString()
の第3引数に渡してるやつの NatNum5 = DBNum2 の期待値なのですね。
ということでこのロジックはままコピれるみたいなので、 別個こんな感じでまとめました。ちょっと長いけど。
{ // tdf#130193 tdf#130140 Native Number Formats mapping for Chinese (Traditonal), Japanese, Korean // -- Traditional Chinese: DBNum1 -> NatNum4, DBNum2 -> NatNum5, DBnum3 -> NatNum6 // DBNum1 -> NatNum4: Chinese lower case text for 123456789 // 一億二千三百四十五萬六千七百八十九 sExpected = u"\u4e00\u5104\u4e8c\u5343\u4e09\u767e\u56db\u5341\u4e94\u842c\u516d\u5343" u"\u4e03\u767e\u516b\u5341\u4e5d "; sCode = "[NatNum4][$-0404]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); sCode = "[DBNum1][$-0404]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); // DBNum2 -> NatNum5: Chinese upper case text // 壹億貳仟參佰肆拾伍萬陸仟柒佰捌拾玖 sExpected = u"\u58f9\u5104\u8cb3\u4edf\u53c3\u4f70\u8086\u62fe\u4f0d\u842c\u9678\u4edf" u"\u67d2\u4f70\u634c\u62fe\u7396 "; sCode = "[NatNum5][$-0404]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); sCode = "[DBNum2][$-0404]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); // DBNum3 -> NatNum6: fullwidth text // 1億2千3百4十5万6千7百8十9 sExpected = u"\uff11\u5104\uff12\u5343\uff13\u767e\uff14\u5341\uff15\u842c\uff16\u5343" u"\uff17\u767e\uff18\u5341\uff19 "; sCode = "[NatNum6][$-0404]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); sCode = "[DBNum3][$-0404]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); // -- Japanese: DBNum1 -> NatNum4, DBNum2 -> NatNum5, DBnum3 -> NatNum3 // DBNum1 -> NatNum4: Japanese modern long Kanji text for 123456789 // 一億二千三百四十五万六千七百八十九 sExpected = u"\u4e00\u5104\u4e8c\u5343\u4e09\u767e\u56db\u5341\u4e94\u4e07\u516d\u5343" u"\u4e03\u767e\u516b\u5341\u4e5d "; sCode = "[NatNum4][$-0411]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); sCode = "[DBNum1][$-0411]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); // DBNum2 -> NatNum5: traditional long Kanji text // 壱億弐阡参百四拾伍萬六阡七百八拾九 sExpected = u"\u58f1\u5104\u5f10\u9621\u53c2\u767e\u56db\u62fe\u4f0d\u842c\u516d\u9621" u"\u4e03\u767e\u516b\u62fe\u4e5d "; sCode = "[NatNum5][$-0411]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); sCode = "[DBNum2][$-0411]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); // DBNum3 -> NatNum3: fullwidth Arabic digits // 123456789 sExpected = u"\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19 "; sCode = "[NatNum3][$-0411]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); sCode = "[DBNum3][$-0411]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); // -- Korean: DBNum1 -> NatNum1, DBNum2 -> NatNum2, DBNum3 -> NatNum4, DBNum4 -> NatNum9 // DBNum1 -> NatNum1: Korean lower case characters // 一二三四五六七八九 sExpected = u"\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d "; sCode = "[NatNum1][$-0412]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); sCode = "[DBNum1][$-0412]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); // DBNum2 -> NatNum2: Korean upper case characters // 壹貳參四伍六七八九 sExpected = u"\u58f9\u8cb3\u53c3\u56db\u4f0d\u516d\u4e03\u516b\u4e5d "; sCode = "[NatNum2][$-0412]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); sCode = "[DBNum2][$-0412]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); // DBNum3 -> NatNum3: fullwidth Arabic digits // 123456789 sExpected = u"\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19 "; sCode = "[NatNum3][$-0412]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); sCode = "[DBNum3][$-0412]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); // DBNum4 -> NatNum9: Hangul characters // 일이삼사오육칠팔구 sExpected = u"\uc77c\uc774\uc0bc\uc0ac\uc624\uc721\uce60\ud314\uad6c "; sCode = "[NatNum9][$-0412]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); sCode = "[DBNum4][$-0412]General\\ "; checkPreviewString(aFormatter, sCode, 123456789, eLang, sExpected); }
さて、実行について。
さきのページにもありました通り、全部のテストを実行するには、
make check
するだけ。このときウィルスチェックがONだと失敗することがあるのでOFFっとくのがいいみたいです*6。
ただ、LibOのユニットテストはとても膨大なので、毎度毎度全部のテストを流すのはホネが折れます。 なので狙ったテストだけ流す方法もあります。
make CppunitTest_svl_qa_cppunit CPPUNIT_TEST_NAME="testUserDefinedNumberFormats"
たとえばこんな感じ。
今回書いたテストは svl/qa/unit/svl.cxx
以下にあるので、makeのターゲットは "svl_qa" となるというわけですね。
……いや、正直にいうと、たぶん ls svl/CppunitTest*.mk
してそれっぽいものを探しただけな気がします。
なお、事前にモジュールがあるフォルダーに cd しておくと、ちょっとだけテストの起動が早くなりますね。
で、失敗したとき。このときもとてもよくできてまして、失敗するとこんな感じのメッセージが出ます。
C:/cygwin/home/naruhiko/lode/dev/core/svl/qa/unit/svl.cxx:437:`anonymous namespace'::Test::testUserDefinedNumberFormats equality assertion failed - Expected: 一億二千三百四十五萬六千七百八十九 - Actual : 一千二百三十四萬五千六百七十八 `anonymous namespace'::Test::testUserDefinedNumberFormats finished in: 736ms C:/cygwin/home/naruhiko/lode/dev/core/svl/qa/unit/svl.cxx(437) : error : Assertion Test name: `anonymous namespace'::Test::testUserDefinedNumberFormats equality assertion failed - Expected: 一億二千三百四十五萬六千七百八十九 - Actual : 一千二百三十四萬五千六百七十八 Failures !!! Run: 1 Failure total: 1 Failures: 1 Errors: 0 warn:unotools.config:1836:23384:unotools/source/config/configmgr.cxx:140: ConfigManager not empty Error: a unit test failed, please do one of: make CppunitTest_svl_qa_cppunit CPPUNITTRACE=TRUE # which is a shortcut for the following line make CppunitTest_svl_qa_cppunit CPPUNITTRACE="'C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/Common7/IDE/devenv.exe' /debugexe" # for interactive debugging in Visual Studio make CppunitTest_svl_qa_cppunit CPPUNITTRACE="drmemory -free_max_frames 20" # for memory checking (install Dr.Memory first, and put it to your PATH) You can limit the execution to just one particular test by: make CppunitTest_svl_qa_cppunit CPPUNIT_TEST_NAME="testXYZ" ...above mentioned params...
そう、ここに書いてある通り、
make CppunitTest_svl_qa_cppunit CPPUNITTRACE=TRUE
ってやると、Visual Studioが立ち上がって、この中でユニットテスト(と、もちろん、その中で呼び出されるLibOのコード)をデバッグできるんですね。 当然 ‘CPPUNIT_TEST_NAME` との併用も可能です。
これで、新規に作ったテストがちゃんと通るようになったら、あらためてユニットテストもgitにコミットして。
コミットしたコードで正しくテストが全部通るかどうか、 make check
をもう一度やっておきましょう。
わたくしはこの工程をさぼったため、先に示した svl/qa/unit/svl.cxx
のテストの実行がCIでfailしてあわわわわ……ってなりました。恥ずかしい*7。
さてさて長くなりました。gitにコミットした内容をもとに、いよいよパッチの提出……は、次の記事にて。
*1:同様の理由で、 公式Wikiの開発情報のページ翻訳するの昔は抵抗があるんですよね……。 Readmeなんかで使ってるMediaWikiの翻訳プラグイン適用してくれないかなー。 そしたら原文更新されたパラグラフは英語になるので、うっかり古い情報を提供せずに済むので。
*2:プロジェクトの日々を知ることができるサイト https://dashboard.documentfoundation.org/ によれば一日当たりだいたい300弱のコミットがあるらしいですね。
*3:回帰ともいう。つまり、変更によって過去に動いてた機能が動かなくなったなど。
*4:今この記事を書くために再度読み直したらそんなに大変じゃないかも……。 たぶん [$-804] がExcel用の言語コードなので、生成されたXLSXをunzipして中のXML覗いて、これだけ直してあげればよさそう。 それで日本語・韓国語のテスト用ODSを作ってあげさえすれば。 レビューで指摘もらったら対応するかも。
*6:わたくしの場合はこのとき、masterからとってきただけのソースでも特定のテストがfailしました……この場合正しくは「どうなってるの?」とメーリングリストなりなんなりで聞くべきなのですが、わたくしはとりあえず無視で先に進みました……よくない。
*7:自分でテスト実行した後、手作業でちょっとだけ直してコミットしたコードに誤りがあったのです。
【野良翻訳】ミュンヘン市、「Public Money, Public Code!」にコミット
Free Software Foundatoin Eurpoe (FSFE)のブログ:
の野良翻訳です。
ミュンヘン市は新たな連立合意で「Public Money? Public Code!」(公金は公的コードへ)原則にコミット。FSFEは新市政におけるこの決定を歓迎し、実現の進捗を緊密に監視します。
ミュンヘン市のSPD*1 および緑の党は、3月の地方選を受けて、先の日曜日に連立協定に合意しました。 この中には、フリーソフトウェアの利用に対するポジティブな声明が含まれています:将来において「Public Money? Public Code!」原則が適用されるべきとのものです。 ミュンヘン市はこうしてFSFEからの要求に加わりました。
「FSFEはミュンヘン市政による「Public Money? Public Code!」ポリシーを歓迎します。 先のSPDとCSU*2による市政は、 それ以前の革新的なフリーソフトウェア戦略から距離を置いていましたが、今や再びポジティブなシグナルが灯りました。 政府組織が「Public Money? Public Code!」原則に従うことは、ほかの公的団体との共同作業に利益となり、特定のベンダーからの独立を保ち、税金を節約できる可能性があり、イノベーションを進め、ITセキュリティのより良い基盤となります。」 と、Free Software Foundation Europe議長、 Matthias Kirschnerは述べました。
2014年、SPDはCSUとの連立合意に加わり、Dieter Reiter (SPD) が新しいミュンヘン市長として当選しました。 ミュンヘン市は、独立したフリーソフトウェアとGNU/Linuxオペレーティングしシステムに基づくITインフラストラクチャを開発する、 「LiMux」戦略を放棄し、プロプライエタリなソフトウェアへの依存への回帰を始めました。Free Software Foundatoinはこの「再移行」を過去に批判しました。 今、SPDと緑の党による新たな合意によって、ミュンヘン市は彼らによる「Public Money? Public Code!」へのコミットメントに戻ろうとしているように見えます。 依然として、協定は、たとえば個人情報や機密情報が含まれていないソフトウェアに限定するなど、いくつかの典型的な抜け穴があり、改善の余地があります。 そのためFSFEは彼らの「Public Money? Public Code!」ポリシーの実施および、将来において調達手続きがどのように行われるかに対する緊密な監視を継続します。
「Public Money? Public Code!」イニシアチブは、フリーソフトウェアを、公的に投資されるソフトウェアの標準とするということを目標としています。 Free Software Foundation Europeは、180の市民団体および、27,000人の個人とともに、オープンレターに署名しました。 この署名をもとに私たちはヨーロッパの政策決定者、政府代表者に連絡を取り、公的なコードを標準とすることを説得しています。 より大きな影響を与えるために皆さんにも署名を呼び掛けています: https://publiccode.eu/
短期集中連載? LibreOfficeをWindowsで開発してみよう:その⑤ 不具合直して? みたよ
GWの間にLibO開発できる環境をWindowsで作ろうの連載5回目。さてGWやらも本日で終わり、なのでこの短期集中連載もさしあたりの最終回。
せっかく開発環境作ったのになんにも触らないのもアレなんで、適当なバグを直してみようと。ターゲットにしたのはこれ。
この不具合なんですが、平たく言うとExcelで作成した「セルの書式設定で大字(12345……を壱弐参四五……って書くやつ)を指定したセルが、LibO Calcで開くと大字にならないってものです。
Excelで大字表示ってどうやるんだろ……って調べてみると、たとえばこのサイトがヒットしたんですけど:
書式記号に [DBNum2]
って指定すればいいらしいです。
Excelの書式指定子(Modifier)、Calcでも指定できるので指定してみる……と、
ホントだ。大字にならないですね。ということでこれを追ってみることにします*1。
ソースを検索して該当部分を探す
最初はやみくもにソースを検索して該当部分を探してみましょう*2。
ソースの検索は OpenGrok でも git grep
でもよいですが、まあせっかくなのでVS2019上で検索してみることにします。
Ctrl-Shift-F を押してソリューション内検索ダイアログを開いて "DBNum2" を検索します。
見つかったのはテストコード、コメントを除くと /svl/source/numbers/zformat.cxx
だけ。名前からいってもそれっぽい。ということで中を覗いてみます。
デバッガを使いつつなんとなく眺める
パッと目に入るのは、 SvNumberformat
のコンストラクタ。
こいつもまあ相当長いメソッドなのですが、要は書式指定子の文字列をパースして [DBNum2] なら 2
を取り出して保持しておく処理っぽいですね。
あと DBNum というキーワードでなんとなくコードを眺めると:
sal_uInt8 SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, bool bDate ) sal_uInt8 SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, bool bDate )
というペアのメソッドが目につきます。なにやら内部的に DBNum と NatNum なるものを相互に読み替えているらしい。
試しにデバッガで前者にブレークポイント設定して*3 DBNum2
を設定してみたら呼ばれてますね。なるほど。
私はこんな風にブレークポイントしかけて確かにこれが見るべき処理かって確認するのよくやります。
机上で追い込むの苦手なので……。
そこで、おっと思ったのが、さっきのテストでセルの書式設定に [DBNum2]
とやったやつ。
あれを保存して再度読み込みなおすと、 [NatNum4]
という書式指定に代わってしまう。
ここでようやっと、仕様確認しようと思いつきました(遅い)。ヘルプを "DBNum2" で検索すると、このページがヒットしました。
「Displaying Numbers Using Native Characters」とあるとおり、NatNum
というのはNative Numberなんでしょうね。
LibOの書式指定のネイティブはこっち。
で、Excel(OOXML)からインポートしたり、手打ちで書式指定 DBNum2
とかした場合は、適切なNatNumに変換して内部的にはそれを使って処理する……と。なるほどね。
エクスポートするときには逆に NatNum から DBNum に書き戻すのでしょう。
さてヘルプを見ると、…… DBNum2
は NatNum4
に対応するということですね。
それは、ODSで保存して読み込み直すときの結果と符合しますね。なのでここに間違いはないと*4。
じゃあそうなると、書式指定をもとに実際の表示文字列を組み立てるところ、それが問題あるということでしょうか。 表示文字列を組み立てるところ、それって多分ですけど、普通の実装なら、 セルの内容を渡したら文字列が返ってくるメソッドを用意するんじゃないでしょうかね*5。
ということで、ソースコードをgrepして(ここはVS2019使わないんかい!) zformat.cxx
の中で戻り値が OUString
なものをgrepして、中のぞいて、あーそれっぽいと思ったのがこの二つ。
OUString SvNumberformat::impTransliterateImpl(const OUString& rStr, const SvNumberNatNum& rNum ) const { css::lang::Locale aLocale( LanguageTag( rNum.GetLang() ).getLocale() ); return GetFormatter().GetNatNum()->getNativeNumberStringParams(rStr, aLocale, rNum.GetNatNum(), rNum.GetParams()); } void SvNumberformat::impTransliterateImpl(OUStringBuffer& rStr, const SvNumberNatNum& rNum ) const { css::lang::Locale aLocale( LanguageTag( rNum.GetLang() ).getLocale() ); OUString sTemp(rStr.toString()); sTemp = GetFormatter().GetNatNum()->getNativeNumberStringParams( sTemp, aLocale, rNum.GetNatNum(), rNum.GetParams()); rStr = sTemp; }
どっちも GetnativeNumberStringParams()
なるメソッドを読んでるわけですが、ここはVS2019でステップ実行でステップインして飛びますと、
最終的には i18npool/source/nativenumber/nativenumbersupplier.cxx
の NativeNumberSupplierService::getNativeNumberString()
メソッドに来るわけですね。
で、こいつをデバッグ実行しつつ追うと、
switch (nNativeNumberMode) { ... case NativeNumberMode::NATNUM4: // Text, Lower, Long number = &natnum4[langnum]; break;
という処理があって、ここで number
という変数に入ってくるのは、すでに大字ではない通常の漢数字……ふむぅ。……ん?
ここで仕様(というかヘルプ)を再度確認
はい、私のよくなかったところ。 おもむろにソースを見る前に、「解くべき問題は果たして何か(何が正しいふるまいか)」を確認する必要がありましたね。
で、ヘルプ再度確認すると、いやー間抜け:
NatNum4
は modern だって書いてあるじゃー、ないですか!
なのでヘルプの記述が仕様として正しいなら、今の動作は完全に正しい。そして、古いヘルプ:
を見ると、この動作は3.3から……というかOpenOffice.orgのころから変わっていない、と思われます。
でもおかしいですよね、Excelでは DBNum2
は大字なのだとしたら、当然LibOではそれに対応する NatNum5
じゃないと、バグ起票されたようにExcelとの互換性がないということになってしまう。うーん。わからん。
目をつぶって直す
まあいいや、もし仮にこいつ直すとしたらどうするか。
結果としては DBNumX
と NatNunX
の割り当てだけが問題ってことになったので、前述の:
sal_uInt8 SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, bool bDate ) sal_uInt8 SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, bool bDate )
この二つを直せばいいということになります。
本来ならすべてのマッピングを見直す方が適切なのかもわからないですが、さしあたりはこの問題だけ直してみます。 以下diffだけだと若干情報足りないので手で補った嘘diffです。
@@ -170,7 +170,7 @@ sal_uInt8 SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang switch ( nDBNum ) { ... case 2: if ( eLang == primary(LANGUAGE_CHINESE)) nNatNum = 5; else if ( eLang == primary(LANGUAGE_JAPANESE) ) - nNatNum = 4; + nNatNum = 5; else if ( eLang == primary(LANGUAGE_KOREAN) ) nNatNum = 2; break;
こちらは DBNum2
を NatNum4
にして、
@@ -238,7 +238,7 @@ sal_uInt8 SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLan switch ( nNatNum ) { ... case 4: if ( eLang == primary(LANGUAGE_CHINESE) ) nDBNum = 2; else if ( eLang == primary(LANGUAGE_JAPANESE) ) - nDBNum = 3; + nDBNum = 2; break; case 6: if ( eLang == primary(LANGUAGE_CHINESE) )
こちらは逆に NatNum4
を DBNum2
に戻しているだけ。あー、超簡単だ。
で、この変更を入れてビルドしたやつで、バグ報告についてたファイルを開いてみると……。
直ってますね!
もし……仮にもし、これをパッチに出すとすると、
- まずはあるべき仕様を日本コミュニティで議論(メーリングリストかな?)。
- 上記に基づき、
DBNum2
以外に対する処理も書く。 - ユニットテストでこの処理を確認しているものがあるげなので、直すなり、もしこのケースを確認してないなら追加するなりする。
- ヘルプも直す。
- コミット整えて、gerrit に push
ってな感じですかねー。
まあともかく、開発環境作ってリアルな問題を(少なくとも技術的には)解けるところまではいったので、 ゴールデンウイークとしてはまあまあの成果かな?
せっかくなので、これっきりにしないで定期的に開発にかかわっていきたいですね!
短期集中連載? LibreOfficeをWindowsで開発してみよう:その④ Visual Studio開発落穂ひろい
GWの間にLibO開発できる環境をWindowsで作ろうの連載4回目。環境作るだけじゃなくてできればバグつぶしてコミットするところまで行きたい。
今日……というか昨日か、はあんまり進んでません。 なぜならSNSなどでご覧になった方はいるかもしれませんが、開発用のノートPCのHDDをSSDに換装したら、環境が全部ふっとんじゃったからです。 それを戻すのに時間がかかってこっちの作業あんまり進められませんでした。
なのでその際に気づいたメモなどを書いてお茶を濁します。 いちおうソースコード眺め始めてはいますが、まだ目立った成果はないので……
- ディスク換装したのですが
\cygwin\
以下をまるっと古いディスクからコピーすればいいかと簡単に考えてましたがダメだったみたいです- git リポジトリでどうやってもuntracked changeがなくならない……
checkout -f
もclean
もstash
/stash drop
もダメ- しょうがないので
dev
以下捨ててlode
直下で./setup --dev --force
やり直して再ビルドしました
- VS2019ソリューションが読めない
- 言語パック切り替えるの忘れてたので English にしたら通りました
- ただこれ、言語パック忘れじゃなくて、なにか VS Installer でちゃんとインストールできてなかったものがあって、 言語パック切り替えでそれがちゃんと入ったとかなのかも
- 実は今回 workload の導入にも chocolatey 使ってみたんですけど、そいつが途中で刺さっちゃったんでアボートしたんですよね
- ビルドとおったので大丈夫かな? と思ってたのですが、大丈夫じゃなかったのかも
- デバッグ実行起動遅い話は、SSD化でだいぶ改善しました。やっぱり金の力は偉大だ
今はそんだけです。夜の報告でコードの解析結果とかお見せできたらいいな。
LibreOffice Asia Conference 2019 Tokyo 基調講演の紹介
去年行われましたLibreOffice Asia Conference 2019 Tokyo
の基調講演2本の字幕を聞き取りなおして日本語訳もつけたので、 せっかくだからもっといろんな人に見てほしいということで宣伝エントリーを書くことにしました。
言わずもがなですがわたくしの個人ブログに書いてることからお分かりの通り、 ここに書いてあることはLibreOffice日本語チーム、あるいはTDFをいかなる意味でも代表した発言ではござりませぬ。 あくまでもLibreOfficeというプロジェクト、コミュニティに好感を持つ一個人の意見としてお読みくださいませ。
さておき。動画については字幕ONにして、言語を日本語にしてご覧くださいね。
Mark Hung: LibreOffice CJK Bugs, Fixes, and Stories.
- タイトル邦訳:LibreOffice CJKのバグ、修正、そして物語。
- 発表資料(PDF): 英語 日本語
Mark Hung氏は台湾のLibreOffice開発者です。 主にLibreOffice Writerにて、を日本語で利用するには欠かせない、 アジア言語(いわゆるCJK; Chinese, Japanese, Korean)ならではの組版規則、ルビ、縦書き、BMP外のUnicode文字の扱いなど、さまざまな不具合を修正してきました。 最近ではWriterだけでなく、Impressのアニメーションの改善などにも取り組んでいます。
この講演では、なぜ彼がLibreOfficeに取り組むことになったか、 そしてどういう問題に取り組んできたかを、ストーリー仕立てで話してくれました。
Markのすごみというかは、自分の解ける範囲の問題を着実に解いて、それを意識して広げているってことです。
例えばルビの不具合、彼が直してくれたというときには、そうかー台湾でもルビ使うのかーって素朴に思ってたんですけど、 そうじゃなくて、自分が使ってないけれども領域が近い(CJKな問題)、 直せそうな問題を選んで取り組んだということをこの講演で言ってて、 なんというかそういう姿勢がすごいですよね。
LibreOfficeが持つCJKなさまざまな機能について振り返るという意味でも面白いですし、 それから、彼のLibreOfficeのストーリーのきっかけとなる、 Apache OpenOfficeで数週間放っておかれた不具合がLibOでは翌日レビューされて、 それが理由で組織がLibOを採用した……なんて話も面白いです。
あんまり弁が立つほうじゃないので、TED的なうまさはないですし地味に聞こえるかもしれないですが、 私としては、淡々とした口調であるからこそ、 なおかつ自分の活動を声高に主張しないからこその、 強さがあるなあと思いました。
彼の活動を日本に紹介したい、だから日本で講演してほしい。 それはずっと思ってきたことだったので、 とっつきの派手さがないから動画見られていない、 SNSとかでもあまり言及がない、ということなら、 それはすごいもったいないと思うのですよねー。
ので、とにかく見てほしいです。OSSへの貢献のありかたという意味でも興味深いです!
Italo Vignoli: LibreOffice, the many different faces of a global community
- タイトル邦訳:LibreOffice、グローバルコミュニティの多様な側面
- 発表資料(PDF): 英語 日本語
Italo Vignoli氏は、LibreOfficeを法的・財務的に支える非営利組織であるThe Document Foundation(以下TDF)の創立メンバーで、 マーケティング・広報担当コンサルタントとしてTDFと契約しています*1。 TDFが行っているLibreOffice認定制度を行う認定委員会の共同委員長でもあります。
LibreOfficeプロジェクト、プロダクトの説明もしていますが、それよりも、 LibreOfficeを取り巻く世界と、そこにおいてLibreOffice/TDFは何を目指して何をしてきたかという話が、 とても興味深いです。
ソフトウェアライセンスの輸出入の多寡で見る世界地図というところは実に衝撃的で、 LibreOfficeを使ってなくても、日本においてソフトウェアにかかわっている人であれば、 この話を聞くだけのためにぜひ見てほしいです。
またLibreOfficeの前身プロジェクトであるOpenOffice.orgとSun、Oracleの関係、 OpenOffice.orgが商標を譲渡したApache OpenOfficeとIBMの関係なんかも、 改めて聞くと面白いんじゃないかと。
まあItaloという人はとにかく弁が立つ人で(そういう意味ではオープニング基調講演のMarkとは対照的)、 若干あおりが入ってるところもありますが、 笑いが絶えない、funかつinterestingな講演でした。
Lothar Becker: Certified as a LibreOffice professional - a win/win/win situation for the community
※Italoの講演の続きとなります。
- タイトル邦訳:LibreOffice 専門家として認定をうけること - コミュニティにとってWin / Win / Win な状況
- 発表資料(PDF): 英語 日本語
Lothar Becker氏は、Italoと同じくTDFのLibreOffice認定委員会の共同委員長です。 OpenOffice.orgの時代から、ドイツでもっとも古い移行案件を実施し、またOpenOffice.orgの認定制度を立ち上げるなどの活動をしてきたそうです。 なお、この当時は違いますが、今はTDFの議長を勤めています。
で、この講演は、彼の実績から、LibreOfficeのビジネスとエコシステムとコミュニティ、 そして認定制度についてのものでした。
ええと、正直に申し上げます。わたくし、 Lotharの話、LibreOfficeのグローバルなカンファレンス(LibreOffice Conference、通常LibOCon)で聞いて、 いまいちピンとこなかったんですよね。 じゃっかん抽象論っぽく聞こえて。
というのは、やっぱりあれじゃないですか、 LibreOfficeへの移行を(その動機はさておき)検討した場合、 「いやそんなことできませんよ」となる理由の一つは、 専門家によるサポートが受けられないことだと思うんですよね。 で、なぜサポートできる専門家がいないかというと、 平たく言うとそれでご飯が食べられないからです。市場がないか小さいから。 これってまさに鶏と卵のジレンマですよね。 そこに対するよい答えが、ないように思ってたのです。
でも、今回書き起こしのために時間かけて聞いたら、 自分で自分に「日本市場には適用できない」って言い訳しちゃってたのかもしれないです。
うーん今のところ考えまとまってないのでうまいこと言えないですけど、 まあ自分としてもうちょっとできることあるんじゃないかな、 人のせいにしてないで、そういうことやらないとなーと思える講演ではありました。
また、LibreOfficeの認定制度についてですが、 オフィスソフトの認定制度というとMSさんのMOSとかそういうのがぱっと浮かびますが、 そういうものとは少し違うんですよね。 その点、ちゃんと説明があったのもよかったと感じました。
……ということで三つの基調講演を紹介しました。
それぞれ、少しずつベクトルが違って面白い講演だったと思います。
面白いな、と思ってくださったら、ぜひ高評価、よろしければチャンネル登録もお願いします*2!
続きを読む