YAMAGUCHI::weblog

海水パンツとゴーグルで、巨万の富を築きました。カリブの怪物、フリーアルバイター瞳です。

Visual Studio CodeでOSSライセンス用の拡張を書いた感想

はじめに

こんにちは、Visual Studio Code界のホエイプロテイン(WPI)です。これはVisual Studio Code Advent Calendar 2016の21日目の記事です。昨日はEbXpJ6bpさんでした。

Visual Studio Codeのリリース以後、ライトユーザーとして便利に使っています。今日は1ユーザーとして便利に使っていたものの、欲しい機能がなかったので拡張を作った話とその感想を書こうと思います。

作ったもの

Visual Studio CodeでOSSライセンス用のLICENSEファイルの作成、およびライセンスヘッダの挿入を簡単に行う拡張である "licenser" という拡張を作りました。

インストールは次のとおりです。

> ext install licenser

拡張を作った動機

Visual Studio Codeを使い始めるまでは、コードを書くときはEmacsVimAndroidのコード書くときはAndroid Studioを使って書いてたわけですが、いろいろ始めから設定されてるという理由でVisual Studio Codeを使い始めました。使いはじめてこれは良いなと思ったのはこんな感じ。

  • IDEとエディタの中間のような操作感
    • IntelliSense由来のポップアップ補完の優秀さはさすがMSですね
  • 設定の容易さ
    • JSONを1つ設定しておけば良い簡便さ。設定中もオプション項目は補完が効くのは便利。
  • 公式サイトでの拡張の管理。
    • 3rd partyではなく拡張が公式にホストされているのは安心感がある。バージョンが上がりエディタ内でも管理出来るようになったのが楽。
  • 充実したカラースキーム
    • なんかオシャレっぽくできてよい
  • 拡張がTypsScriptまたはJavaScriptで書ける
    • 見た目だけでいえばAtomに似てるわけですが、拡張を書くためだけにCoffeeScript覚えたくなかったので、他の用途でも使えるTypeScriptで書けるのは良かった。
  • デフォルトで結構戦える
    • 拡張をまったく入れなくてもメジャーどころの言語を使うときはシンタックスハイライトや補完も大体問題ないので良い

しかしながら、欲が出てくるもので、IDEっぽく使えるならもっとIDEっぽい機能がほしいなと思うようになり、その中でもダントツにほしく感じたのはOSSライセンス関係の機能でした。公式で提供しているかとも思ったのですが、ありませんでした。また3rd partyで公開されていた2つも、こんな感じで求めたものではありませんでした。

  • LicenseHeader - Visual Studio Marketplace
    • ライセンスヘッダの追加のみしか行ってくれない上に、MITライセンス決め打ちなので自分の用途に合っていない。またC言語スタイルのコメント以外は使えない。
  • License Injector - Visual Studio Marketplace
    • ライセンスヘッダの追加のみしか行ってくれない上に、MITライセンス決め打ちなので自分の用途に合っていない。

これらの拡張にContributeしてもよかったのですが、大元のコードが非常に短かかったので結局はじめから書き直すことになると思い、練習がてら自分で書いてみることにしました。

拡張を作った感想

豊富な公式ドキュメント

さすがはMSだなあと思ったのは、まず提供されているドキュメントの量と質。公式ドキュメントにチュートリアルもあり、手元で少し動かすだけで簡単に動かすことが出来ました。例えばこのあたりから読みはじめて手を動かすだけでした。

また実際に自分の拡張を書く際にもAPIリファレンスが整備されていたので、ドキュメントとエディタの補完だけですんなり書くことが出来ました。

code.visualstudio.com

Yeomanを使ったボイラープレートの提供

ドキュメントにも書いてありますが、Visual Studio Codeの拡張を作る際には決まった形のディレクトリ構成でコードを書き始めることになります。自分で用意するのは面倒ですが、Yeomanのボイラープレートが用意されてるのですぐに拡張を書き始めることが出来ます。楽ちん。

$ npm install -g yo generator-code
$ yo code

標準でのテスト環境の提供

作った拡張がうまく動作しているかを確認するのも簡単で、デバッグタブからデバッグ実行を行うことで、バニラ環境に開発中の拡張を入れただけのVisual Studio Codeが立ち上がり、そこで開発中の拡張の振る舞いを確認することができます。ログは開発を行っている側のウィンドウで確認できるので、特に複雑な設定をしなくても十分な検証ができます。便利。

拡張の公開用ツールの提供

作った拡張を一般公開したい場合には、パッケージングをして中央レポジトリに登録するわけですが、それも専用のNode.js製ツールを使ってコマンド一発で公開ができます。

$ npm install -g vsce
$ vsce publish

最初の1回目はもろもろと設定が必要ですが、それも公式ドキュメントに細かにスクリーンショット付きで記述してあるので、迷うこと無く設定ができました。

今後の予定

とりあえず日常用途で使う分には便利に使えるようになったので、細かなアップデートが出来ればなあと思っています。たとえば

  • メントスタイルを1行コメントと複数行コメントの両方を選択できるようにする
    • いまはライセンスヘッダは、1行コメントがある言語はすべて1行コメントで、複数行コメントしかない言語はそちらを使って書くようにしている。
  • shebangがある場合は2行目からライセンスヘッダを書くようにする
    • 対応したはずなんだけどうまく動いてないようなのであとでやる
  • プロジェクト内のファイル全体に一気にライセンスヘッダを挿入する
    • あんまり自分が必要になってないのでやってない

