日曜日の夕方ぐらいから、かなり体調が悪化して熱が出てきた。

子供も午後から熱が出て高熱に。


月曜日の朝、子供がけいれんを起こし救急車を呼ぶ (5分経過時点で119にかけたが、電話が終わった直後にけいれんがおさまり、合計では結局6分程度だった) 一応病院までいって救急の診察をうけたが、症状はおさまっているし「熱性けいれん」でしょうということで一旦帰る (タクシー) 前回の教訓を活かしけいれん中は動画をとっていた。救急医とかにはそれ見せたらいいので説明する必要がなく気が楽。

ただ、救急のフォローのため再度受診するために午前中に病院へ。ひたすら待ち時間が長くて、僕はどんどん体調が悪化してどうしようもなくなったので、妻の母に代わってもらい自分は帰宅して内科いって寝ていることに。(子供はまたいろいろ検査したが結局普通の風邪で、やはり熱性けいれんでしょうとのことだった)


内科にいくと喉が腫れているので、そこからくる風邪でしょうという診断をうけ、ロキソニンと鼻水止めだけもらって帰宅し、ひたすら寝ていた。

火曜日ももらった薬を飲んで耐えつつひたすら寝ていた。

水曜日、全く熱が下がらず (正確にはロキソニン飲んでいる間だけ解熱して、また上がる) 再度内科。弱めの抗生物質が追加で処方された。


子供の熱はこのあたりで下がっていたと思うが自分が辛すぎて完全に妻に押し付けていたので記憶が曖昧

木曜日も全く熱が下がらず、とにかく辛い。ロキソニンが朝晩1日2回しか飲めないので、13〜18時ぐらいと、24〜翌6時ぐらいの空白時間帯で死ぬほどつらい目にあう。喉がめちゃくちゃ痛いのは確定的にあきらかなので、耳鼻科に行こうと決意するが、木曜日は休診日のため耐える。


金曜日、午前中のロキソニンが効いている時間のうちに受診する。「完全に急性扁桃炎ですねえ」と言われ、内科の処方は一旦全部止めにして、強めの抗生物質とステロイド、イブプロフェンで様子を見ましょうということになる。耳鼻科だと処方に加えネブライザーとか鼻水吸引とか一通りやってくれるので結構楽になる。

土曜日、2回薬は飲んだが熱が下がらず、一応耳鼻科を受診しておくことにした。夜中にあまりにもつらいことがあるが、なんとかならないかと話をしたらアセトアミノフェンの頓服をもらう (結局使わなかったが)。ロキソニンも余っていたらつらかったら使ってもよいと言われた。

日曜日の朝方、急激に解熱したようですごい汗と動機と共に起床した。ものすごく疲弊していたがひとまず解熱薬以外で普通に解熱した。全身症状が収まってくると喉の痛さが余計気になるようになる。

月曜日、再び耳鼻科を受診。良くなってるので処方は変えずそのまま様子見。

火曜日、喉が痛い以外はだいぶ良くなったが全身が疲弊しまくっていた。

水曜日、再び耳鼻科を受診。もう少し強い薬を続けましょうということで3日分現状の初葉が延長される。その後の3日分の薬も処方される。この日から出社しようと電車にのって途中までいったが、保育園から連絡があり帰ることに。ただ、結果からいうと体調があまり戻っておらず、出社しなくてよかった。

木曜日、だいぶ良くなったが喉が痛い状態。ひさしぶりに出社したが全体的にふらふらする。

金曜日、喉がほぼ痛くなくなる。全身のふらつきも木曜日より改善 ← いまここ


とりあえず解熱するまで38〜39度ぐらい断続的に発熱していて死にそうだった。1週間近く発熱したのは初めての経験だったので、このまま死ぬんじゃないかとか、入院になったらどうしようとか考えていた。日々追うごとに気力も体力も失われていく。当然だるすぎて1週間は完全に何もできなかった。

とにかく今回の敗因は内科に通い続けたことだと思うので、耳鼻科の範疇っぽかったらすぐに耳鼻科に行くべきだった。内科はもっとひどくなるまで薬の処方しかしないので、耳鼻科の下位互換でしかない。耳鼻科でもインフルないし風邪の診断はしてくれるので、デフォルトで耳鼻科に行くべきで、内科はそれからでも良いという教訓を得た。

