たごもりすメモ

コードとかその他の話とか。

macOS Big Sur なM1 MacのEmacsでDocuments以下のファイル(など)を開く

M1 mac (macOS Big Sur)買ってからまだちゃんと開発とかに使えてなくてちょっとずつセットアップ進めてるんだけど、Emacsで ~/Documents 下とかが読めないことに気付いた。以前のバージョンで指摘されてた解法であるところの以下の方法もダメ:

  • M-x ns-open-file-using-panel で一度Documents下のファイルを開けばいける → ダメ
  • EmacsにFull Disk Access権限を与える → ダメ
  • 実は裏技で/usr/bin/rubyにFull Disk Access権限を与える → なんかファイル開くダイアログで/usr/binとかが開けなくなってない?(ダメ)

というわけで調べてたらこんなのが見付かった。

braveam.com
Can not do dired on ~/Documents when it is in iCloud on Catalina · Issue #84 · caldwell/build-emacs · GitHub

このままやるとx86_64なバイナリを起動しようとしてしまうので以下のように。
1. システム環境設定 → システムとセキュリティ → プライバシー → フルディスクアクセスをEmacs.appに与える
2. Terminalで以下のコマンドを実行、arm64なバイナリにリンクするよう注意

$ cd /Applications/Emacs.app/Contents/MacOS
$ mv Emacs Emacs.old
$ ln -s Emacs-arm64-11_2 Emacs

これでうまく動くようになった。めんどくさいですね。

Dropwizard ValidatorがListに対して正常に動かない

Kotlinが悪いのかListはそもそもダメなのか既知の問題なのかなどはまだ確認してない。

追記: この問題っぽい。JVMのオプション追加でどうにかなるケースと、いややっぱダメみたいな話もあるのかな。トップレベルにListを使わないのが結局のところいちばんよさそう。うーん。

Dropwizard Validator*1を使って、YAMLから読んだデータのバリデーションをしようと思ったんだけど、なんかどうやってもエラーが報告されなくておっかしいなーと思ってたところ、どうもトップレベルがListだと正常に動かないっぽい。
以下のようなテストコードを書いて確認できる。

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import io.dropwizard.jersey.validation.Validators
import javax.validation.Valid
import javax.validation.constraints.NotEmpty

val validator = Validators.newValidator()
val mapper = ObjectMapper(YAMLFactory()).registerKotlinModule()

data class TopLevel(
    @field:Valid val items: List<Item>
)

data class Item(
    @field:NotEmpty val data: String
)

class ValidationTest {
    @Test
    fun `validator does not report errors for top-level list`() {
        val yaml = """---
        |- data: ""
        |- data: ""
        |""".trimMargin()
        val list = mapper.readValue(yaml) as List<Item>
        assertNotEquals(emptySet(), validator.validate(list))
    }

    @Test
    fun `validator can report errors if top-level is not list`() {
        val yaml = """---
        |items:
        |  - data: ""
        |  - data: ""
        |""".trimMargin()
        val obj = mapper.readValue(yaml) as TopLevel
        assertNotEquals(emptySet(), validator.validate(obj))
    }
}

これでトップレベルがListのやつはエラーを報告せずfailし、トップレベルにdata classを置いてその子要素としてListを持たせたやつはバリデーションエラーを報告する。

f:id:tagomoris:20210209144401p:plain

条件を見付けるまでにだいぶ長いことハマってしまった。これ以上調べるかどうかはまだ決めてない。

*1:Hibernate由来の、Springとかでも使われてるやつ

DropwizardとShadow jarの話

AWS Lambda用にshadow jarをビルドしてたリポジトリで、別のデーモンプロセス*1をDropwizardベースにすることにして依存関係やビルド方法などを書き換えていったところ、設定ファイルに書かれてるLog appenderが見えない、みたいなエラーが出て起動に失敗するという状況に。手元で./gradlew runしたときはうまくいくんだけどサーバにデプロイしたらダメ。