おわりに

Visual Studio Codeは安定して開発が進んでいる印象で、バージョンが上がる度にデフォルト機能が良くなっているのも好印象です。個人的には、現状の挙動だと、文字を入力する度にフックを入れるようにするとどんどん動作が重くなってしまうので、補完系のツールは気をつけないと折角の軽い動作が損なわれてしまう可能性があるということで、その辺の改善が行われていくと良いなあと思っています。

明日は @albatrosary さんです。

GoのASTを使ってパッケージのメンテナンスを考える

はじめに

こんにちは、Go界の骨盤職人です。buildersconにmattnさんがいらしていたということで生mattnさんに謁見したかったのですが、諸事情でこの日程はどうしても都合がつかず、参加できなかったことが非常に残念でいまでも悔やんでいます。

さて、Goは安定して開発が進んでおり、いまは安定バージョンが1.8にもなろうというところです。セルフホスティングも1.5で達成し、GCの高速化も順調に進んでいる中、いまだにGoの問題として挙げられるものとして「パッケージバージョンの管理」があります。今日はその辺の話をしようと思います。

TL;DR

go パッケージを使って、自分たちが書いたコードが依存してるパッケージを明らかにし、依存先パッケージの更新に追従していこう。

前置き

以下の話はGoをプロダクションで中規模〜大規模に利用している環境を想定しており、細かな閉じられたパッケージのみを開発している状況は想定していません。(そのような状況であれば既存のパッケージ管理ツールでも運用可能だと思っている)

背景

現在Goのバージョン管理には公式ではGo 1.5からvendoringがあり、3rd partyなものとしては gbgodepglide などがあります。すでに1.8にもなろうとしているのに、なぜ公式がいまだにパッケージのバージョン管理のサポートを暫定的な措置であるvendoringでしかサポートしていないのか、その理由は公式ドキュメントのFAQから垣間見ることが出来ます。

"Go get" does not have any explicit concept of package versions. Versioning is a source of significant complexity, especially in large code bases, and we are unaware of any approach that works well at scale in a large enough variety of situations to be appropriate to force on all Go users. What "go get" and the larger Go toolchain do provide is isolation of packages with different import paths. For example, the standard library's html/template and text/template coexist even though both are "package template". This observation leads to some advice for package authors and package users.

Packages intended for public use should try to maintain backwards compatibility as they evolve. The Go 1 compatibility guidelines are a good reference here: don't remove exported names, encourage tagged composite literals, and so on. If different functionality is required, add a new name instead of changing an old one. If a complete break is required, create a new package with a new import path.

If you're using an externally supplied package and worry that it might change in unexpected ways, the simplest solution is to copy it to your local repository. (This is the approach Google takes internally.) Store the copy under a new import path that identifies it as a local copy. For example, you might copy "original.com/pkg" to "you.com/external/original.com/pkg". The gomvpkg program is one tool to help automate this process.

The Go 1.5 release includes an experimental facility to the go command that makes it easier to manage external dependencies by "vendoring" them into a special directory near the package that depends upon them. See the design document for details.

ここにあるように、そもそもの思想として「パッケージ管理は一筋縄ではいかない」「パプリックで公開しているものは作者は依存パッケージのアップデートに追従すべき」というものがあり、Googleが実際に行っている方法として「破壊的変更が心配ならローカルのレポジトリにバージョン固定でコピー」をおすすめしています。(この思想がvendoringにも反映されていると見ていいでしょう)

ローカルにパッケージをコピーすればひとまずバージョンは固定できますから、オリジナルで破壊的変更があってもローカル(個人なら手元、会社で使っている場合は社内)ではビルドが壊れないので安心です。またローカルでバージョンを固定しておくことで他のプロジェクトがそのパッケージを利用する場合にも同一のバージョンを利用しているという安心感があります。実際に、1パッケージ1バージョンを維持することの重要性は今後のパッケージ管理のロードマップでも語られています。

とはいえ、オリジナルとローカルのインタフェースの差分が大きくなればなるほど追従が難しくなります。たとえば外部パッケージAをローカルに保存し、それ依存したローカルパッケージB、Cを開発している場合、Aから破壊的変更があったバージョンA'に更新すると、BとCの作者は壊れないように追従しなければいけません。さらにB、Cに依存したパッケージDの作者はさらに追従しなければいけません。またBとCがA1, A2とAの異なるバージョンに依存している場合にも、どちらを優先すべきかなどの問題が発生します。 このような連鎖的な依存関係はよくあることですが、製品規模が大きくなった場合にこのような変更にどのように追従していけばよいのでしょうか。

体制

一例としてGoogleの例を挙げます。ACMGoogleのソフトウェアエンジニアが社内での開発体制を紹介した記事でも語っていますが、Googleではサードパーティーライブラリ(社内で開発していないもの)は特定のディレクトリ以下にスナップショットを取り特定のバージョンを利用するようにしています。

そのスナップショットのバージョンを上げるとなると、それに依存して製品を作っている人々は対応をしなければいけないわけです。次の引用がまさにその状況を説明しています。

This model also requires teams to collaborate with one another when using open source code. An area of the repository is reserved for storing open source code (developed at Google or externally). To prevent dependency conflicts, as outlined earlier, it is important that only one version of an open source project be available at any given time. Teams that use open source software are expected to occasionally spend time upgrading their codebase to work with newer versions of open source libraries when library upgrades are performed.

サードパーティーライブラリのバージョンを上げるときは依存した製品の開発責任を持つ人々が同じタイミングで製品の動作保証をするように対応するわけです。