概要

  1. OsmAnd はターンバイターンで事前に決めたルートをナビゲーションできる現状でほぼ唯一のアプリケーション
  2. OSS なため挙動が謎ならコード読めばいい安心感がある
  3. 普通のプロダクトだとカスタマイズできないことがカスタマイズできる安心感がある

Google Maps で自転車ルートナビゲーションは辛い

Google Maps は日本ではそもそも自転車ルートを検索できないので、使うとしたら徒歩ルートとして検索するしかない。しかし徒歩ルートはかなり曲がりまくる道をルートされるため、実際のところ移動という点ではあまり実用的ではない。

そして自転車で走りやすいルートというのは、なかなか難しいものがあるので、基本的に事前に調査をしてルートを決めてそのルート通りに走りたくなる。

Strava で事前に走行ルートを決める

Strava はPC版にルート作成機能があり、他人のも含めた走行データをもとにいい感じのルートを比較的簡単に作ることができる。経由地点を適当に設定すると、そこを経由しつつ、人気のあるルート・坂が少ないルートを自動で検索でき、完璧とは言えないが事前にルートを作る用途であれば十分使える。高低差のグラフが出るので、事前に辛さを検討しやすい。

しかし、作ったルートをアプリでターンバイターンナビゲーションする機能はなく、基本はマップ上にルートが表示されるだけである。また、別アプリで記録をとっている場合、Strava で記録を開始したくないので、そもそも使いたくない。

ということで、StravaからエクスポートできるGPXファイルをGoogle Mapsに取りこんでナビ…… としたいところだけど、Google Maps はグーグルの提案する道しか案内できないため、この用途では使えない。

一応、GPXファイルを変換して、マイマップとしてGoogle Mapsに取りこんでルートを表示することはできる。しかし、表示できるだけなので、ルートを確認するときは止まって端末のロックを解除して… という操作が必要になり、かなりだるい。というかルート表示するだけなら、前述の通りStravaのアプリでもできる。

OsmAnd でルートに沿ったナビゲーション

で、やっとタイトルのOsmAndがでてくる。

http://osmand.net/ Open Street Map を利用した Android 向けのマップアプリで、有料版もあるけど、開発がオープンになっており、あまり商売気はない。有料版も買いきりタイプでそんなに高額ではない。有料版というか寄付バージョンというおもむき。

セットアップ

まず地域データをダウンロードする必要がある。Japan Kanto (など地域ごとにある) の地図をダウンロードしておく。音声データは、ダウンロード可能になっているものは現状ではかなり難があるのでダウンロードしなくてよい (後述)

ダウンロード画面はなんかバギーなので、一回操作したらダウンロードが終わるまでしばらく待ったほうが良い。基本地図と含めて300MB ぐらいダウンロードが必要だけど、向こうの回線がそれほど早くないみたいであまり高速には落ちてこない。

2.0.1 には地図上の日本語を正しく表示できないバグがあるみたいだけど、そのうち直るらしいので気にしない。

GPX ファイルの配置

.gpx ファイルを Android File Transfer で内部ストレージ→ /osmand/tracks/ 以下に保存する。

マップ画面のナビボタンをタップして、自転車を選び、設定アイコンをタップする。いろいろオプションが表示されるが、下のほうに「GPXルート:無し」となっているので、設定してやる。

そうするとルートが表示され、オプションが更新されるので、適当に設定して「出発」をタップすれば良い。

「GPXルートを反転」は帰りルートだろうけど、「経路全体に沿って通る」はいまいちよくわかってない。FAQ によると、終了点付近にいても開始点から沿うようになってる?

音声ナビのTTSファイル

TTS(Text to Speech)は自体は Android システムのエンジンが使われる。これはシステム側の「設定」→「言語と入力」→「テキスト読み上げの出力」から設定できる。

Google Maps が入っていれば Googleテキスト読み上げエンジンが入っているはずなので、これを設定しておけばとりあえず間違いない。