io.dropwizard.configuration.ConfigurationParsingException: /opt/myapp/config.yaml has an error:
   * Failed to parse configuration at: logging.appenders.[0]; Could not resolve type id 'console' as a subtype of `io.dropwizard.logging.AppenderFactory<ch.qos.logback.classic.spi.ILoggingEvent>`: known type ids = [] (for POJO property 'appenders')
  at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.myapp.MyAppConfiguration["logging"]->io.dropwizard.logging.DefaultLoggingFactory["appenders"]->java.util.ArrayList[0])
         at io.dropwizard.configuration.ConfigurationParsingException$Builder.build(ConfigurationParsingException.java:278)
         at io.dropwizard.configuration.BaseConfigurationFactory.build(BaseConfigurationFactory.java:157)
...

なんかこんな感じのスタックトレースが出る。

調べてみたらDropwizardによる実装の探索とshadowが衝突しているっぽい。このへんのコメントを参考にした。
で、手元はGradleはKotlin DSLで書かれてるので、このコメントを参考にえいやとbuild.gradle.ktsに以下のようなのを追加。

import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

// ...

tasks {
    named<ShadowJar>("shadowJar") {
        archiveBaseName.set("stream-processing-shadow")
        mergeServiceFiles()
        manifest {
            attributes(mapOf("Main-Class" to application.mainClassName))
        }
    }
}

これでうまくいった。めでたしめでたし。

*1:同じリポジトリの別Main classを使う

GradleプロジェクトでArtifactoryに依存ライブラリを置くときのKotlin DSLでの記述

なんかちょっとハマってたのでメモ。要するに公式ドキュメントのをどう書くか、だけなんだけど。

Gradle Artifactory Plugin - JFrog - JFrog Documentation

結果的にはこのissue commentを読んでやった。

// build.gradle.kts
plugins {
  // ... others
  id("com.jfrog.artifactory").version("4.17.2")
}

repositories {
    mavenCentral()
    maven {
        url = uri("https://mycompany.jfrog.io/mycompany/libs-release/")
        credentials {
            username = System.getenv("MY_ARTIFACTORY_USERNAME")
            password = System.getenv("MY_ARTIFACTORY_PASSWORD")
        }
    }
}

// snip

上記Issue commentにあった認証方式としてのBasic認証の明示は結果的には必要ないっぽい。
あと関係ないけど、上記URLの "mycompany" の部分、ふたつめを "artifactory" (設定サンプルにある)から変え損ねててずっと404になって悩んでた。

コロナ禍の最中にグランツーリスモSPORTで10kg痩せた話

TL;DR

  • 2019年11月末 73.9kg → 2020年8月末現在 64.2kg になるまで痩せた
  • 原因がグランツーリスモSPORT*1しか思い付かない
  • 食事制限などは一切なし、普段からそんなに食生活が偏ってはいないと思う、が、毎晩ビールは飲んでるぞ
  • (追記) プレイ中の心拍数が100〜140くらいで、これはいい運動になってそう

経緯

身長171cmの自分も、自転車をだいぶ強烈にやっていた頃*2には58〜60kgの体脂肪率ひと桁とかだったが、9年経った2019年年始には68kgくらいまで増量していてこれはいかんと思っていたところ、2019年1月にスキーで骨折し全く動かない生活をしばらく過ごしていたら73kgぐらいまで一気に太った。これはやばい。

とはいうものの、ライフイベントがあれこれ*3あったりもして、あまり気にすることなく危機感のない生活を送っていたら2019年のうちは体重が全然変わらなかった。んで2019年11月末に体重を計ってから体重計にも近付かずふらふら暮らしていた*4ところ、3月末の時点で気付いたらズボンがぜんぶユルくて歩いてるとずり落ちてくる。全部2019年12月末に買ったもの。おかしいなと思いつつこのときにズボンをまた買い足したんだけど、そのズボンが今現在(2020年8月)ではもうウエストが余ってベルト無しにはまったく履けない。

