Infinito Nirone 7

白羽の矢を刺すスタイル

初キャンプ@ふもとっぱら

つい最近はやった某キャンプアニメにあやかって、ゆるくキャンプしようぜ!と知人と話しをしていて、ふもとっぱらキャンプ場でキャンプをしてきました。

ふもとっぱら - fumotoppara.net -

ふもとっぱらは、本栖湖の南、富士山麓のなかでも静岡県側にあります。車でのアクセスでは中央道でも東名でも行けると思います。 とにかくかなり広い高原で車に横付けしてテントを設営できるオートキャンプ場で、朝と夕方はそれぞれ見ごたえのある富士山を拝めます。

自分は車もキャンプ用具も持ち合わせてはいないので、ほとんどをレンタルサービスに頼りました。車はもともとレンタカーをよくつかうので慣れているのですが、テントやシュラフもレンタルが可能なことをつい最近知りました。今回は旧知の友人と行きましたが、自分たちで買ったものと言えば、食材・飲み物と簡易コンロ・木炭など食事に関するもののみでした。

レンタルテントやシュラフは郵送で受取・返却ができます。この週末は受取のタイミングがギリギリだったので郵送での受取はできませんでしたが、返却では着払いの郵送をしました(レンタル時の金額によっては元払いになるそう)。

テントの設営からして完全に素人でしたが、なんやかんやサッとテントが設営でき、楽しくキャンプができました。 これからの季節日の出がかなり早いので、朝起きるのがはやくなります。いいカメラをもっていると、朝焼けの富士山をおさめることもできます。

次にキャンプする時は、もう少し良い炭を使って焼肉をしたり、お湯を沸かす装備を持っていってゆったりとスープやコーヒーを楽しむなどもしてみたいなと思いました。

Mirage Solo で開発者オプションをいじるときは「ポインタの位置」を有効にしない

そろそろ自分も VRバイスを一個くらい手元において遊べるようにしておこうとおもって、先週末 Mirage Solo を注文しました。Amazon 先生がサッと発送してくれたので週末にシュッと受け取れました。

開発者なので電源投入してすぐ開発者オプションを ON にしたのですが、この開発者オプションの中にある「ポインタの位置」を ON にすると、ポインタの位置のオーバレイはきちんと出るのですが設定画面が表示されなくなるようです。設定画面自体は Chrome など VR 非対応のアプリとおなじように、スマホの画面のようなものが VR 空間に浮かび上がるように表示されますが、なぜか Chrome は大丈夫で設定画面はダメなようです… もし ON にしてしまって設定画面が触れなくなった場合は、adb shell settings put system pointer_location 0を叩いて戻してあげましょう。

VR コンテンツそのものは軽くサッと触っただけでまだほとんど楽しめてないので、もうしばらくはいろいろ試しながら遊んでみようと思います。

箱根を登ってインターハイしてきた

先週は金精峠に行ったので、今週は箱根です。

はじめての箱根、聞いていたとおりのキツさで、かつ距離を勘違いしていて終盤ヘタってしまいました……

 

国道1号最高地点の標識を見てだいぶ満足しましたが、芦ノ湖に降りてからは「このまま小田原に降りてしまっていいのか?」と頭の悪いことを考えてしまい、結果芦ノ湖から山中湖まで行く修行のような行程になりました。
f:id:KeithYokoma:20180512175630j:image

芦ノ湖からはまず大涌谷方面に走り出し乙女峠を目指します。そこを越えると一気に御殿場まで降り、御殿場の市街地を抜けるとすぐに籠坂峠(山中湖村)まで続く長い長い登りが始まります。斜度は7%を超えることはなく、ひたすら4%5%あたりの坂が無限に続きます。緩くなることが殆どないので、ペースを守らないと簡単に足が売り切れると思います……

 

山中湖からは、富士吉田から大月を目指すプランと道志みちを通って相模原を目指すプランというふたつのヤバいプランをまたしても考えましたが、もう足がないので富士山駅輪行することにしました。
f:id:KeithYokoma:20180512180112j:image

来月は富士ヒルでまた来ます。

GWのシメに日光から金精峠を登ってきた

ゴールデンなウイークの間にどこかへ輪行して山に行こうという計画は前々からしていて、本当は渋峠に行きたかったんですが、火山活動の関係で長野県側からしか登れなくなってしまいました。長野側から登るのもいいんですが、ゴールデンなウイークでみんな電車やら新幹線使うのでそういう中での輪行は大変だからもうちょっとイージーモードで行ける場所!と思って出した結論が日光でした。もともといろは坂やら金精峠は言ってみたかったのでちょうど良いタイミングだ!と思ってせっせときっぷを確保しました。

 

とりあえず我が家からなら新宿に行けば東武日光までの特急に乗れるので、あとは駅から金精峠までまっしぐら!

 

いろは坂までの道でもすでに上り坂なので油断ならないのですが、いろは坂自体は激坂というわけでもないので、淡々と登りました。
f:id:KeithYokoma:20180506174353j:image