Pico TTS というのがデフォルトで入っているが、これは日本語に対応していないので設定しておくとハマる。

好みで KDDILABAS N2 TTS とかにしてもいいと思うけど、明瞭度が低くてナビゲーション向きの声ではなかった (良くいうと落ち着きがある声質)。


OsmAnd でダウンロードできる日本語TTSは、ローマ字をTSSエンジンに送るような形になっており、かなり発音がおかしいし、ちょいちょいローマ字をそのまま読みあげたりする。PR は送ったが、とりあえず自力でTTSファイルを作ってインストールする。

これを Android File Transfer で、「内部ストレージ」→「osmand/voice/ja-native-tts/_ttsconfig.p」として保存する。

Android File Transfer で osmand とか voice とか、ディレクトリが見えない場合、ちょっと面倒なことしたりする必要がある。

ちなみにこの TTS ファイルは Prolog のプログラムになっている(難しい)。

Microsoft Maps を表示させる

デフォルトはオフラインのベクターマップだが、結構表示にもたつきがあるのと、レンダリングが綺麗とはいえないので、Microsoft Maps を表示するようにしてみる。(なおルート検索のためにもベクターマップは必ず必要)

オンラインマッププラグインを有効にして、

  1. 「タイルマップ選択」
  2. 「リスト以外のものをインストール」
  3. 「Microsoft Maps」

とやると Microsoft Maps を使うことができる。しかし、英語リソースがダウンロードされてしまうので、

  1. 「マップの定義と編集…」
  2. 「既存データから選択…」→「Microsft Maps」
  3. 「URL」におもむろに Java っぽいコード (正確にはBeanShell)があらわれるので、がんばって return しているとことを探して、クエリパラメータに mkt=ja-jp がつくようにする。

とやると、日本語のマップデータがダウンロードできる。

高解像度データではないのですこしボヤけるが、非常にみやすいマップになって良い。欠点はいちいちロードが走ることだろうけど、最悪オフラインマップがあると思うと気が楽ですね。

  1. USB を一度抜く
  2. 設定→アプリケーション→メディアストレージ
  3. 「強制停止」
  4. 「データを消去」
  5. https://play.google.com/store/apps/details?id=com.gmail.jerickson314.sdscanner を実行する
  6. USB を繋ぐ

→ Android File Transfer が起動して見れるようになる。

.nomedia があるディレクトリはインデックス化されないみたい? なので、もし見たいディレクトリにあるなら、Android 側のファイラか何かで消しておく。

発熱があって自宅で寝ている間に2回短い痙攣のような症状(おさまってすぐ泣いたため、お医者さんの話ではこれは悪寒戦慄ではないかとのこと)

朝方、今度は30秒~1分ぐらい痙攣したあと、30秒ぐらい意識がなく(目は開いているがどこにも焦点があっておらず呼びかけにも応えない状態)、その後意識は戻ったが、小児科に電話したところすぐ受診となった。

かかりつけ小児科では既に紹介状が用意されていたようで、すぐに総合病院での検査になった。

その検査の最中、また痙攣が起き、意識が戻るまで7分。

この間に血液検査、尿検査、髄液検査といろいろ検査された。

結局のところ尿路感染症と熱性痙攣とのことで、最悪な感じではなかったが、1週間程度の入院となった。

悪寒戦慄(震え)と痙攣の違い

見てても区別が難しい。

震えの場合意識がなくならないので、目があったままなら震えらしい。

痙攣だと呼吸が弱くなるので、だんだんくちびるが青くなってきたら痙攣らしい。

いずれにしても、症状がでている間はそっとしておく以外できることはないので、録画でもしていたほうがあとで役に立つ。

5~10分止まらなかったり意識が戻らなかったら救急車を呼んでいいらしい。

今回2回痙攣を起こした(普通は1回らしい)が、退院時の説明によると、次回また痙攣を起こしたとしても、今回と同じ判断基準で受診なり救急車を呼ぶなりせよとの説明だった。

判断基準

育児書に書いてある通りの判断を行った。

前もって育児書の対応一覧を夫婦でそれぞれ読んでいたので、熱性痙攣というのがあるのは知っていたし痙攣時間を見たりは一応できたが、 それでもかなり混乱する。