Goをメインに使って開発を行う場合に、このような体制をどのように構築したら良いのでしょうか。体制とまではいかずとも、このような依存関係を常に意識する簡単な方法はないでしょうか。

パッケージの依存関係をGoの抽象構文木(AST)から知る

長い前置きとなりましたが、ようやく本題です。Goでは標準パッケージ内に go パッケージがあり、Goのソースコードそのものをなるべく扱いやすくできるようになっています。Goの利点として語られるところにIDEに頼らずとも、標準ツールやサードパーティーツールと連携させることで、VimEmacsVisual Studio Code等々のエディタでも高い生産性を発揮できるというものがありますが、それらのツールもこの go パッケージを利用して作られています。go パッケージの操作の簡易性は日本でも多くの方々がすでに良い記事を書いてくださっているので説明はそちらに譲ります。(記事のリンク等は参考の節にまとめました)

さて、go パッケージの中にはサブパッケージとして go/parser があり、これを使うとカジュアルにGoのソースコードをASTにしてくれます。実際にどれくらいカジュアルか、あるディレクトリ配下のソースコードを全部パースするコードを書いてみます。

import (
    "go/parser"
    "go/token"
)

fset := token.NewFileSet()
pkgs, first := parser.ParseDir(fset, path, nil, parser.ImportsOnly)

以上です。驚くほど簡単です。さらに go/parser は用途によりパースの内容を定数で変更できます。

parser.Mode で定義してあるのですが、デフォルトの 0ソースコードすべてを解析します。それ以外の用途のためにいくつかのオプションが用意されています。ドキュメントを見ると解説付きでわかりやすく書いてあります。

const (
        PackageClauseOnly Mode             = 1 << iota // stop parsing after package clause
        ImportsOnly                                    // stop parsing after import declarations
        ParseComments                                  // parse comments and add them to AST
        Trace                                          // print a trace of parsed productions
        DeclarationErrors                              // report declaration errors
        SpuriousErrors                                 // same as AllErrors, for backward-compatibility
        AllErrors         = SpuriousErrors             // report all errors (not just the first 10 on different lines)
)

今回は依存しているパッケージを明らかにすることが目的なので、 ImportsOnlyimport 文までを読めば事足ります。先ほどの parser.ParseDir でパースすると、戻り値の pkgs にそのパッケージを構成するすべての情報が入っています。これを解析したASTのルートと考えていいでしょう。

ASTが手に入ったので、次はこれをいろいろと辿りながらいろいろと工作をしていきたくなるわけですが、「木構造を辿る」というような計算機科学でよく出てくる課題のようなプログラムを書かないといけないかというと、そんなことはありません。おあつらえ向きの関数が用意されています。

func Walk(v Visitor, node Node)

Walk という関数名は見たことがありますね。そうです、これは filepath.Walk のように、ASTのルートとWalkのための関数を渡してあげるとあとはよしなに深さ優先探索でASTを辿ってくれるという関数です。ASTの各ノードは次のように定義されています。

type Node interface {
        Pos() token.Pos // position of first character belonging to the node
        End() token.Pos // position of first character immediately after the node
}

このインターフェースを実装した構造体が各ノードになっているわけです。各構造体の定義は go/ast のドキュメントを参照してください。

さて ast.Walk に渡す ast.Visitor ですが、これは適当にそのインターフェースを満たす構造体を宣言するだけです。今回のサンプルでは次のように実装しています。

type packageVisitor struct {
    imports []string
}

func (p *packageVisitor) Visit(node ast.Node) ast.Visitor {
    if node != nil {
        switch n := node.(type) {
        case *ast.ImportSpec:
            is := (*ast.ImportSpec)(n)
            if is.Path != nil {
                p.imports = append(p.imports, (*is.Path).Value)
            }
            return p
        default:
            return p
        }
    }
    return p
}

これも実装が非常に素直です。Visit はノードに着くたびに呼ばれるので、その都度、ast.Node の実際の型によって処理を切り替えてあげるだけです。今回は import の中身だけみたいので、ImportSpecの場合だけ処理すればよいでしょう。さて、つらつらと説明してきましたが、この辺で簡単にサンプルを置いてみます。

もうちょっといろいろやろうと思ったんですが、とりあえずはここまで。この example ディレクトリ内の main.go をビルドしてそのディレクトリで実行すると repos.json 内に書いてある3rd partyパッケージが依存しているパッケージがすべて羅列されます。試しに実行してみると

% ./example
[Processing]: github.com/simeji/jid
[Done]: github.com/simeji/jid
/tmp/src/github.com/simeji/jid :
     "bytes"
     "github.com/bitly/go-simplejson"
     "github.com/nsf/termbox-go"
     "github.com/pkg/errors"
     "github.com/stretchr/testify/assert"
     "io"
     "io/ioutil"
     "os"
     "regexp"
     "sort"
     "strconv"
     "strings"
     "testing"
/tmp/src/github.com/simeji/jid/cmd/jid :
     "flag"
     "fmt"
     "github.com/simeji/jid"
     "github.com/stretchr/testify/assert"
     "os"
     "testing"
...