そうなって初めてこれはもしや痩せてるのでは、と思って自宅の体重計に乗ってみたら、いきなりものすごく痩せた数字が出てきた。びびった。65.7kg (7月上旬)。その後も特に特異値というわけではなくて、継続して体重は低下し、現在では64.2kgを記録している。

原因の考察

さて何をしたかというと、何もしていない……。もちろんコロナ禍のまっただ中なので、外に出掛けたりはほとんどしていない。運動も(自転車の新車を買ったのもあって)自宅の近所を巡ったりはたまにするが、強度が低くて話にならないのは自分で分かっている。これで痩せるなら全人類にダイエットは必要ない。

と思ったのだが、唯一思い付いたものがある。グランツーリスモSPORTだ。この2017年10月発売のゲーム、PSVRの体験のためにすぐ買ってある程度やっていたもののしばらく放置していたのを、2020年2月から再開したのだった。

www.gran-turismo.com

これ、以前にやっていたものの積み重ねから、今となってはまあまあ真剣に・そこそこのレベルで競えるようになってきた。特にコロナで出掛けられなくなってからのストレス解消に毎日1〜2時間*5修練を続け、オフラインでできる範囲のものをやり終えたからしょうがなくオンライン(スポーツモード)のレースをやりはじめたのが3月20日からであった。

もちろん、これだと思ったのには理由がある。単純に、毎回プレイするたびにめちゃくちゃ汗をかく。

f:id:tagomoris:20200826135656j:plain
ハンドルコントローラのセットアップ

こんな感じのハンドルコントローラ環境でやってるんだけど、冬のうちから、とにかく汗をかく。椅子に布がかぶせてあるのは、自分があまりに汗をかくんで妻が嫌がったからという理由による。今だと1時間レースやる*6と水を1リットルは飲む。もちろんクーラーは動かしているが。

使っているのはロジクールG29。そこまで高級なモデルでもないが、フォースフィードバックがちゃんとかかり、路面の状態もわかる(と思う)。

gaming.logicool.co.jp

やっているモードにもよると思う。オンラインでのレースやっているときの疲れかた(と汗のかきかた)は、一人でタイムアタックしてるときに較べて圧倒的に激しい。周囲のクルマの動きに気を配らないといけないし、僅かなブレーキミスが衝突に繋がるし、などなどで緊張感がぜんぜん違うからだと思う。自分のDR*7が上がったことで周囲も上級者になってきて、全体としてミスの少ないレースを強いられているのもあるはず。

というやつを、最近ではほぼ休みなく毎日1時間はやっている。これではないか。というかこれ以外に思いつかない。まあ休みなくペダル踏みつけハンドル回してるからなあ。

追記: プレイ中の心拍数を計ってみた

お昼の直後ということもあるので、他の時間帯よりも心拍数は上がりにくい状態でこのくらい、だと思う。この強度の運動が着替え・機材の準備なしにできて、かつ天候も関係なしって、ダイエット用にだいぶいい運動なんじゃないのかな。すげえ。 (追記ここまで)

そのほかの生活

食生活などはほとんど変わっていない、というかそもそも痩せたのを自覚したのがだいぶ遅かったくらいだし、まったく何もしていない。

もちろんコロナな状況なので、飲み会なんかは皆無。しかし元々そんなに高頻度で飲み会に参加していた生活でもないし、今だってたまには近所の店で外食したりもする*8。自宅での夕食時にはたいていビール飲んでるし、そのあとさらに晩酌でビールや日本酒を飲んだりもする。F1のレースがある週末なんかは330ml瓶を3本空けちゃうことだってあるし、もちろんそうなるとツマミだって用意しちゃうし。

とはいえ、普段の生活から、あまり不摂生はしてなかったなとは思う。ポテチをひと袋もりもり食べるのだって月イチくらいだし*9、ラーメンも週1くらいで食べるとはいえ大盛りにしないしスープを全部飲んだりもしない*10、晩酌のツマミもそんなにハイカロリーはものはあんまり食べてないかな、くらい。