最新決定版 はじめての育児: 生まれてから3才までの育児はこの1冊におまかせ! (暮らしの実用シリーズ) -

4.0 / 5.0

病状別に、時間外診察すべき基準、救急車を呼ぶべき基準が書いてあるのが良い。そのページだけどっかに貼っておきたいぐらい。

退院後

入院中はずっとついていられないので、だいぶ泣いたみたいで喉がかれていた。看護士さんは保育士ではないので、人によっては塩対応ぽいが忙しいので仕方ない (というか責任範囲ではない)。

退院後も自宅療養せよとのことで、保育園に預けることができず、厳しい。病児保育まで気が回らなかったので、近くの親戚に相談して預かってもらって、数日後に診察で登園許可がでた。

ただ、尿路感染症はしばらく定期的に通って検査する必要があるみたい。

入院中、小児医療費助成で医療費はほぼかからないが、食事の健康保険外の負担だけある (1食につき260円が標準)。

細い回線で Chrome のダウンローダだとうまくレジュームできないことが多々あって厳しい。キャンセルするとダウンロード途中のファイルが消えたりするし (余計なお世話だ)、大きなファイルはダウンロードしにくい。

ということで、curl でダウンロードすることにする。特にログインセッションが必要でなければ普通にやればいいが、ログインセッションが必要な場合、いちいちヘッダを全部書くのはだるいので、一度 Chrome 上で開発者ツールを開き、リクエストを発生させてすぐキャンセルし、Network ペインで該当リクエストを右クリックして Copy as cURL すると早い。

そのうえでお尻に -o filename -C - をつけてやる、つまり

$ noglob curl... -o filename -C -

curl... の部分はペースト。noglob は念のためつけておく。-o filename でダウンロード先ファイル名を指定し、-C - でレンジリクエストによるレジュームを有効にする。-C オプションはハイフンを指定すると、-o で指定したファイルの大きさから判断してレジュームをかけてくれる。ファイルがなくても -C オプションはエラーにはならないので、はじめからつけておいて良い。

Current Speed が0ちかくになったらやりなおせば良いし、ログインセッションが切れたら、ログインしなおしてクッキーを取得し、同じファイル名でレジュームを続ければ良い。

雨の日は走らない自転車通勤

自転車通勤を検討しようと思っても「雨の日は走らない」を前提に考えると「果たして定期券よりも安いのだろうか?」と不安になる。

そこで、過去30年の降水履歴を考慮しつつ、自転車通勤 vs 通勤定期のコスト差を出してみることにした。

定期券の場合、通勤にかかるコストは定期券料金だけである (普通は6ヶ月分を一括で買うが、この場合半額ぐらいになる)

雨の日は電車通勤する自転車通勤の場合、晴れの日の駐輪場料金のほか、雨の日の往復電車賃がかかる。

計算

Polymer 使って書いてみた

各値について

入力

  • 定期代:定期代
  • 期間:定期を買う期間
  • 雨天時往復料金:雨が降って自転車通勤しないときの往復料金
  • 駐輪場料金:晴れていて自転車通勤するときの駐輪場料金
  • 開始日:この日から定期の期間分の間の降水確率をもとめる

出力

  • 総通勤日数:期間中の土日を除いた日数
  • 期間中平均降水確率:1mmでも降水がある確率
  • 期待自転車通勤日数:雨の日を除く通勤日数
  • 損得分岐日数:この日数以上は最低でも自転車通勤しないと定期よりも損をするという日数

実装

降水確率

無駄に統計データを集計して使っている。

気象庁の統計データが csv でダウンロードできるので

http://www.data.jma.go.jp/gmd/risk/obsdl/index.php#

  • 東京
  • 1985-01-01 - 2014-12-31 までの29年
  • 降水量の合計
  • 日別

を選択してダウンロードし、日付単位で集計し、1mm でも降水があったら雨として降水確率を出している。29年なのは、1回でダウンロードできる限界だったから。

https://dl.dropboxusercontent.com/u/673746/Screenshots/2015-06-03%2010.34.39.png

Polymer

