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

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 独自であり、標準化されているものではない。

  1. トップ
  2. tech
  3. Polymer 最小構成のペライチファイル

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

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

そこで、過去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を複雑にいじるようなことはしていないので、非常に簡単に書けた。データバインディングがあるとこういうのはらくちんでいいですね。

  1. トップ
  2. tech
  3. 定期券を捨てて自転車通勤にして本当に金を節約できるか?

細い回線で 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ちかくになったらやりなおせば良いし、ログインセッションが切れたら、ログインしなおしてクッキーを取得し、同じファイル名でレジュームを続ければ良い。

  1. トップ
  2. tech
  3. curl で大きなファイルを resume しながらファイルダウンロード

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

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

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

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

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

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

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

見てても区別が難しい。

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

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

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

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

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

判断基準

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

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

最新決定版 はじめての育児 (暮らしの実用シリーズ) - 細谷亮太

細谷亮太

4.0 / 5.0

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

退院後

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

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

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

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

  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 側のファイラか何かで消しておく。

  1. トップ
  2. tech
  3. Android File Transfer で表示されないファイルがある

概要

  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. トップ
  2. tech
  3. OsmAnd で自転車ルートをターンバイターン・ルートナビゲーション