かきしま海道

江田島のかきしま海道を走りました。ブルーラインがひかれてからは初めてです。

自宅から呉までは自走。呉からブルーラインに沿って切串を目指します。呉駅の近くにブルーラインの始点があると聞いていましたが見つけられなくてスルー。音戸方面に走っていたら途中からブルーラインが現れました。

音戸の渡し船で対岸へ。

曇り空だった天気も走っているうちにだんだん晴れてきました。

三高港に向かって走っているといつのまにかブルーラインが呉方面の表示に。鹿川で左折するところを直進してしまったようです。西能美島は反時計周りに走り、鹿川から再度コースアウトをして切串方面のコースに復帰しました。

切串から宇品までフェリー。

市内を通って自宅まで帰りました。走行距離は116km。

ANTLR4のパースエラーを捕捉する

文法エラーの時、エラーメッセージが表示されるだけで例外が発生しないので少々悩みました。パーサーにステータスを持っている様子もないなー、など追ってみれば、ANTLRErrorListenerを実装したクラスをパーサーにaddErrorListenerで追加するだけという単純な話でした。

ANTLRErrorListenerを実装。

public class MyErrorListener implements ANTLRErrorListener {
    @Override
    public void syntaxError(Recognizer<?, ?> recognizer,
            Object offendingSymbol, int line, int charPositionInLine,
            String msg, RecognitionException e) {
        throw new RuntimeException(msg, e);
    }
    ...
}

addErrorListenerで追加。

MyLexer lexer = new MyLexer(new ANTLRInputStream("1 + 2"));
CommonTokenStream tokens = new CommonTokenStream(lexer);
MyParser parser = new MyParser(tokens);
parser.addErrorListener(new MyErrorListener());

もっと色々やりたい場合は、ANTLRErrorStrategyを実装、もしくはDefaultErrorStrategyを継承したクラスを書き、setErrorHandlerで登録してやれば良いようです。

石見グランフォンド2014

先週は石見グランフォンドに参加。140kmコースをゆっくり走りました。国東の疲れが残っていたので…。200kmは来年挑戦したいです。

前日は江の川沿いに移動。また機会があれば川の駅あたりから川沿いをまったり走りたいものです。

当日朝は砂浜の駐車場へ。タイヤが砂にはまって動けなくなった車を数台見かけました。

スタート位置は早いもの勝ち。私はゆっくり走るので最後尾から。スタートの順番が回ってくるまで20分程度待ちました。

第一休憩所のそば道場。ショートコースだとそばを楽しむ心の余裕を持てます。

ゆるりゆるりと登り坂を走ります。

わらび餅と洋梨です。

昼食の休憩所となる断魚渓。足がすくみます。

昼食後は江の川沿いを走った後、ロングコースの三瓶山へ行きました。長い登り坂にやられましたが、素晴らしい景色を楽しめて爽快な気分。キャンプなどでまた訪れたいと思いました。

三瓶バーガー脇の休憩所ではチョコバナナが振舞われました。

三瓶へ寄り道したので距離は156km。時間に追われず、のんびりとサイクリングを楽しめました。

ツール・ド・国東 2014

ツール・ド・国東に参加しました。今回は1人での参加です。

前日移動。フェリーからの眺めが気持ち良い。

受付も済ませておきます。参加賞に小型のバッグをもらいました。受付は前日に済ませておくのが吉。

当日は前日とは打って変わって曇り空。参加者は多かったです。

休憩所。今回は引っ張ってくれる先輩がおらず足切りが不安だったので、休憩もそこそこに先を急ぎました。

前半は緩やかな坂道を中心とした山道。天気もだんだんと良くなりました。全体的に急な勾配はなく安定して走れたように思います。ただ向かい風がやたら強い。下りでもスピードが出ないことがしばしばありました。

粟嶋神社で昼食。いちごやたこ焼きなど珍しいものが並んでいました。

後半は海沿いの道。時折アップダウンがありつつ平坦な道が続きます。前半の向かい風に疲労も溜まっていましたが、山道はもうなさそうだったので気は楽でした。

17時ごろゴール。ギリギリ間に合った様子でした。

19時のフェリーは諦め、銭湯で汗を流してゆっくり帰宅しました。

1人での大会参加は初めてでしたが事故もなく無事走りきれました。 運営の皆様、ありがとうございました。

angular.jsのdirectiveでカスタム要素をつくる

directiveを使ってカスタム要素をつくるというのをやってみました。

http://docs.angularjs.org/guide/directive

restrict: "E",

restrictはdirectiveの種類で、'E'は要素を指します。他にも'A'や'C'があり、それぞれ属性とクラスを指します。デフォルトは'A'のようです。'AEC'と指定すれば全てにマッチするようです。

var template = ''
    + '<div class="user">'
    + '  <span class="user-id">{{user.id}}</span>'
    + ...

user要素を置き換えるテンプレートを文字列で組み立ててtemplateに渡していますが、 別のファイルに切り出して、templateUrlでそのファイルのurlを指定する方法もあります。

scope: { user: "=data" },

user要素内で使うデータをscopeで指定します。data属性で渡された値を、user要素内ではuserという名前で扱えます。

controller: function($scope){
    ...
}

user要素内のコントローラも通常と同じように定義することができます。

独自の部品をお手軽に作れて大変便利です。

angular.jsのdirectiveで再帰的なカスタム要素をつくる

ツリーのような再帰的なカスタム要素をつくろうとした場合、素直に書くと、 "RangeError: Maximum call stack size exceeded"が発生します。 angularがテンプレートを再帰的に解析しようとして収集つかなくなるようです。

そのものズバリな解決策が以下のページに書かれていました。

http://stackoverflow.com/questions/19125551/angularjs-understanding-a-recursive-directive

テンプレートのコンパイルの挙動を指定するようです。 ということで自分でもやってみました。

angular.jsのdirectiveでng-popstateをつくる

HTML5のHistory APIでは、pushStateでスタックへ積んだ状態を、window.onpopstateにセットしたイベントハンドラで受け取ることができます。このイベントハンドラをangular.jsで扱いやすいようにng-popstateという属性を定義するという内容です。

app.directive("ngPopstate", function($parse, $timeout, $window){
    return function($scope, $element, $attributes){
      var fn = $parse($attributes["ngPopstate"]);

大文字はハイフン区切りに変換されるようなので "ng-popstate"という属性にしたければ"ngPopstate"という名前にします。

"ng-popstate"属性が指定された要素が$elementに、その要素の各属性が$attributesの値になります。

この例ではbody要素に'ng-popstate="onPopState($state)"'と指定しました。 そうすると"onPopState($state)"がそっくりそのまま$attributes["ngPopstate"]に格納されます。 このままだとただの文字列であり、onPopStateを呼べないので$parseでパースします。

あとは以下のように引数をバインドしてファンクションを呼んでやります。

fn($scope, {
    $state : event.state,
    $event : event
});

オブジェクトで渡している$stateと$eventは、ng-popstateに記述された引数に束縛されます。この例では"onPopState($state)"としてますので$stateの方だけ渡されることになります。