tech::hexagram

personal note for technical issue.

MTのテンプレートタグの変数展開

セットした値を mtFor で利用したい場合は、変数名を $ で囲うと展開される。

<mt:SetVar name="current_year" value="2017">
<mt:For var="year" from="1990" to="$current_year" increment="1">
...
</mt:For>

追記: MTテンプレートタグで去年の年を取得する方法として、 MTDate を利用すると良いと一度書いたものの、これは

再構築した日時を表示します。更新日時を表示したいときなどに利用します。

とあるので、「アクセスした日」を起点としての判断ができないらしい。

git fetchで、unable to update local refとエラーが出た場合の対処法

リモートでブランチが削除されたのか、git fetchしようとした時にエラーが出た。 git remote prune origin / git fetch originで解決。

error: there are still refs under 'refs/remotes/origin/XXX`
 ! [new branch]      XXX    -> origin/XXX  (unable to update local ref)
$ git remote prune origin
...

$ git fetch origin
From github.com:xxx/xxx
 * [new branch]      XXX    -> origin/XXX

distilleryを利用したリリースビルドから、command経由でmoduleを実行する際のハマりどころ

2点ハマりどころがあったのでまとめておく。

リリースビルドに含まれないmoduleを実行していないか

/path/to/bin$ ./some command Elixir.Some.Module run ...
{"init terminating in do_boot",{undef,[{'Elixir.Some.Module',application,[],[]},...,{line,24}]},{init,start_em,1,[]},{init,do_boot,3,[]}]}}
init terminating in do_boot ()

/path/to/lib/some 配下で、 Elixir.Some.Module.beam ファイルが生成されているかどうか確認する。

ETSの上限に達していないか