はじめて自転車で来る中禅寺湖


f:id:KeithYokoma:20180506174515j:image

戦場ヶ原からさきは車でも来たことがないので、完全にテンションがあがっています。


f:id:KeithYokoma:20180506174626j:image

戦場ヶ原から金精峠までは割とキツめ。たまに10%を超える坂が出てきましたがなんとか登りきりました。たぶん途中でろんぐらいだぁすの原作者の方っぽい人を追い越した気がする。朝の電車でツイッターみてたら先に登り始めていたらしいので。。


f:id:KeithYokoma:20180506174845j:image

峠を超えて少し下ったところにある休憩所で山菜そばとゆば豚まんを食べました。


f:id:KeithYokoma:20180506174951j:image

山と言えばソフトクリーム。


f:id:KeithYokoma:20180506175045j:image

下りはゆるゆる、上りで通過してきたところに寄り道を。この寄り道の途中で、登ってきたときに見かけたユーコンというお店がろんぐらいだぁすの聖地だということに気がついて、ここでご飯食べたら良かったと少し後悔しました。


f:id:KeithYokoma:20180506175226j:image

帰りは、行きに食べ損なった駅弁。おいしゅうございました。

桜のAACR完走

今年はじめて桜の AACR(Alps Azumino Century Ride)に参加しました。

これまではヒルクライムが中心だ、長距離ライドのイベントはツールド東北以来ということになります。

車で行くか電車で行くか悩みましたが、150km走ったあとに運転するのはヤバそうだなと思ったので、特急でいくことに。

前日に受付を済ませて松本の観光と食事を。晩御飯は以前ツールド美ヶ原に来たときにたまたま立ち寄ったとんかつ屋さんが最高だったので、リピートしました。
f:id:KeithYokoma:20180422173848j:image

お通しに二種類のお漬物がでてきて、それからたんまりのとんかつや揚げ物、ご飯とお味噌汁がでてきます。

スタートは1組なので早めに就寝。4時に起きて準備して、5時半スタートに備えました。昼間はあんなに暑かったのに、夜や明け方は超寒かったです。まあでも、自転車に乗っていれば体はあたたまるので、日がいい感じに登るまでの辛抱でした。
f:id:KeithYokoma:20180422174748j:image

安曇野やその周辺はどこを走ってもキレイな眺めで、ちょうど今のこの時期が、雪をかぶった山と満開の桜が楽しめるようで、エイドステーション以外の場所でも写真撮影をしていました。普通に一眼レフなどを持ち歩いている観光客も多くいました。
f:id:KeithYokoma:20180422175013j:image

独特な味噌をつけていただくおにぎり最高!🍙
f:id:KeithYokoma:20180422175044j:image
f:id:KeithYokoma:20180422175124j:image
f:id:KeithYokoma:20180422175056j:image
f:id:KeithYokoma:20180422175218j:image
f:id:KeithYokoma:20180422175235j:image
f:id:KeithYokoma:20180422175338j:image

14時前にゴールするのは完全に予想外でしたが、無事完走できました。
f:id:KeithYokoma:20180422175416j:image
 手足はカバーをつけて日焼け対策をしましたが、顔や首周りの対策ができていなくて、ゴール後梓水苑のお風呂に入ったときにヒリヒリしてしまいました。次はきをつけよう。

ゴールしたときにゼッケン番号による抽選会をやっていて、こういうの当たらないんだよなと思っていたらハンドクリームが当たりました。肌荒れひどいマンなので助かる。

Robolectric を offline mode で動作させる

Robolectric でテストを実行すると、初めの方のテストでなにかを Maven Central からダウンロードしているログが出力されることがあります。これは Robolectric がテスト実行時に必要な依存をダウンロードしているもので、Android SDK のなかのクラスを JVM で実行可能にしている jar が入っています。

ローカルでテストを動かす分には初めてテストを実行するときにしかお目にかかることはありませんが、CI のような環境の場合、CI が走るたびに Robolectric の依存解決が動きます。 また、Robolectric はどの SDK version でテストを動かすかを動的に指定できるので、@Config(sdk = [21]) とか @Config(sdk = [25]) とかが付いているテストケースがあるたびに、必要な jar を適宜取りに行くようになっています。 そうすると、@Config アノテーションの数だけ jar のダウンロード時間が必要になるので、CI だと結構な時間が依存解決に費やされてしまいます。

そこで Robolectric には offline mode というのがあって、あらかじめ jar をローカルに保存しそのパスを教えてあげると、テスト実行時には Maven Central へアクセスせずともテストが実行できるようになっています。 これで時間の節約ができるというわけです。

事前にダウンロードする Gradle スクリプト

medium.com

実はすでにこれを実現するスクリプトが公開されています。

問題点

概ね offline mode の設定と jar の場所の設定はこのスクリプトで問題ありませんが、複数の jar が必要なときにうまく動きません。

上記の記事で書かれたスクリプトの dependencies を次のように書いたとします。