独自要素の style is="custom-style" は template 直下におかないと効かなくてハマった

this.notifyPath("obj"); だと obj の各キーに対する notify にならないらしく、this.notifyPath("obj.foo"); とかやる必要があった (this.set("obj.foo", newValue))

flex layout のドキュメントがどこにあるのか謎なので、iron-flex-layout/classes/iron-flex-layout.html を見る必要があった。

あとは特にDOMを複雑にいじるようなことはしていないので、非常に簡単に書けた。データバインディングがあるとこういうのはらくちんでいいですね。

なにを入門するにせよ、とりあえず最小構成を確認したい、と思う人はいるでしょう。何を隠そう、僕もその一人です。

index.html

<!DOCTYPE html>
<html>
        <head>
                <title></title>
                <meta charset="utf-8"/>
                <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
                <script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
                <link rel="import" href="bower_components/polymer/polymer.html"/>
                <link rel="import" href="bower_components/paper-input/paper-input.html"/>
                <link rel="import" href="bower_components/paper-material/paper-material.html"/>
                <link rel="import" href="bower_components/paper-styles/paper-styles.html"/>
        </head>
        <body class="horizontal center-justified layout">
                <dom-module id="my-app">
                        <template>
                                <div style="width: 300px">
                                        <paper-input label="Foo" type="number" value="{{foo::input}}"></paper-input>
                                        <paper-input label="Bar" type="number" value="{{bar::input}}"></paper-input>
                                </div>
                                <div class="result">
                                        Foo: <span>{{result(foo, bar)}}</span>
                                </div>
                        </template>
                </dom-module>

                <paper-material elevation="1" style="padding: 20px">
                        <my-app foo="1" bar="1"/>
                </paper-material>

                <script>
                        Polymer({
                                is: 'my-app',
                                properties: {
                                        foo: Number,
                                        bar: Number
                                },
                                result : function (foo, bar) {
                                        return +foo + +bar;
                                }
                        });
                </script>
        </body>
</html>

bower.json

{
  "name": "my",
  "version": "0.0.0",
  "authors": [
    "cho45 <cho45@lowreal.net>"
  ],
  "license": "Public Domain",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "paper-input": "PolymerElements/paper-input#^1.0.0",
    "paper-button": "PolymerElements/paper-button#^1.0.0"
  }
}


これら index.html と bower.json を特定のディレクトリにおき、bower update をかけてから、ブラウザで 直接 index.html をひらけば、なんとなく動く。

ただこれだと、せっかく Polymer を使っているのに、Chrome 以外でうごかない。というのも、HTML Import によって Polymer の依存が解決される前に (native で HTML Import が実装されていないブラウザでは) Polymer() がある script 要素が実行されてしまうからのようだ。dom-module を定義する場合 index.html で定義せず、別ファイル (app.html とか) にして rel="import" し、index.html では要素を書くだけでスクリプトは書かないのがセオリーのようだ。

どうしてもペライチのまま動かす場合、以下のように WebComponentsReady のタイミングで Polymer を呼べば、その後該当する要素はコンポーネントとして扱われて正しく動くようになった。

document.addEventListener('WebComponentsReady', function() {
    Polymer(...);
});

当然このまま動かすと、依存する html ファイルや css をたくさんリクエストするが、本当にちょっとしたアプリなら気にするほどでもなくとりあえずこれで開発して、あとから考えればよさそう。

Polymer のざっくりした考えかた

アプリケーションはコンポーネント(と呼ばれるエレメント)の集合体であり、アプリケーションもまた1つのコンポーネント(エレメント)であるというのが Web Components の考えかた、だと思う (コンポーネントの定義が見つからなかったので、正しくないかもしれない)。

Polymer は Web Components そのものではなく、あくまで Web Components の概念をベースにしたフレームワークなので、とりあえず Polymer は Polymer として使いかたを覚えたらよくて、Shadow DOMガー! とかいって Shadow DOM が何かを知る必要はない。というか Shadow DOM のポリフィルは使ってない。Polymer は双方向データバインディングの仕組みが template 要素を使って提供されているが、データバインディングの仕組みは Polymer 独自であり、標準化されているものではない。