/path/to/bin$ ./some command Elixir.Some.Module run ...
{"init terminating in do_boot",{{badmatch,{error,{some,{{shutdown,{failed_to_start_child,'XXXX',{shutdown,{failed_to_start_child,'XXXX',{system_limit,[{ets,new,['XXXXXX',[set,public,named_table,{read_concurrency,true}]],[]},...{init,start_em,1,[]},{init,do_boot,3,[]}]}}
init terminating in do_boot ()

ETSの上限に達している場合、上記のようなエラーが出る。ETSの上限は ERL_OPTS から "+e 16384" のように渡すことが出来る。

github.com

distilleryのビルドの設定で、 erl_opts から設定を追加する。

github.com

Exqのenqueueのプロセスを追ってみた

仕事に必要だったのでメモ書き程度に残しておく。

Exq というRedisを利用したJob queueライブラリのコードリーディング。

  • Exq.enqueue/4 : use Exq.Enqueuer.EnqueueApi とあるので、その中に実体がある。
# Exq.Enqueuer.EnqueueApi

def enqueue(pid, queue, worker, args), do: enqueue(pid, queue, worker, args, @default_options)

def enqueue(pid, queue, worker, args, options) do
  GenServer.call(pid, {:enqueue, queue, worker, args, options}, Config.get(:genserver_timeout))
end

GenServer の仕組みで :enqueue をメッセージとして送信する。 handle_call:enqueue を処理しているメソッドを探す。

# Exq.Manager.Server

def handle_call({:enqueue, queue, worker, args, options}, from, state) do
  Enqueuer.enqueue(state.enqueuer, from, queue, worker, args, options)
  {:noreply, state, 10}
end
  • Exq.Enqueuer.enqueue: use Exq.Enqueuer.EnqueueApi とあるので、その中に実体がある。
# Exq.Enqueuer.EnqueueApi.enqueue

def enqueue(pid, from, queue, worker, args, options) do
  GenServer.cast(pid, {:enqueue, from, queue, worker, args, options})
end

handle_cast:enqueue を処理しているメソッドを探す。

# Exq.Enqueuer.Server

def handle_cast({:enqueue, from, queue, worker, args, options}, state) do
  response = JobQueue.enqueue(state.redis, state.namespace, queue, worker, args, options)
  GenServer.reply(from, response)
  {:noreply, state}
end
# Exq.Redis.JobQueue
def enqueue(redis, namespace, queue, worker, args, options) do
  {jid, job_serialized} = to_job_serialized(queue, worker, args, options)
  case enqueue(redis, namespace, queue, job_serialized) do
    \:ok    -> {:ok, jid}
    other  -> other
  end
end
def enqueue(redis, namespace, queue, job_serialized) do
  try do
    response = Connection.qp(redis, [
      ["SADD", full_key(namespace, "queues"), queue],
      ["LPUSH", queue_key(namespace, queue), job_serialized]])

    case response do
      {:ok, [%Redix.Error{}, %Redix.Error{}]} = error -> error
      {:ok, [%Redix.Error{}, _]} = error -> error
      {:ok, [_, %Redix.Error{}]} = error -> error
      {:ok, [_, _]} -> \:ok
      other    -> other
    end
  catch
    :exit, e ->
      Logger.info("Error enqueueing -  #{Kernel.inspect e}")
      {:error, :timeout}
  end
end

def to_job_serialized(queue, worker, args, options) do
  to_job_serialized(queue, worker, args, options, Time.unix_seconds)
end
def to_job_serialized(queue, worker, args, options, enqueued_at) do
  jid = UUID.uuid4
  retry = Keyword.get_lazy(options, :max_retries, fn() -> Config.get(:max_retries) end)
  job = %{queue: queue, retry: retry, class: worker, args: args, jid: jid, enqueued_at: enqueued_at}
  {jid, Config.serializer.encode!(job)}
end

というわけで Exq.Redis.JobQueue.enqueue/4 がほぼ実体であることがわかった。Redisに投げているコマンドの詳細は下記となる。


ちなみに dequeue の処理を追うつもりであったが hexdoc に詳細な解説があったので大体の処理の流れは理解できた。

ロードバイクで仙台まで行ってきた

連休を利用し、3泊4日でロードバイクに乗ってはるばる仙台まで自走してきた。

総走破距離は386kmで、これまでで一番遠くまで行くことが出来た。今回の旅に向けて準備してきたこと、旅の道中、旅から帰宅後の反省も含めて記録しておく。このエントリは1万字を超えているので、どんな旅だったかかいつまんでみたい場合は目次を利用していただきたい。

準備編

気をつけたこと

実は去年、同じようにゴールデンウィークを利用して2泊3日でロードバイクに乗って名古屋に行こうとしていた。しかしながら、準備不足で2日目に浜松に到着した時点で体力が底を尽きてしまい、そこから輪行で名古屋に向かったので自走できたのは270kmほどだった。

この経験を踏まえて、今年は下記に気をつけて計画を練った。

1日あたりの走行距離を短縮

去年は1日平均120~130kmの行程で着いたら夕方、しかもヘトヘトで何もする気が起きなかった。自転車旅行で移動がメインの目的ではあるが、日々の目的地に着いた後の観光も(時間は限られてはいるが)楽しみたかったため、1日80km前後を目標に再設定した。

走行中に体に荷物を背負わないようにする

去年リタイアした最大の原因としては、荷物をバックパックに詰めて背負って移動していたため、1日経つ毎に肩の凝りがひどくなったことだった。これを踏まえて、走行時に身につけるものはヒップバッグのみになるようにし、大半の荷物は自転車に積むようにした。

ホテルはコインランドリーがあるところを選ぶ

サイクルウェアは1着しか用意していないので、基本的には宿についたら洗うようにする運用方法を取った。去年は宿に到着後、自分で洗ってたらすごく疲れたので今年はそれを回避。

平地で足を使いすぎない

去年は1日目に静岡の新富士のあたりまで走っていて、行程の終盤に箱根超えがあり、800mほどの登坂をする必要があった。にも関わらず、平地で飛ばしすぎてしまったことで箱根では足が使い物にならずほぼ押して凌いでしまっていた。

県をまたぐ際はほぼ山越えがあると思っていたほうが良いので、それを見据えて平地で気持ちよく走れそうなところもぐっと抑えて足に負担がかからないペースになるように気をつけた。

用意した荷物

また泊りがけで行くときのために備忘録も兼ねてリストアップしておく。

f:id:manji602:20170429093820j:plain

荷物

  • 輪行グッズ

    • ショルダーケーブル・ホイール用紐
    • スプロケ保護カバー・チェーン保護カバー
    • フレームカバー
    • エンド金具
    • 輪行袋(オーストリッチ ロード320)
      • 前輪と後輪両方外すタイプのもの
    • 紐予備2本
  • 自転車応急処置グッズ

    • 針金、結束バン
    • チェーンカッター
    • ミッシングリンク・タイヤブート・パッチ
    • バルブキャップ予備・SPDクリート予備
    • 予備チェーン
    • 予備チューブ
    • シーラント剤・CO2ボンベ
  • ツールポーチ

    • バルブ変換器
    • 携帯ポンプ
    • 予備チューブその2
    • 六角レンチ類
    • パンク修理用パッチ
    • タイヤレバー
  • 衣類圧縮袋

    • 小(靴下・下着を入れる)
    • 中(Tシャツ・短パン・タオルの予備)
  • サイクルウェア

    • サイクルジャージ
    • レーパン
    • アームウォーマー・レッグウォーマー
      • ホテル着いてからの観光時にも使った。
    • SPDクリート付きシューズ
  • その他グッズ

    • 補給食
    • 空気圧計
    • 軍手・フロス
      • 走行時はサドルバッグ手前側に入れておくと吉
    • 洗濯用携帯ハンガー
    • サンダル
    • 折りたたみリュック(画像のオレンジ色のもの。走行時はコンパクトに畳める)
    • 洗濯ネット
    • 歯ブラシ・歯磨き粉(宿にもあるが、個人的には使い慣れたもののほうが良いので)
    • メガネケース
    • モバイルバッテリー
    • 鍵2種類(ワイヤーキー・U字ロックキー)
    • USB充電器(mini USB・micro USB・lightningケーブル)
    • ティッシュ
    • 財布
    • フロントライト予備
    • 輪ゴム
    • マスク
    • チェーンルブ
    • 応急処置キット(軟膏類・絆創膏・湿布)

洗濯用携帯ハンガーは、こんな感じでちょっとした小物を干すのに役立った。

f:id:manji602:20170502052223j:plain

バッグ

  • サドルバッグ:APIDURA ドライ サドルバッグ ミディアム

    • 容量14リットル
    • 自転車応急処置グッズ・輪行袋以外の各種輪行グッズ・衣類圧縮袋・軍手、フロス・サンダルはここに入れた。
  • フロントバッグ:mont-bell フロントバッグ

    • リクセンカウルのアタッチメントを付けて脱着可能にしている。これがかなり良かった。「リクセンカウル化」でググると色々と情報が出てくるので参考にしていただければと。
    • 輪行時にも実は付けられる。これで折りたたみリュックにしまう荷物を減らすことが出来た。
    • 輪行袋とU字ロック、あとは洗濯ネットと充電器周りを入れていた。
  • トップチューブバッグ:TOPEAK トライドライバッグ

    • ワイヤーチェーンとモバイルバッテリーを収納。
  • ヒップバッグ:RS TAICHI RSB270

    • 容量5リットル
    • バイク用品メーカーだったが、使い勝手が良かった。収納力と大きさのバランスが取れている。

走行時

f:id:manji602:20170429112148j:plain

走行時は、サドルバッグとフロントバッグに大半の荷物を詰め、携帯したい荷物に関してはヒップバッグに詰めておくようにしている。サドルバッグ上部にあるビニール袋にはサンダルが入っている。不格好なので、もっとコンパクトなサンダルを見繕って次回以降なんとかしたい。

輪行

f:id:manji602:20170503200234j:plain

輪行時は、折りたたんでいたリュックを展開して、その中にサドルバッグに入れていた荷物とサドルバッグ自体を詰める。 前述の通りフロントバッグは装着したまま輪行できるので、自転車をばらして輪行袋に入れた後に再度装着する。

本編

1日目: 神奈川県川崎市-茨城県古河市

天気

地域 天気 最高/最低気温 降水確率
横浜市 23/12 0%
千代田区 24/11 0%
熊谷市 25/9 0%
水戸市 22/7 0%

走行距離・ルート・獲得標高

84.66km

f:id:manji602:20170505094422j:plain

f:id:manji602:20170505094444j:plain

タイムログ

7:19 自宅を出発し、綱島街道を北上。

7:28 神奈川県を抜け東京都へ。

f:id:manji602:20170430072850j:plain

8:30 日本橋近辺で4号線に乗る。以後、ずーっと4号線。

f:id:manji602:20170430083026j:plain

9:12 ローソン クオール薬局島根一丁目店でピットイン。お茶500ml補給。

9:38 埼玉県草加市に突入。

f:id:manji602:20170430093800j:plain

10:14 ローソン・スリーエフ 越谷神明町店でピットイン。トイレ休憩。

11:01 道の駅庄和でピットイン。新4号バイパスを永遠と走っていた。

f:id:manji602:20170430105932j:plain

日曜日ということもあり何か催し物をやっていた。

f:id:manji602:20170430110426j:plain

お茶と黒豆煎餅、肉巻きおにぎりで補給。

f:id:manji602:20170430110502j:plain

f:id:manji602:20170430110852j:plain

11:43 茨城県五霞町に突入。

f:id:manji602:20170430114335j:plain

12:04 利根川を渡りいよいよ目的地である実家目前に。

f:id:manji602:20170430120430j:plain

12:13 セブンイレブン 古河水海店で最後のピットイン。アイスで補給。

12:46 実家到着で1日目のライド終了。

2日目: 茨城県古河市-福島県西白河郡西郷村

天気

地域 天気 最高/最低気温 降水確率
宇都宮市 晴一時雨 25/11 60%

走行距離・ルート・獲得標高

126.72km

f:id:manji602:20170505094523j:plain

f:id:manji602:20170505094600j:plain

タイムログ

この日は予報が雨ということもあり、早い段階で宿に着きたかった。

日の出出発を目論見4時起きで早めに出発した。

4:50 出発。日の出が4:49ということもあり既に明るかった。

4:55 栃木県野木町突入。

f:id:manji602:20170501045514j:plain

5:39 ファミリーマート 小山八幡町店でピットイン。トイレ休憩。

6:42 ローソン 石橋下古山北原店でピットイン。トイレ休憩。

6:47 宇都宮市突入。ここでおおよそ1/3なので先はまだまだ長い。

f:id:manji602:20170501064711j:plain

6:57 4号線を100km走破。節目の地点。

f:id:manji602:20170501065711j:plain

7:39 ミニストップ 御幸本町店でピットイン。トイレ休憩。

7:57 鬼怒川を渡る。

f:id:manji602:20170501075706j:plain

8:34 セブンイレブン さくら卯の里4丁目店でピットイン。おにぎりとお茶を補給。

9:38 ファミリーマート 大田原野崎店でピットイン。ウィダーインプロテインリポビタンDでパワー注入。

10:23 那須塩原駅に到着。あとは県超えを残すのみとなった。

f:id:manji602:20170501102315j:plain

10:54 セブンイレブン 黒磯バイパス店でピットイン。おにぎりとお茶を補給。

11:20 このぐらいから雨がポツポツ降り始める。最初は小粒だったので無視していたが、次第に雨量がひどくなってきたのでウィンドブレーカーを着用、またフロントバッグにはABCマートの袋をかぶせて簡易的に雨除けをできるようにした。

県超えではちょっとした峠を超える必要があり若干のヒルクライムとなった。とはいえ、都民の森と比較するとそこまで斜度はキツくなく、しかも一定間隔で平地や下り坂で休憩があったため100kmを走った後の脚でもなんとかなった。

12:09 福島県西郷村に突入。この写真を見ると分かるように、この後歩道がなくなっていた。そんな中大型トラックがスピードを落とすことなく何台も走り去っていたので、かなり怖かった。一通り車が捌けたのを見計らって勢いで走行再開し、歩道が復活するところまで駆け抜けた。

f:id:manji602:20170501120913j:plain

12:30 宿に到着し2日目のライド終了。標高が500m近かったのでかなり寒かった。凍えながら輪行袋ロードバイクをしまう。寒くて手がかじかんでいた事もあって50分くらいかかってしまった。

f:id:manji602:20170501123010j:plain

ホテルのチェックインが15時からとなっていたため、一度ホテルにはロードバイクのみ預け、その後昼食を取りに近くの定食屋「赤門新館」へと立ち寄った。

13:56 名物らしいジャンボトンカツ定食を頂いた。後述するがこの時白河ラーメンにしておけばよかったと若干の後悔があった。

ホテルにチェックイン後、温泉に立ち寄ろうと決めていたが場所を調べていなかったので、15時まで目的地をスマホで探しつつ時間を潰すことに。

f:id:manji602:20170501135625j:plain

15:50 ホテルへチェックインを済ませて荷物の整理と温泉に向かうための準備を済ませ、新白河駅へ。矢吹駅に向かう。

f:id:manji602:20170501161317j:plain

16:41 目的地である「観音湯」に到着。事前に調べた情報では矢吹駅から徒歩15分とのことだったが、Google Mapでガイドを出した所なんと30分かかることが判明し、辛かった。このタイミングで、行きは徒歩で向かい帰りはタクシーを呼ぶことに決めた。

f:id:manji602:20170501164305j:plain

17:40 矢吹駅にタクシーで帰還。よく分からないゆるキャラにお出迎えされる。

f:id:manji602:20170501174051j:plain

18:49 新白河駅に戻り、当初入ろうとしていた白河ラーメン店を訪れた所、麺切れで営業終了していた。他に白河ラーメンを提供しているところがすぐ見当たらなかったので、宿近くのイオンに入り豚の生姜焼き定食を頼むハメに。ご飯は東北産だったのでとりあえずそれだけが地元の名産物となった。

f:id:manji602:20170501184935j:plain

夕食を食べた後は、イオンで買い出しを済ませ宿に戻った。雨で泥だらけになったロードバイクのメンテをし、タイヤの空気を調整したりしていた。23時には就寝していたはず。

3日目: 福島県西白河郡西郷村-福島県福島市

天気

地域 天気 最高/最低気温 降水確率
福島市 21/9 20%

走行距離・ルート・獲得標高

91.23km

f:id:manji602:20170505094619j:plain

f:id:manji602:20170505094631j:plain

タイムログ

6:26 宿の部屋から見た景色がとても爽やかだったので記念にパチリ。

f:id:manji602:20170502062639j:plain

7:10 輪行袋からロードバイクを組み立てて出発。

7:33 セブンイレブン 白河バイパス店でピットイン。この日はホテルで朝食が出なかったためおにぎりとソイジョイ、お茶を補給して朝食を取っていた。おにぎりを頬張っている最中に知らないおじさんに話しかけられ、福島市に向かうことを話すととても驚かれた。結婚はしていないのかと言われる(1回目)が、たしかにもうそんな年だよなぁとも思いながら世間話をしていた。

8:07 4号線を200km走破。

f:id:manji602:20170502080750j:plain

8:39 ファミリーマート 鏡石境栄町店でピットイン。トイレ休憩。以後コンビニが2, 3出現した後ぱったりと消え大変な目に遭う。

10:17 日本橋と書いて「ひもとばし」と読む橋を通過。これはなかなかトリッキーだった。

f:id:manji602:20170502101721j:plain

10:22 デイリーヤマザキ 本宮五百川店で2時間ぶりのピットイン。慌ててトイレ休憩を済ませ、羊羹とウィダーインプロテインリポビタンDでパワー注入。やたらとエロ本コーナーの幅が広かった。

11:06 ファミリーマート 大玉大山店でピットイン。トイレ休憩。

11:09 休憩後少し走ると大量の鯉のぼりが準備されていた場所があり、興味本位で撮影。

f:id:manji602:20170502110908j:plain

12:04 道の駅 安達でピットイン。トイレ休憩とお茶の補給、昼食を済ませる。

f:id:manji602:20170502120546j:plain

山菜そばとザクザク汁(二本松市の郷土料理)をいただく。

12:26 昼食を済ませライド再開。ここで福島市に突入。

f:id:manji602:20170502122644j:plain

13:00頃 目的地まで残り10kmを切ったくらいのタイミングだった。車道から歩道に乗り換えようとした際に、段差に乗り上げた衝撃からか後輪のスポークが折れ、ブレ幅が大幅に悪化し車輪がフレームに当たるレベルで悪化。

自転車をひっくり返して応急処置を検討するもどうしようもなく、途方に暮れる。スマホで調べた所4.3km先に自転車屋があるとのことだったのでそこまで押して歩くことに。パンク、タイヤの損傷、チェーンの損傷あたりまでは準備していたがこのトラブルに関しては完全に想定外だった。

事前にかなり準備はしていたが、これに関しては出発前にサイクルショップで軽く点検をしておくべきだったと反省させられる。おそらくではあるが、この日はかなり風が強く横なぐりになることも多かったので、それでスポークにかなりの力がかかっていたのが原因ではないかと推測している。

13:47 セブンイレブン 福島清水町店にピットイン。トイレ休憩。

14:10 調べていたサイクルショップ「ワンズサイクル 南福島店」に到着。すがる思いで自転車を見ていただいたものの、ロードバイクは取り扱っていないため修理は難しいと断られる。2km先にロードバイクを扱う別のサイクルショップがあると教えていただいたので更に押して歩くことに。

14:40 教えていただいた「イシダサイクル」に到着。

f:id:manji602:20170502163549j:plain

見ていただくとやはり修理は不可なレベルで後輪が破損しており、ホイール交換になると伝えられる。あと1日、80kmほど走れれば良かったので高いホイールには交換したくない旨を伝えると、こちらのわがままにも関わらず意向を汲み取って頂き、試乗車の鉄下駄ホイール交換8kでどうかと持ちかけられ、それでお願いをする。首の皮一枚で繋がった。

修理が16:30頃までかかると伝えられ、それまでに宿にチェックインしたらどうかとママチャリまで貸してくださった。本当に助かった。

ママチャリで宿に向かい、チェックインだけ済ませた。途中線路を超える坂がありここがこの日一番の激坂だった(笑)

f:id:manji602:20170502164841j:plain

宿に到着後は「再びイシダサイクルさんに戻るための荷物」と「ロードバイクを受け取った後温泉に向かうための荷物」を整理。一度宿を出て近くのツルハドラッグにて買い物を済ませた後、再びイシダサイクルさんへ向かう。

16:36 無事に修理いただいたロードバイクを受け取る。泣きそうになった。何度も感謝の気持ちをお伝えして店を去る。

f:id:manji602:20170502163536j:plain

16:50 宿に再びロードバイクで戻りかなり遅くなったが3日目のライド終了。急いで輪行袋に自転車をしまい、部屋においた後、予定通り飯坂温泉を目指すことに。

17:50 福島駅に到着、福島交通飯坂線に乗車。

f:id:manji602:20170502174902j:plain

車内には温泉の「ゆ」と書かれた垂れ幕が飾られていた。

f:id:manji602:20170502174915j:plain

18:21 飯塚温泉駅に到着。

18:26 餃子 照井本店に到着。

f:id:manji602:20170502182626j:plain

安倍総理も直近で訪れたことのある名店だった。

f:id:manji602:20170502182914j:plain

名物の「円盤餃子」と日本酒「飛露喜」をいただく。

f:id:manji602:20170502184854j:plain

f:id:manji602:20170502191329j:plain

19:25 共同湯である導専の湯に到着。ここはロッカーのある共同湯だったので、貴重品をもったまま来ていた身としては助かった。

f:id:manji602:20170502192539j:plain

湯に浸かっていると再び見知らぬおじさんから話しかけられる。結婚はしていないのかと言われる(2回目)。何処行ってもこの話題は避けられない模様。いろいろな話をした(させられた)が、利久の牛タンは仙台産ではないというのが一番頭に残った。何故か執拗に「自分のホームページを作って欲しい」と依頼されるが、笑いながら断り、このタイミングで話から抜け風呂を出ることに。

20:27 再び飯坂温泉駅に戻り宿を目指す。

f:id:manji602:20170502202707j:plain

21:00 福島駅に到着、ギリギリで閉店間際のイトーヨーカドーに立ち寄って買い出し、その後宿でサイクルウェアの洗濯と荷物の整理をし、24時ごろ就寝。

4日目: 福島県福島市-宮城県仙台市

天気

地域 天気 最高/最低気温 降水確率
福島市 晴時々曇 26/8 10%
仙台市 19/10 10%

走行距離・ルート・獲得標高

85.23km

f:id:manji602:20170505094645j:plain

f:id:manji602:20170505094656j:plain

タイムログ

6:34 ホテルで朝食。朝からガッツリエネルギーを取っておいた。ホテルではオレンジジュースをよく飲む。

f:id:manji602:20170503063430j:plain

7:34 ロードバイクを組み立て出発。

8:26 サンクス 福島桑折町店でピットイン。トイレ休憩。

9:13 ちょっとした峠越えでこの前後でおそらく宮城県入りしたと思われる。肝心なタイミングで写真を撮りそびれてしまった。峠を下っていくとちょっとした湖畔があったので記念にパチリ。

f:id:manji602:20170503091322j:plain

9:24 4号線300km走破。300km地点のプレートは路肩も狭く、歩道もない場所にあったため撮影を断念した。

f:id:manji602:20170503092435j:plain

9:53 ファミリーマート 白石インター店でピットイン。お茶とアイスを補給。

10:35 ローソン 大河原バイパス店でピットイン。トイレ休憩。

11:42 宮城県仙台市に突入!このあたりから謎のパワーが湧き出て来る。道のコンディションも良かったこともありアウタートップでエンジン全開で進む。38km/hくらいの速度でかっ飛ばしていた。

f:id:manji602:20170503114251j:plain

12:17 セブンイレブン 仙台一高前店でピットイン。トイレ休憩。

12:29 Koboパーク宮城に到着。

f:id:manji602:20170503122808j:plain

12:44 仙台駅到着で最終日のライドが無事に終了。

f:id:manji602:20170503124446j:plain

総走破距離は386kmとなった。400kmには届かなかったが過去最高記録。

f:id:manji602:20170503124626j:plain

13:11 DATE BIKE サービスステーションに到着。仙台駅のクロークが廃止されたので、ロードバイクを預かってくれるところはここくらいかと思われる。預かって貰う前に、折りたたみリュックを展開し荷物を詰め直す。

f:id:manji602:20170503131117j:plain

14:41 炭焼牛タン東山 仙台本店別館へ。この旅の最大の目的であった牛タン定食を食す。最高に美味かった。

f:id:manji602:20170503144915j:plain

16:13 仙台駅入りし、新幹線に乗って帰途に着いた。帰りはあっという間だった。

f:id:manji602:20170503161251j:plain

後編

4日間、疲れはあったものの走り続けて無事に仙台まで自走することが出来た。達成感も大きかったが、以下のような反省点も残ったので次回に活かしたい。

  • 荷物に関して

    • サンダルがサドルバッグに入らなかったので、折りたためるサンダルか靴を見つけたら今後はそれを使うようにしたい。サドルバッグの上にビニール袋に入れてくくりつけるのはちょっと恥ずかしかった。
    • ポケットのかなり小さい短パンを持ってきてしまい、貴重品を入れる場所がなかった。次回はちゃんとポケットが両側にある短パンを持参する。
    • ホテル到着後、身の回りのものをコンパクトにしまえるポーチのようなものがあるとなお良さそう。
  • ロードバイクに関して

    • 事前のメンテナンスが少し不足していた。3日目にホイールが破損したのもその原因の一端にはなっていたと思うので、今後はロングライドに出る前には極力サイクルショップで点検をして貰った方が良い。
    • 2日目、雨が降っている中の峠越えとなったがかなり危険な状態だったので、今後は以下に気をつけつつ走行を続行するか判断するようにしたい。
      • 峠手前の最後のコンビニはどのあたりか見ておく。
      • 峠中にトラブルが発生した場合、歩いてリタイアできる距離にあるか確認する。
      • 天気は少し待てば回復しそうかどうか確認する(宿について少ししたら雨が止んだため)。

色々大変だったが泊りがけのロングライドは他にない楽しさがあるので、このエントリでそれを少しでも感じ取っていただければと。

Javascriptで連想配列のDeepCopy

Object.assign を実装当初利用したものの、Safariでは9以上でないと動かないらしい。

jQuery$.extend を利用するとオブジェクトのマージという形でDeepCopyが出来る。

var src = fetchSrc(); // 何かしらで取ってくる
var dest = {};
$.extend(true, dest, src);

上記の用に記述すると destsrc連想配列がマージされる。 dest 自体はもともと空の連想配列なので、実質 src のDeepCopyとなる。 第一引数に true を渡すと再帰的に階層を渡ってマージするので基本的には true を渡しておいたほうが良さそう。

任意で渡ってきた変数が特定のStructかどうか判定する方法

is_struct みたいな便利メソッドがないようなので以下のように判定する必要があった。 割と面倒だったのでまとめておく。

例として、任意で受け取った引数 argsUser のStructかどうかを判定する。

StructはMapの拡張になっている

まずStructは Mapを拡張した拡張であるので、 is_map(args) がtrueになる。

Structs are extensions on top of maps that bring default values, compile-time guarantees and polymorphism into Elixir.

ref: Structs - Elixir

iex(1)> user_struct = %User{}
%User{...}
iex(2)> string = "test"
"test"
iex(3)> is_map(user_struct)
true
iex(4)> is_map(string)
false

Structは __struct__ というkeyを保持している

In the example above, pattern matching works because underneath structs are bare maps with a fixed set of fields. As maps, structs store a “special” field named struct that holds the name of the struct:

次に、Structの場合は __struct__ というkeyを保持しているので、「MapであるがStructでない変数」の場合は Map.has_key?(args, :__struct) で弾くことが出来る。

iex(5)> map = %{hoge: "huga"}
%{hoge: "huga"}
iex(6)> map |> Map.has_key?(:__struct__)
false
iex(7)> user_struct |> Map.has_key?(:__struct__)
true

__struct__ にはStructの名前が入っている

args.__struct__User であればtrueになるので、あとはこれを比較すれば良い。

iex(8)> not_user_struct = %NotUser{}
%NotUser{...}

iex(9)> user_struct.__struct__ == User
true
iex(10)> not_user_struct.__struct__ == User
false

まとめると

def is_user?(args) do
  is_map(args) && Map.has_key?(args, :__struct__) && args.__struct__ == User
end