configurations {
    robolectricRuntime
}

dependencies {
    robolectricRuntime "org.robolectric:android-all:4.1.2_r1-robolectric-r1"
    robolectricRuntime "org.robolectric:android-all:4.3_r2-robolectric-r1"
    robolectricRuntime "org.robolectric:android-all:4.4_r1-robolectric-r2"
    robolectricRuntime "org.robolectric:android-all:5.0.2_r3-robolectric-r0"
    robolectricRuntime "org.robolectric:android-all:7.1.0_r7-robolectric-r1"
    robolectricRuntime "org.robolectric:android-all:8.1.0-robolectric-4611349"
}

テストでは ICS, JB, K, L, N, O のそれぞれの android-all について jar が必要な状態です。 複数必要なので dependencies の指定も複数並べることになりますが、robolectricRuntime のどの dependency も GroupId と Artifact が同じで Version のみが異なるため、Gradle はこの列挙された dependencies の中から最新のものしか解決しません。 結果、jar を放り込むディレクトリには O の android-all の jar ファイルしかいないことになります。

どう解決するか

Configuration ごとに dependency の解決が行われることを考えると、必要な android-all の jar ごとに Configuration を作れば良いことになります。

configurations {
    robolectricRuntimeICS
    robolectricRuntimeJB
    robolectricRuntimeK
    robolectricRuntimeL
    robolectricRuntimeN
    robolectricRuntimeO
}

dependencies {
    robolectricRuntimeICS "org.robolectric:android-all:4.1.2_r1-robolectric-r1"
    robolectricRuntimeJB "org.robolectric:android-all:4.3_r2-robolectric-r1"
    robolectricRuntimeK "org.robolectric:android-all:4.4_r1-robolectric-r2"
    robolectricRuntimeL "org.robolectric:android-all:5.0.2_r3-robolectric-r0"
    robolectricRuntimeN "org.robolectric:android-all:7.1.0_r7-robolectric-r1"
    robolectricRuntimeO "org.robolectric:android-all:8.1.0-robolectric-4611349"
}

そして jar を copy するタスクの中身を次のように書き換えます。

rootProject.task(type: Copy, overwrite: true, "downloadRobolectricDependencies") {
    configurations.all { configuration ->
        if (configuration.name.startsWith("robolectricRuntime")) {
            from configuration
        }
    }
    into robolectricDependenciesFolder
}

これで Configuration ごとに別の android-all の jar をダウンロードしてローカルにコピーするまでが実現できました。

あとは ./gradlew downloadRobolectricDependencies とするだけですべての jar がダウンロードできます。

Android Plugin for Gradle 3.1.0 で The SourceSet 'xxx' is not recognized by Android Gradle Plugin

Android Studio が 3.1.0 になったのに合わせて Android Plugin for Gradle も 3.1.0 が出ました。

Android Plugin for Gradle Release Notes | Android Studio

リリースノートには記述がありませんが、alpha のころから存在する問題として、3.1.0 にあげると"The SourceSet 'xxx' is not recognized by Android Gradle Plugin"というエラーでビルドが失敗する場合があるようです。 たまたま自分もこの問題にぶちあたったので、何がダメでどうするとよいかをメモしておきます。

次のような build.gradle がある前提です。 minSdktypeのふたつの flavorDimensions があり、variantFilter で api19FlavorA だけを無視する設定です。

android {
  flavorDimensions 'minSdk', 'type'

  productFlavors {
    api19 {
      dimension 'minSdk'
      minSdkVersion 19
    }
    api21 {
      dimension 'minSdk'
      minSdkVersion 21
    }
    flavorA {
      dimension 'type'
    }
    flavorB {
      dimension 'type'
    }
  }

  variantFilter { variant ->
    def names = variant.flavors*.name
    if (names.contains('api19') && names.contains('flavorA') {
      setIgnore(true)
    }
  }
}

このとき api19FlavorA の SourceSet を設定すると、タイトルにあるようなThe SourceSet 'xxx' is not recognized by Android Gradle Pluginというエラーが発生します。 Android Plugin for Gradle 3.0.x まではとくにエラーになるものではありませんでしたが、3.1.0 からはダメなようです。

上記のビルドスクリプトでは variantFilter で variant を setIgnore(true) する条件が ProductFlavor の名前だけなので、不注意でないかぎり無視した ProductFlavor の SourceSet を設定することはないと思いますが、無視する条件が環境によって変わる場合は、それにあわせて SourceSet の設定を変えてやる必要があります。

def disable_condition = // Condition to disable api19Flavor variant

android {
  // ...

  variantFilter { variant ->
    def names = variant.flavors*.name
    if (disable_condition && names.contains('api19') && names.contains('flavorA') {
      setIgnore(true)
    }
  }

  sourceSets {
    if (!disable_condition) {
      api19FlavorA {
        // api19FlavorA SourceSet configuration under a specific condition
      }
    }
    api19FlavorB {
      // always configure SourceSet for api19FlavorB
    }
    // ...
  }
}