食事は朝昼晩食べている。普通にごはんもパンも食べてる。野菜を多めにしようとはしているかもしれぬ。揚げものは自宅でやるのが面倒だからあんまり食べないなー。

というわけで

みんなもグランツーリスモSPORTやってオンラインレースで楽しくカロリー消費しようぜ!

おまけ: 最近の生活環境

前にリモートワークについてのエントリを買いてから、COVID-19はそうそう簡単に収束しないなというのが見えたのと、夫婦そろってしばらくはリモートでの仕事が確定、自分の場合はCOVID-19が収まってもかなりの割合で自宅からの勤務ができそうという話が会社から出たりもして、そんなわけで自宅で仕事をする環境を整えるため、えいやで一軒家(賃貸)に引越した。GW直前から探しはじめて5月半ばにはもう決まってた、6月半ばに引越し、という感じでだいぶスピード引越し。

間取りとしては3LDKあって仕事用の書斎がひと部屋とれたので、ワイドディスプレイやオフィスチェア、電動昇降式デスクなど一式を揃えて快適に仕事ができるようになった。扉が閉まるからZoomとかやってても他への影響が小さくて良い。

f:id:tagomoris:20200824111326j:plain
書斎のワークデスク

ひとりが書斎を使うとして、もう一人も快適に仕事するためのスペースが自宅内あちこちで取れるようにしてある。特に屋上テラスと階段下ヒキコモリスペースがお気に入り。

f:id:tagomoris:20200824111327j:plain
テラスと階段下

仕事は、もちろん、だいぶやりやすくなった。自宅内を移動するだけでも気分転換にはなるし、業務中に妻との距離がある/スペースが隔離されているのは、お互いに気をつかわなくていい。あと単純にかなり広くなったので、長期間籠もっていてもストレスが溜まりにくくなったのもあると思う。

出勤頻度の激減*11を見越して駅からはちょっと歩くけど、そこまででもない、くらい。それでもまあいいお値段の家賃になったけど、これは必要経費かなあ。最初から2〜3年の様子見のあいだだけ住む、ぐらいの感覚で決めたので許容範囲ということにしている。別の場所に行くなり買うなりはその間に社会情勢を見ながら考えるつもり。 さて、どうなるんですかねー。

*1:フォースフィードバックのあるハンドルコントローラ使用

*2:毎日夜に自宅で1.5〜2.5時間くらい自転車用のトレーニングマシンに乗っていたり、ヒルクライムレースに年5,6レースくらい出ていた

*3:結婚とか……

*4:元々コロナ前ではしょっちゅう各地の温泉施設とかに行ってそこの体重計に乗ってたので自宅の体重計に乗る習慣がなかった

*5:がっつりやるときは3時間くらい

*6:典型的には20分くらいのレースx2と10分くらいのレースx1

*7:ドライバーランク、E,D,C,B,A,A+,Sがあるなかで自分は現在B

*8:もちろん夫婦のみで、あまり密な感じの店は避けるようにしている

*9:今でもやる

*10:無料のごはんもつけない

*11:激減もなにも引越し後はまだ一度も出社してないんだけど

systemdのenvfileを普通のコマンド実行時に流用する

普段はsystemd経由で実行しているコマンドをCLIから実行したい、環境変数もsystemd経由で起動するときと同様にセットしたいのでenvfile(EnvironmentFile)をそのまま使いたいんだけどなんか微妙にやりにくくないか、と思って何度か調べたことがあるんだけど、あんまりうまい方法が検索結果に出てこない。

んだけど、あれ、これ簡単じゃん。(追記: これはごく単純なケースでしか動かなかった、後段参照)

$ env $(cat myenvfile | grep -v '^#') target-command

envfileをシェルスクリプトとして実行して追加された変数をなんとかexportすれば……みたいに考えてたけどenvコマンドで一発だった。変なコメントとか入ってると厄介だけど、こんな感じでいいのでは。ということでメモ。

空白を含む値の処理