と、つらつらと雑な感じでつらつらと依存しているパッケージが羅列されます。このサンプルでは一段下までしかやりませんが、go getすると依存パッケージはすべて獲得するので、取得したパッケージを入力にして再帰してあげればすべての依存ツリーを作成することが可能です。(実際の go get の実装ではそのようになっています

先にあげたサンプルはちょろちょろと書きなぐっただけのものですが、ほんの少しの手間でパッケージの依存を明らかにすることが出来ます。開発中のパッケージのオーナー情報と依存パッケージの関係を紐付けておくことで、通知などを行うこともできるでしょう。

おわりに

ということでパッケージ管理の一例を紹介し、それに関連してASTを使った簡単なツールの作成を行ってみました。正規表現reflectgo generate 使っても強力なツールを作ることができますが、ASTを使うことでより強力なツールが作れるようになると思います。冬休みにぜひ試してみて下さい。

参考

健康に気を遣う歳になってしまったので筋トレを始めた

はじめに

こんにちは、BCAA大好きマンです。このエントリーは pyspa Advent Calendar 2016 の12日目の記事です。昨日は @nikuyoshi のエントリ でした。「2016年に買ってよかったもの」「今年1年海外旅行・出張で印象的だったこと」「あなたの知らない @shiumachi」「統合思念体pyspaの実態」などのタイトルの中から、今年1年大きな変化があった健康への気遣いに関する話を書こうと思います。特にオチはありません。

私という人間は「酒を飲む」ことが好きな質で、大学の頃から20代前半までは合法的な高テンション導入剤として、20代中盤は友人と時間を過ごす口実として、20代後半から30歳はうまいものを食べに行ったり仕事上会いたい方を誘う口実として「飲みに行く」という行為を積極的に行っていました。家では単純に良い心持ちになるためだけに、毎日晩酌をしていました。

ことの始まり

2015年後半〜2016年1月

普段、ウイスキーをストレートで飲むかビールを飲むことが多かったのですが、よりカジュアルに飲酒をしたいと思うようになり、家でハイボールを飲み始めるようになりました。ハイボールは割る炭酸の量によってアルコール度数を変更でき、爽やかに口当たりもよくグイグイ飲めることからどんどん酒量が増え、1日に1L以上飲む日も珍しくはありませんでした。そのうち、750mlの瓶を買うのが面倒になり、4Lペットボトルのサントリー角を常備するようになり、気がつけば完全に軽度のアル中になっていました。

2016年1月〜2016年5月

すっかりウイスキーを家で飲む習慣が板についたころ、AMPプロジェクトのリリースなどもあり、家で酒を飲みはじめる時間が遅くなっていきました。会社と家で仕事をする時間が長くなり始めた時期と重なって、会社と家、それぞれで使っていたキーボードが狭く感じる頻度が高くなっていきました。そんな折にちょうど @nippondanji さんからErgoDoxを紹介してもらう機会を得た あと、 ErgoDox EZ というフルアセンブリのErgoDoxを知り、購入しました。もともと会社でも家でもエルゴノミクスキーボードを使っていたため、肩こりもほとんどなかったのですが、ErgoDoxを使い始めてからは、肩まわりを定期的に伸ばす程度でまったく肩こりがなくなりました。

長時間のデスクワークを快適に過ごせる環境が会社にも家にもできたことで、家でも諸プロジェクトの都合で本社の時間に合わせて仕事する時間が増え、業務に支障が出ない程度にハイボールを飲みつつ、休日はダラダラと映画を見ながら家で朝から酒を飲むという自堕落な生活をしていました。

また4月頭と5月末にはシンガポール出張と本社出張をし、たまにしか会えないと同僚と情報交換や近況報告をしつつ、無事イベントを終えたことをねぎらい酒を交わすという日々を過ごしました。出張中はどうしても外食が多く、高カロリーな食事が増え、そのダメージは気づかぬところで体に影響を与えていたのでした。

気づきと変化

2016年6月〜8月

肩への負担がなくなり「これでまだまだデスクワーク起因の身体的支障は回避できそうだ」などと思っていた折、ふとデスクワークをしていた際の自分の腹を見てみると、目を疑う腹の肉の膨らみがあることに気付き、慌てて体重計に乗ってみると78kgを超えていました。身長は180cmあるものの、社会人になって以来最重量を記録したことに狼狽しました。2年前には運動量は変わらずとも70kg前後で安定していたので慢心していたことを思い知り*1、なにか始めなければととりあえずジョギングを週に1回程度始めました。

しかし、この腹は生半可なことではどうにもならないと思い、エンジニア界の花山薫こと握力王子新沼氏(以下「団長」)に肉体改造の相談をしました。開口一番「今気づいてよかったですね。あと数年後ではかなりリカバリーが効かない状態になっていたと思います。」と言われ、覚悟を決めジムに通い始めました。ジムに通うのは大学のころに真面目に運動をしていたとき以来。とりあえず過去にやっていたトレーニングをもう一度やってみたけれども、まったく体が動かずあらためて自分が置かれている状況を認識し、大学1年のころにジムに初めて行ったときと同じように体を慣らしていくことからはじめました。

団長にトレーニングメニューと食事へのアドバイスをもらいつつ、なるべく空き時間を作り出来る限りジムへ行くようにし、特に6月〜7月は週5日はジムへ行き基本的なメニューをこなしていました。6月にオランダ出張があったものの、プッシュアップバーを持っていき、ホテルでの腕立て伏せは欠かさないようにしていました。

この頃には炭水化物はトレーニングでバテないように摂る程度に抑えるようになり、蛋白質メインの食事になっていきました。またサラダもブロッコリー中心となり、これまでしていたような「お腹いっぱいになるまで食べる」ということも減っていきました。と同時に、酒を飲むことがめっきり減り、家で晩酌することもほぼなくなっていきました。*2

2016年9月〜10月

スタートダッシュで月に2kgずつ体重が減っていったのですが、72kgで停滞。トレーニングメニューを変更し、上半身2日、下半身1日の3日間のあと1日オフというルーチンに変え、食事の内容も脂質を意識しだしました。同時にサプリメントも混合プロテインだけだったものを、BCAAとマルチビタミンも摂るようにし、継続的にトレーニングを行える環境を整えていきました。

また数ヶ月筋トレを続けてきた影響が良くも悪くも体に現れ始めたのもこの時期です。良い影響としては、大胸筋が目に見えて大きくなり、上腕三頭筋も明らかに太くなり、また広背筋、僧帽筋といった背中の筋肉も発達し、Tシャツを着たときのシルエットがだいぶ変わり始めました。悪い影響としては、筋肉の張りがなかなか取れなくなり、テニスボールでの刺激でもなかなかほぐれなくなったため、ランブルローラーやストレッチポールを導入し始めたのもこのころです。

毎日コツコツとトレーニングとケアを続けた結果、バルクを維持しつつも少しずつ体重が落ち始め、調子が良くなり始めたのですが、ここで10月末にロンドン→ニューヨークの2週間の出張となってしまいました。ホテルのジムに週2回程度行くようにはしたのですが、やはり出張で外食だらけになるといままで意識していたような食事が摂れず、体重も73kg程度まで戻してしまいました。

ブレイクスルーを求めて

2016年11月〜12月

帰国したものもつかのま、11月半ばにまた本社出張が入ってしまい、11月はこれまで行っていたようなリズムでのジムトレーニングができなくなりました。トレーニングしたいときに出来ないということがどれだけストレスかを実感させられました。と同時に、たとえジムに行けなくても出来る限りのトレーニングを行うことの必要性を強く感じるようになりました。11月はあまりジムに行けなかったものの、時間が空いたときの腕立て伏せやスクワットなどでトレーニングを維持したおかげで、11月末にトレーニングのルーチンが再開したときにも負荷を下げることなく行うことが出来ました。

この時期から食事内容を更に意識するようになり、脂質を極力削り、プロテインも混合プロテインからWPIに切り替えました。食事で摂る炭水化物も基礎代謝を維持する程度のもののみにし、トレーニングのためのグリコーゲン確保のためにトレーニング中にCCDを摂取するようにし、トレーニング1時間前のおにぎりなどは辞めました。

また偶然ベテランパーソナルトレーナーに相談する機会を得、骨盤が開いているとの指摘をいただき、やはり骨格と姿勢の矯正が必要であることを強く意識しました。結局筋トレは骨格に対して正しく筋を動作させないと望んだ結果が得られないということは、ここ半年での実感だったので、骨盤の矯正は目下の課題です。団長いわく「2014年ベストプロダクト」であるところの「骨盤職人」を、件のベテランパーソナルトレーナーもおすすめしていたので、すぐさま購入し毎日腰から臀部をほぐしています。

今後

現状は71kg台中盤を上下していますが、コツコツお腹の脂肪は削れているように思います。いまは学生の頃よりも良い体格になっているので、確実に結果は出ているのでしょう。筋トレを半年続けて感じたのは、正しく続けていれば結果は出るということ、そして継続するためにはそもそもの肉体のメンテナンスをおこならないことが大事であるということでした。また「ただ体重が落ちれば良い」というような闇雲なやり方でなく、科学的なアプローチで何を摂取すべきかなどを考えながら食事のバランスを極端なものにしないように頭を使うのは楽しい作業でもあります。

これからはどんどん体が動かなくなったり、健康診断の結果が芳しくなかったり、といったことが容易に想像されるので、できるだけの抵抗はしていきたいです。特にデスクワークが多い人間だと、姿勢が固定されることは必至で、これは本当に悪影響しかありません。呼吸が浅くなったり、肩甲骨や腰や臀部が硬くなったりと、毎日緩やかに自分を締め付けているようなものです。机、椅子、キーボード、マウス等々をもろもろこだわってはいるものの、やはり体を動かして直していかないと今後まずいことになる、という危機感はジムに行き始めてからより強く感じるようになりました。

2017年も引き続きトレーニングを続けながら、筋肉量を維持しつつ、70kgを割れるようにコツコツ続けていけるようにしたいものです。

明日は太一さんです。

おまけ

サプリメント

いままで試して良かったサプリメントはこんな感じです。Amazonのリンクなのは、単純に他のECサイトで埋め込みが出来ないから。海外製品の価格はAmazonだとかなり高いので注意。

ケア

  • 骨盤職人

    ペルビス 骨盤職人 PV01

    ペルビス 骨盤職人 PV01

    地方の温泉宿にありそうなフォルムをしているけれど、侮ってはいけない。これのおかげで本当に腰や臀部が毎日ほぐれるようになった。筋肉が固まると血行が悪くなり余計に筋肉の動きが悪くなり、さらに関節が稼働しづらくなるなどどんどん悪循環となるので、骨盤職人のようなケアは絶対に必要。

  • ストレッチポール

    肩甲骨まわりから腰回りなどを程よく緩めてくれる。寝る前にストレッチポールで体を動かすようになってから、より熟睡できるようになった。純正品のリンクを貼ったけれど、類似品が低価格で出ているのでそれを買っても同様の効果は得られると思う。

  • ランブルローラー

    前鋸筋、小胸筋、前脛骨筋、菱形筋など、骨盤職人でほぐすのが難しいところはこれでほぐしています。見た目通りかなりほぐれる。これもストレッチポールと同じく類似品でも同様の効果は得られると思う。こういうものを筋肉に当ててみて激痛が走るようなら少なからず状態は良くない。普通筋肉を押して痛いことは筋肉痛以外ありえないので。家に1個これを置いといて、背中をコロコロするだけでも日々の背中周りの疲れにだいぶ効果があると思う。

*1:老化は線形ではなくステップ型に起きる、ということも身をもって認識しました。

*2:ラーメンとカレーは2大麻薬なので、この頃から食べることを控えるようになりました。カレーは最近機内食と昼食で1回ずつ5ヶ月ぶりぐらいに食べて、ラーメンはここ半年食べてません。不思議なものでラーメン断ちをしたら、次に食べるラーメンはせっかくだから美味しいところがいいと思うようになり、結果としてなかなか美味しいラーメン屋に遭遇できず、ラーメンから足が遠のいていきました。

スペイン旅行記

はじめに

Hola!! 去年のイタリアに続いて、今年は9/19-27という日程でシルバーウィークを活用し、スペインに旅行に行ってきました。めったに更新されなくなったこのブログを更新するためにも旅行記を残そうと思います。去年のイタリア旅行記はこちら。

旅程

今回の旅行ではスペインの3都市、バレンシアバルセロナ、サンセバスチャンを旅してきました。日程は9/19-27の7泊9日。バレンシアからバルセロナは鉄道、バルセロナからサンセバスチャンはビルバオを経由して飛行機とバスでの移動です。

都市 日程
バレンシア 9/19-20
バルセロナ 9/20-23
サンセバスチャン 9/23-26

気付きと感想

ただ感想見るよりは写真があったほうがわかると思うので、アルバムを置いときます。

全体として

  • 朝、日が昇るのがすごく遅い。7時になってもまだ夜明け前。よく考えると当たり前で、スペインのタイムゾーンヨーロッパ中央夏時間で、フランスはおろか、ドイツやスウェーデンとまで同じ時間帯。同じ時間帯のなかの一番西端なので時間帯が同じだったら当然日の出時刻は遅くなる。現地時間から2時間引いて考えるとなんとなく感覚が合う。
    • スペインは夕食の時間が21時くらいからと遅いけど、それも日の入りからの時間で考えたら結構普通だった。
  • 英語は思った以上に通じなかった。イタリアに行ったときはそれほどまでではなかった記憶がある。
    • あいかわらずGoogle翻訳は素晴らしい。(後述)
  • バレンシアでもサンセバスチャンでもビーチではトップレスになる女性が多い。特にご年配の女性のトップレス加減には貫禄すら覚えた。
  • 施設の見学はオンラインで事前に入館チケットを買っておくのが吉。
  • Google Mapsは今回も最高に役にたった。
    • 飲食店の保存、現在地からの移動時間、お店の開店時間などが見られるのが良い。特にスペインはシエスタがあったりしてお店の開店時間がまちまちなので超重要。
    • バス、電車、トラム、地下鉄、ケーブルカーなど全部出て来るのが素晴らしい。
  • チップはイタリアと同じように満足したときに払う、という雰囲気。5%くらいで良い。
  • バイルネットワークは概ね良好。行った3都市では4G入った。ただ建物に入ると結構な確率で電波なくなった。
  • 街中に宝くじ(ロト)売り場が結構あった。
  • スペインなのでZARAがめっちゃ多い。メインのZARAだけでなく、ZARA HomeZARA Kids、また姉妹ブランドのStradivariusやMassimo Duttiなども多い。

バレンシア

  • 英語がほぼ通じないと思っていい。ヨーロッパに行ってここまで英語が通じなかったのは初めてだった。ヨーロッパといえどどこでも英語が通じるわけではない、というのを初めて肌で感じた。
  • 街灯はネオン。夜の散歩は雰囲気があって良い。
  • Estació del Nord(バレンシア北駅)そばのPlaza de Toros de Valencia(闘牛場)は博物館が併設で、闘牛をやっていないときは闘牛場の中に入れたりとして楽しい。闘牛をやっていないときの入館は€2と大変お安い。

バルセロナ

  • 結構栄えてる。地下鉄やバスは活動時間に合わせ、日付が変わった後でも運行している。
  • バルセロナを移動する際にはTMBのT-10(10回回数券)が得。地下鉄、バス、トラム、電車が結構な範囲乗れる上に、1時間15分以内なら乗り換え無料。
  • サグラダ・ファミリアでエレベーターがいきなり故障して生誕の塔に登れなくなった。しょうがないので翌日に受難の塔に登る予約をして、再度チャレンジした。
  • Camperはスペインのブランドだけあって日本で買うより断然安い。おまけに免税も効くのでスペインで買うのがお得。
    • 前にイギリスでCamper買ったときも同様だったので、ユーロ圏で買うのが良い、という話かもしれない。
  • 英語はバレンシアよりは通じるが、理解はすれども話せないという人が多い。危機感を感じるのでレストランの注文くらいは覚えて片言で話せるようにした。
    • 数字、「おいしい」、「ありがとう」、「会計をください」、「いくらですか」、お気に入りの料理の固有名詞など
  • ゴシップ地区はセレクトショップ的なおしゃれなお店が多い。古い町並みなので中心部と違った風景が楽しめて良い。
  • ピカソ美術館ではピカソが15歳くらいまでは凄くアカデミックな写実的な作品を主体として描いていたことがわかる。

サンセバスチャン(ビルバオ

  • ここもバレンシアと同様英語はほとんど通じない。
  • Feelfree Rentals というAirBnBの物件保有と掲載を自分たちでやってるようなサービス経由でアパートを借りたが、玄関のドアの鍵が全然開けられない。どうやらスペインの古い建物はほとんどそうで、みなドアの開け方のコツをそれぞれに習得しているらしい。昔の日本みたいだ。
  • そこら中でピンチョスが食べられるので、食べ歩きしたい人にはバレンシアバルセロナ以上におすすめ。
    • 個人的なおすすめのお店(カッコ内はおすすめメニュー)は Borda Berri(牛頬肉の煮込み、ボンバ、リゾット)、Taberna Gandarías(牛頬肉の煮込み、ピンチョス全般)、Txuleta(Tボーンステーキ)、La Cuchara de San Telmo(フォアグラ、リゾット)、Atari Gastroteka(牛頬肉の煮込み)、Ganbara(ポルチーニ茸炒め)
  • サンセバスチャンのビーチはこの時期は入るには冷たい。15:30くらいにあるとようやく頑張ってはいれるくらいの水温になる。
  • 日曜日は店がほとんどやっていない。人もほとんど外にいない。ピンチョス屋のみやってる。
  • 子供が夜遅くまで外で遊んでる。しかも親の監視がない場所で子供だけで遊んでたりする。乳飲み子を12時過ぎまで連れ歩く家族も結構いた。
  • 免税のスタンプをもらう方法が初見殺し。(後述)

細かなTips

インターネット予約

どこの観光地でもそうだけれど、入館が必要なところは事前にインターネット予約したほうがいい。

SIMカード

イタリアの旅行のときと同様に、スペインでも相変わらず現地でスマホが活躍した。やはり現地SIMを利用できるSIMフリー端末を持っているのは便利である。

今回はいくつかのキャリアの選択肢はあったけれど、最初の訪問地のバレンシアでのホテルに近かったOrangeでプリペイドSIMを購入。2GBと30分のフリーコールで€20。1ヶ月有効で足りなくなったらSMSでデータ容量の追加も可能。

バレンシアバルセロナ、サンセバスチャンの3都市を訪問したが、どの都市でも街中では常に4Gが利用でき、速度も特に問題なかった。店内に入ると不通になることはあったが、Google翻訳などの辞書を事前にダウンロードしておけば特に問題にはならなかった。

Google翻訳

今回も相変わらず高精度な翻訳で本当に役に立った。話者が多いこともあり、前回の旅行で利用したイタリア語→英語の翻訳よりもスペイン語→英語の翻訳のほうが精度が高い。 どのような結果になるかは次の画像を見てもらったほうが早いと思う。看板やレストランのメニューなど、様々なところで役にたった。

ビルバオの免税スタンプについて

今回は帰国に際しビルバオ空港からシャルル・ド・ゴール空港で乗り継いで日本に帰ってきた。スペインということで地元のブランドであるCamperの靴を買ってきたが、免税適用が可能なため、ビルバオ空港で免税のスタンプを取得する必要があった。ただこのスタンプの取得が完全に初見殺しな上に日本語の情報がネットで見つからなかったのでここに残しておく。今回の方法は免税対象品を飛行機の預入荷物の中に入れたい場合。

  1. まず最初にチェックインカウンターの裏側にある手荷物検査所のエリアの近くに行く
  2. その辺にいる警備員に「免税のためにスタンプがほしいのでその手続をしてほしい」と頼む
  3. するとその警備員は「免税書類を提出して、免税対象品を見せろ」と聞いてくるのでその通りにする
  4. 警備員が免税対象品を確認すると、免税書類を持っておもむろにセキュリティゾーンの方に去っていくので待機する
  5. 自分の代わりにスタンプを取得した警備員が戻ってくるので免税書類を受け取る
  6. 無事に必要事項が揃った免税書類が取得できたので、封筒に入れて空港にあるポストに投函して完了
  7. 免税対象品はスーツケースに入れてしまえば機内に持ち込まなくて済む

ポストはインフォメーションセンター近くの自動ドアを出てすぐのところにある。ライオンの像がポストなので初見だとポストと気づかない。

サブ機としてのα6000

自分はニコンのD610とFマウントレンズをいくつか持っているのだけれど、歩きの移動が多い海外出張や海外旅行だとかなり重労働になるので、ここ半年くらいサブ機がほしいと思っていた。で、今回の旅行に際して諸々悩んだ末にα6000のズームレンズキットを購入した。上のアルバムの写真はこのα6000で撮影したもの。画像加工はGoogle Photosが自動で行ったHDR以外は撮って出しのものだけ。

APS-C機だけれど、ボディとレンズでの重量も軽くサイズも小さく、ブラケット撮影や連写、動画撮影、マニュアル撮影等々もそれなりにこなせる良いカメラだったので買ってよかった。バリアングルでないため、セルフィーなどは難しいけれど、適当にピント合わせるとわりとちゃんと撮ってくれるので問題ない。携帯のアプリを通じてシャッターも切れるのでそっちでも良いかも。Eマウントはレンズが少ないところだけが辛いけど、サブ機だったりいままでカメラを持ってなかった人がレンズ交換可能機として初めて持つなら十分おすすめ。

参考

TypeScript 2.0.0とVisual Studio Code 1.4でChrome拡張を書く

はじめに

こんにちは。ナルゲンボトル愛好家です。ふと思い立ってChrome拡張作ろうかなと思ったんですが、どうせならTypeScriptでやるのがいいじゃねえかってことでやりました。で、最近ブログ書いてないし、なんかまとめたらいい感じかなと思ったのでまとめます。

構成

.
├── dist // 生成された拡張
│   ├── context-menu.js
│   ├── icons
│   │   └── icon48.png
│   └── manifest.json
├── gulpfile.js
├── .eslintrc.json
├── package.json
├── static
│   ├── icons
│   │   └── icon48.png
│   └── manifest.json
├── ts
│   └── src
│       └── context-menu.ts // Chrome拡張をTypeScriptでやってくやつ
└── tsconfig.json

毎回思うんですが、ちょっとのことやりたいだけなのに xxxx.json みたいな設定ファイルばっかりでほんとにだるい。だれかなんとかしてほしい。

下準備

typescript@2.0.0 を Visual Studio Code の参照先にする

あたりまえだけどまずTypeScriptが必要。今回は新しいやつを早く使いたかったんで @2.0.0 をグローバルに入れた。バージョン使い分けるほど使ってません。

$ npm i -g typescript@2.0.0

最近はエディタは軟派にVisual Studio Codeをよく使ってるんだけど、こいつがデフォルトで使うTypeScriptの設定を変えてやらないと新しい文法とか出てきた時にlintがうるさいので変えておく。Visual Studio CodeのUser Settingsでこんな感じの設定をしておく。ワークスペースごとに使うTypeScriptのバージョン違うという人がいたら、Workspace Settingにして、Workspaceのtypescriptを参照するようにしたらいいんじゃねえかと思いますが、やったことはありません。

"typescript.tsdk": "/Users/ymotongpoo/.nvm/versions/node/v6.3.0/lib/node_modules/typescript/lib"

Chrome Extension APIの型定義ファイルを参照する

TypeScriptの恩恵にあずかりたいので型定義ファイルを持ってくる。当然Chrome本体にモジュールはあるため、型定義ファイルだけあれば良いので、 id:otiai10 に感謝を唱えつつモジュールを落とす。

$ npm i @types/chrome

あとは普通に使えば良い。tsconfig.jsonとcontext-menu.tsはこんな感じでやっていく。tsconfig.jsoncompilerOptionsChromeがES5で頼むって感じだったはずなので target に気をつけるのと、あとでbrowserifyするんで modulecommonjs にしときました。momentは単に今回使ったので特に重要じゃないです。

{
    "compilerOptions": {
        "target": "ES5",
        "module": "commonjs",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": false,
        "noImplicitAny": false
    },
    "files": [
        "./ts/src/context-menu.ts",
        "./node_modules/@types/chrome/index.d.ts",
        "./node_modules/@types/filesystem/index.d.ts",
        "./node_modules/@types/filewriter/index.d.ts",
        "./node_modules/@types/moment/index.d.ts"
    ]
}

context-menu.tsでは参照しときましょう。

/// <reference path="../../node_modules/@types/chrome/index.d.ts" />

いい感じになった。

f:id:ymotongpoo:20160805131904p:plain

gulpの設定

grunt だとか gulp だとかなんか周辺ツール多すぎてホント嫌になってくるんですが、まあそういう形で回っちゃってるものはしょうがないので文句言いながら gulpfile.js 書きます。必要なパッケージを入れときます。

$ npm i -g --save-dev browserify
$ npm i --save-dev vinyl-source-stream tsify gulp-jsmin
$ npm i -u typescript@2.0.0

ローカルにもtypescript入れるのはtsifyでtypescriptモジュールをrequireしてるため。tsifyだけにしちゃうと依存してるデフォルトのバージョンが入っちゃうんでこうやってる。最初はgulp-typescript使ったりしてたんだけど、公式サイト見に行ったら使わないで一発でbrowserifyしてて楽だったので真似した。

const gulp = require('gulp');
const del = require('del');
const browserify = require('browserify');
const source = require('vinyl-source-stream');
const tsify = require('tsify');
const jsmin = require('gulp-jsmin');

const config = {
    browserify: {
        opts: {
            basedir: '.',
            entries: ['./ts/src/context-menu.ts'],
            cache: {},
            packageCache: {},
            debug: false
        }
    },
    source: {
        target: 'context-menu.js'
    }
};

gulp.task('copy', [], () => {
    return gulp.src('./static/**/*')
        .pipe(gulp.dest('./dist'));
});

gulp.task('build', ['copy'], () => {
    return browserify([], config.browserify.opts)
        .plugin(tsify)
        .bundle()
        .pipe(source(config.source.target))
        .pipe(gulp.dest('./dist'));
});

gulp.task('minify', ['build'], () => {
    gulp.src(['./dist/**/*.js])
        .pipe(jsmin())
        .pipe(gulp.dest('./dist'));
});

gulp.task('clean', [], () => {
    return del(paths.dist.dir);
});

gulp.task('default', ['minify']);

使ってたmoment.jsの型定義ファイルだけインストールして、肝心のmomentパッケージ自体をインストールし忘れたことで、当然concatされないことを気付かずに悩むみたいなバカなことをしたけど、まあ動いちゃえば単純。

distをパッケージにする

普通にここに書いてあるとおりにやるだけです。Macな人はコマンドが若干異なるけどほぼ一緒です。

$ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' --pack-extension=dist

というわけで dist.crx が出来て嬉しいですね。

おわりに

設定ファイル何個書かせるんだよ。めんどくさい。