まあいいやとスルーしてたけど値が空白を含むときに上記のコマンドだと正常に動きませんね。

$ env "$(grep -v '^#' myenvfile)" target-command

こうかな。catする意味は別になかった。

空白を含む値の処理again

上の例だとぜんぜんダメだった。ファイルのほぼ全体が最初の環境変数名にセットされて終わるという悲しい結果になる。
というか色々試してるとenvコマンドが key=value ペアのparseになんか独自のルールを持っている? っぽくって、空白文字をエスケープしようと思うとぜんぜんうまくいかない。

んで同僚の@k0kubun氏とあれこれやっていたところ彼が見付けたのが set -o allexport を使うハック。それだとちょっと他への影響が出るので、サブシェル化して実行すればいい。
このときenvfileは以下のように書かれている必要がある。

VALUE_ONE=1
VALUE_TWO="value may contain spaces"

このファイルを読み込むときに set -o allexport して全てを環境変数にする。それをサブシェルの中でやって、んでコマンドを実行する。

(set -o allexport; source envfile; target-command)

できたー!

この時期、業務で低パフォーマンスを出し続ける覚悟

今この時期、もちろん弊社もCOVID-19関連の事情を鑑みてテレワーク……とはあんまり自分の回りでは言わない、リモートワーク(もっと言うとWFH: Work From Home)してる。自分が完全WFHに切り替えたのは1月半ばくらいだったかなー。もう3ヶ月ですね。

で、どうかというと、業務のパフォーマンスで見ると、自分のいまのパフォーマンスは明らかに悪い。少なくとも良くはない。それは自分でもわかってる。
でももう、これはしょうがない、と思うので、覚悟している。高パフォーマンス出せたらいいとは思うけど、同時にどう考えても無理して仕事で高パフォーマンス出すような時期でもないと思う。

だからこのエントリは、まあしょうがないよね、というのを受け入れよう、という話です。*1

なおこのエントリは業種柄、リモートワークに移行しやすい自分の話しかしていません。生活必需品や医療品関連の小売店舗や病院、窓口が必要な店舗や役所、流通関連など、その他さまざまな職種の現場でいま現在も社会を支えてくださる方々には本当に感謝しかありません。ありがとうございます。

普段の話

COVID-19以前の弊社はといえば、基本的にはオフィスに行って仕事をしましょう、というのがルールだった。うちのチームのマネージャーはユルいんでいつWFHしても全く問題ないんだけど、まあ全体的にはそう。
で、自分も性格的にオフィスで仕事する方が気持ちの切り替えができて好きなので、通常は普通にオフィスに出勤して、仕事して、帰るという感じだった。自宅でコード書くときはラップトップのディスプレイとキーボードでもまあ別にいいや、という感じ。

一方ミーティングとかは、同僚がそもそも世界中に広がってることもあって常にZoomだったので、そこは基本的に変わってない。オフィス内でも同僚と会話するけど、それは運良くその仕事に関わっている同僚が同じオフィスにいればであって、いなければZoomで話すことになる。
いっしょのタスクをやっている同僚がバンクーバー在住の人になることが多かったので、そういう人達とは定期的にZoomで話す時間を作ったりしていた。

自宅の仕事環境の話

元々オフィスで仕事する前提でいたから、自宅に腰を落ち着けて仕事する環境がなにもない。外部ディスプレイや外付けキーボードすらなかった*2。場所もいまはダイニングテーブルを主に使ってるけど、自宅がそもそも生活のことだけ考えてたから個室がなくて、家族の生活とモロに筒抜け状態になってたりする。
なんでそんな環境なのと言われると、単に自宅にその必要を感じてなかったから、以外には何も理由がない。

で、これはもちろん効率が悪い。コードを書くときに集中するのも難しいし、Zoomで会議やるにも家族への配慮がいるし、雑談したいからZoom繋ぎっぱなし、みたいなのもほとんど不可能*3。お昼ごはんのたびにディスプレイやラップトップをどかしたりするのも地味にめんどい。
そもそもZoomで繋ぐこと自体が自宅全体へのストレスになる*4というのはちょっと発見だった。これ、同僚と常に話してるみたいなマネージャー陣は大変だろうな。

社会環境の話

もちろん、COVID-19まわりの情報も気になる。Twitterのタイムラインは荒れ気味だし、Facebookでもあれこれ声高に言う人もいるし*5、TVは……まあほとんど点けないけど。ゲームとかNetflixにしか使ってないな。
で、そういうあれこれに気が散る。政治の話もあるし、海外の状況も(特に同僚が多くいる国や地域の話は)気になる。あれこれ。これも集中を失わせる大きな要因になっている。

生活習慣の話

普段自分は休日にわりと外での活動でストレス発散することが多い。サイクリング、ドライブ、キャンプ、スキー、本屋めぐり、美術館や博物館、あれやこれや。全部できなくなった。
最近はだから自宅でゲームやって、あとは電子書籍やらAmazon経由で買った本やらを読むんだけど、もちろん普段のストレス発散方法がとれないのは大きい。平日の活動にも影響を与えていると思う。

最近の意識的な活動の話

とにかく休憩を頻繁に取ろうとする、昼休憩をだいぶ長めにとる、ようにはしている。夕方も、とにかく早目に仕事を切り上げるようにはしている。
あと水分補給をすぐ忘れるので、常に湯冷ましを手元に置くようにしている。日に1リットルくらいは飲んでるけど、もうちょっと多めにしたいなあ。難しい。

最近会社が会計年度の切り替わりをズラしたりみたいなのの副作用で手持ちの有給休暇残日数がかなりあるので、これを、意識してとろうかなと思っている。今週も火曜は意味もなく休みにしてのんびりしてた。これも馬鹿にならない効果があるなと思ったところ。継続的に週の真ん中の休みを入れていこうかなと思っている。

仕事以外にやっていた活動はほぼ全滅気味。やばい。関係者の方にはマジで申し訳もない、が、今のところどうしようもない。生活ペースをもうちょっとちゃんと組み立てられればなんとかなるかもしれないが、ならないかもしれない。

結論

というわけで、短い時間を集中しにくい環境で働いていて、パフォーマンスがいいわけがない。これはもうしょうがないな、と受け入れることにした。

会社側の評価どうなるとかいう話もなくはないだろう*6けど、それとは関係なく「低パフォーマンスしか出せない自分へのストレス」みたいなものがあって、これを直視できないうちは、そのストレスが雪だるま式にふくれてる気がした。2月〜3月中旬くらい、だいぶそういうストレスを感じていた気がする。

これはたぶん本質的に危険で、どうにかしたほうがいい。とはいえストレス解消のためのアクティビティも軒並み封じられているから、何か方法を考える必要がある。
自分はそのストレスを、直視して、無視することにした。無視するといっても心の中で思っているだけだと徹底できない部分もあるから、こうやって文章にして明示することにしてみた、というのがこのエントリでした。

うん、大変だけど、とにかく健康は大事。ウィルスのせいで肉体的な健康も危険だが、とはいえ、いやだからこそ、メンタルの健康も大事だと思う。大事にしていきたい。

*1:なおうちのチームのマネージャーは、常に健康第一、休憩をもっと頻繁に長くとれ、パフォーマンスとかよりそっちの方がはるかに優先だ、と毎週の1on1で常に言ってます

*2:これは最近オフィスのを送ってもらったが、特定の置き場所がないので使うたびに上げたり下げたりしている。めんどい。

*3:Zoom飲み会も、だからちょっと配慮というか心構えが必要になってしまう

*4:安心して生活音を立てられる、という状況がちょっとでも失われるのはストレスなんだなあ、と今回初めて実感した

*5:今回の情勢でこれはちょっとという人のフォローを外したりもした

*6:自分は弊社について、この状況下でのパフォーマンスを理由に理不尽なことをしないだろうと信頼しているけれど、まあそれはそれ