とら食堂 福岡分店

福島の老舗ラーメン店「とら食堂」が福岡に出店していた。その名も「とら食堂 福岡分店」。

白河ラーメンと呼ばれるジャンルらしい。昼食を食べていなくて空腹だったので、焼豚ワンタン麺を注文した。しかも麺増しで。麺増しだと麺とスープだけでなく、焼豚も1.5倍になるみたい。おかげですごいボリュームだった。

琥珀色のスープは澄んで綺麗。それでいて鶏や醤油の旨味がしっかりと出ていた。すごく優しいスープで飲み干してしまった。平打ち麺は舌ざわりがツルツル。噛むともっちり。このスープにはこの麺しかないという組み合わせだと思う。焼豚は3種類の部位が食べられて、どの肉も甲乙つけがたい。焼豚1.5倍増しは、今回みたいにMAX空腹でないと食べきれなさそうだ。

期待以上の味だった。現時点で、自分の中の「醤油ラーメン食べるときの店第1位」に輝いた。豚骨と同じかそれ以上に醤油ラーメン好きなので、また食べに行こう。

とら食堂 福岡分店

食べログ とら食堂 福岡分店

久楽

天神北にある『北海道らーめん奥原流 久楽』に行ってみた。この場所、以前は理髪店が入ってたと思うけど、いつのまに変わったんだ。オープン1周年らしい。

味噌ラーメンと餃子、ライスのセットを注文した。味噌ラーメンは白味噌を選択。白味噌の味噌ラーメンは食べたことないな。

白味噌のスープが濃厚でいてまろやかで、白米によく合う。シメにご飯を投入するのがオススメらしい。今回はしなかったけど。麺にも良く絡んで美味い。

餃子はオーソドックスな味。餃子にハズレはそうそう無い。

白味噌の味噌ラーメンというのもなかなか良かった。赤味噌や合わせ味噌もあるので、他の味も試してみたくなる。味噌のつけ麺も気になるところ。あと、ランチではご飯が無料で付くみたいだ。それを考えると餃子のセットはコスパ良くないな。ラーメンだけ注文したほうがお得な気がする。

北海道らーめん奥原流 久楽 天神店

食べログ 北海道らーめん奥原流 久楽 天神店

『3月のライオン(1)~(12)』を読んだ

BUMP OF CHICKEN が『ファイター』でタイアップして、『3月のライオン』のことを知った。 そして、『アンサー』で再びタイアップしたので、これをいい機会に 1巻から12巻までを Kindle でまとめ買いして読んだ。

読む前は失礼ながら、競技が違うけど『ヒカルの碁』みたいなマンガかなと思っていた。実際に読んでみると、まったく違った。将棋マンガではあるが、むしろ将棋を題材にした人間ドラマを描いたマンガに思えた。

主人公の桐山零は物語開始時点ですでに、中学でプロ入りした天才棋士という周りの評価。ただメンタルに難があり、そのせいで伸び悩んでいる状態。物語内で明かされていく彼の半生からすると、それも仕方ないことではある。 なので、将棋の技量的な成長よりも、人間的な成長に重きを置いて物語は進んでいく。

零の人間的な成長に深く関わってくるのが川本家。3姉妹と祖父だけというワケありの家族なのだが、皆まっすぐで、そしてすごく温かい。 子供がいる身としては、特にひなたやモモみたいに健やかに育って欲しいと、かなり思った。

最近の零は、ひなたに(心を?)救われてからというもの、その成長は目を見張るものがある。 このマンガに悪役ってほとんどいないんだけど、数少ない悪役・捨男(仮名)と舌戦を繰り広げる姿は頼もしい限りで、ここまでに成長するとは。

個人的なお気に入りは二海堂。 めっちゃ熱くていいヤツだった。 ライバルというより強敵とかいてトモと呼ぶタイプ。むしろ親友。 モモに並ぶ癒しキャラでもあると思ってる。 モモとのコンビは見ててホッコリする。

将棋の知識が無くても楽しめるマンガになっていた。 ヤングアニマルで連載中なので、連載の方も読んでみようかな。 ただ、ヤングアニマルはちと購入のハードルが高めの雑誌だ。 モーニングやアフタヌーンだったらなぁ。 13巻が待ち遠しい。

S3 からファイルをフォルダごとダウンロードする方法のメモ

S3 Management Console では、フォルダごとダウンロードできなかった。 2017/04/10 現在でも、まだ AWS CLI を使うしかない。

aws s3 cp --region ap-northeast-1 s3://バケット名/パス ダウンロード先 --recursive

指定した URL に付けられたすべてのブックマークを取得する

はてなブックマークネタ第3弾。 最後は、指定した URL に付けられたすべてのブックマークを取得してみた。

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace HatenaBookmarkSample
{
    class Program
    {
        static void Main(string[] args)
        {
            var bookmarks = GetAllBookmarks("http://hatenablog.com")
                .GetAwaiter().GetResult();

            foreach(var bookmark in bookmarks.Bookmarks)
            {
                Console.WriteLine($"{bookmark.User} : {bookmark.Comment}");
            }

            Console.WriteLine("Enter で終了します。");
            Console.ReadLine();
        }

        static async Task<EntryBookmarks> GetPopularBookmarks(string url)
        {
            var httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders
                .Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            // User-Agent を設定しないと nginx にはじかれる
            httpClient.DefaultRequestHeaders
                .UserAgent.Add(new ProductInfoHeaderValue("HatenaClient", "0.0.1"));

            var requestUri = $"http://b.hatena.ne.jp/api/viewer.popular_bookmarks?url={url}";

            var json = await httpClient.GetStringAsync(requestUri);

            var bookmarks = JsonConvert.DeserializeObject<EntryBookmarks>(json);

            return bookmarks;
        }

        static async Task<EntryBookmarks> GetAllBookmarks(string url)
        {
            var httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders
                .Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            // User-Agent を設定しないと nginx にはじかれる
            httpClient.DefaultRequestHeaders
                .UserAgent.Add(new ProductInfoHeaderValue("HatenaClient", "0.0.1"));

            var requestUri = $"http://b.hatena.ne.jp/entry/jsonlite/?url={url}";

            var json = await httpClient.GetStringAsync(requestUri);

            var bookmarks = JsonConvert.DeserializeObject<EntryBookmarks>(json);

            return bookmarks;
        }
    }

    [JsonObject]
    public class EntryBookmark
    {
        /// <summary>
        /// ブックマーク ID を取得または設定します。
        /// </summary>
        [JsonProperty("eid")]
        public string Id { get; set; }

        /// <summary>
        /// タイトルを取得または設定します。
        /// </summary>
        [JsonProperty("title")]
        public string Title { get; set; }

        /// <summary>
        /// 記事の URL を取得または設定します。
        /// </summary>
        [JsonProperty("url")]
        public string Url { get; set; }

        /// <summary>
        /// ブックマークしたユーザーを取得または設定します。
        /// </summary>
        [JsonProperty("user")]
        public string User { get; set; }

        /// <summary>
        /// ブックマークコメントを取得または設定します。
        /// </summary>
        [JsonProperty("comment")]
        public string Comment { get; set; }

        /// <summary>
        /// ブックマークした時間を取得または設定します。
        /// </summary>
        [JsonProperty("timestamp")]
        public string Timestamp { get; set; }
    }

    [JsonObject]
    public class EntryBookmarks
    {
        /// <summary>
        /// ブックマーク件数を取得または設定します。
        /// </summary>
        [JsonProperty("count")]
        public int Count { get; set; }

        /// <summary>
        /// エントリの ID を取得または設定します。
        /// </summary>
        [JsonProperty("eid")]
        public string EntryId { get; set; }

        /// <summary>
        /// エントリのタイトルを取得または設定します。
        /// </summary>
        [JsonProperty("title")]
        public string Title { get; set; }

        /// <summary>
        /// エントリの URL を取得または設定します。
        /// </summary>
        [JsonProperty("entry_url")]
        public string EntryUrl { get; set; }

        /// <summary>
        /// ブックマークの URL を取得または設定します。
        /// </summary>
        [JsonProperty("url")]
        public string Url { get; set; }

        /// <summary>
        /// ブックマーク一覧を取得または設定します。
        /// </summary>
        [JsonProperty("bookmarks")]
        public List<EntryBookmark> Bookmarks { get; set; } = new List<EntryBookmark>();
    }
}

実行結果はこちら。

f:id:griefworker:20170405172557p:plain

はてなブックマークが提供する API は、REST APIAtom API や件数取得 API などなど、 たくさんあって分かりにくい。 REST API に一本化して、機能を充実してほしいところだ。

指定した URL の人気ブックマーク一覧を取得する

はてなブックマークネタ第2弾。 今度は、指定した URL に付けられたブックマークのうち、 人気のヤツを取得してみた。

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace HatenaBookmarkSample
{
    class Program
    {
        static void Main(string[] args)
        {
            var bookmarks = GetPopularBookmarks("http://hatenablog.com")
                .GetAwaiter().GetResult();

            foreach(var bookmark in bookmarks.Bookmarks)
            {
                Console.WriteLine($"{bookmark.User} : {bookmark.Comment}");
            }

            Console.WriteLine("Enter で終了します。");
            Console.ReadLine();
        }

        static async Task<EntryBookmarks> GetPopularBookmarks(string url)
        {
            var httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders
                .Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            // User-Agent を設定しないと nginx にはじかれる
            httpClient.DefaultRequestHeaders
                .UserAgent.Add(new ProductInfoHeaderValue("HatenaClient", "0.0.1"));

            var requestUri = $"http://b.hatena.ne.jp/api/viewer.popular_bookmarks?url={url}";

            var json = await httpClient.GetStringAsync(requestUri);

            var bookmarks = JsonConvert.DeserializeObject<EntryBookmarks>(json);

            return bookmarks;
        }
    }

    [JsonObject]
    public class EntryBookmark
    {
        /// <summary>
        /// ブックマーク ID を取得または設定します。
        /// </summary>
        [JsonProperty("eid")]
        public string Id { get; set; }

        /// <summary>
        /// タイトルを取得または設定します。
        /// </summary>
        [JsonProperty("title")]
        public string Title { get; set; }

        /// <summary>
        /// 記事の URL を取得または設定します。
        /// </summary>
        [JsonProperty("url")]
        public string Url { get; set; }

        /// <summary>
        /// ブックマークしたユーザーを取得または設定します。
        /// </summary>
        [JsonProperty("user")]
        public string User { get; set; }

        /// <summary>
        /// ブックマークコメントを取得または設定します。
        /// </summary>
        [JsonProperty("comment")]
        public string Comment { get; set; }

        /// <summary>
        /// ブックマークした時間を取得または設定します。
        /// </summary>
        [JsonProperty("timestamp")]
        public string Timestamp { get; set; }
    }

    [JsonObject]
    public class EntryBookmarks
    {
        /// <summary>
        /// ブックマーク件数を取得または設定します。
        /// </summary>
        [JsonProperty("count")]
        public int Count { get; set; }

        /// <summary>
        /// エントリの ID を取得または設定します。
        /// </summary>
        [JsonProperty("eid")]
        public string EntryId { get; set; }

        /// <summary>
        /// エントリのタイトルを取得または設定します。
        /// </summary>
        [JsonProperty("title")]
        public string Title { get; set; }

        /// <summary>
        /// エントリの URL を取得または設定します。
        /// </summary>
        [JsonProperty("entry_url")]
        public string EntryUrl { get; set; }

        /// <summary>
        /// ブックマークの URL を取得または設定します。
        /// </summary>
        [JsonProperty("url")]
        public string Url { get; set; }

        /// <summary>
        /// ブックマーク一覧を取得または設定します。
        /// </summary>
        [JsonProperty("bookmarks")]
        public List<EntryBookmark> Bookmarks { get; set; } = new List<EntryBookmark>();
    }
}

実行結果はこちら。

f:id:griefworker:20170405164319p:plain

指定したユーザーのはてなブックマーク一覧を取得する

いいかげん、そろそろプログラミングネタを書かねば。 ってことで、C# で「指定したユーザーのはてなブックマーク一覧を取得する」サンプルを書いてみた。

はてなブックマークに専用の API が見当たらないので、RSS フィードを取得してパースしている。 オフセットも指定できるから、これはこれで XML を返す Web API と見れなくもない。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace HatenaBookmarkSample
{
    class Program
    {
        static void Main(string[] args)
        {
            var bookmarks = GetUserBookmarks("griefworker", 100)
                .GetAwaiter().GetResult();

            foreach(var b in bookmarks)
            {
                Console.WriteLine(b.Title);
                Console.WriteLine(b.Url);
                Console.WriteLine(b.Comment);
                Console.WriteLine();
            }

            Console.WriteLine("Enter で終了します。");
            Console.ReadLine();
        }

        static async Task<IEnumerable<Bookmark>> GetUserBookmarks(string userId, int offset = 0)
        {
            var httpClient = new HttpClient();

            // RSS フィードなのでレスポンスは XML
            httpClient.DefaultRequestHeaders
                .Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));

            // User-Agent を設定しないと nginx にはじかれる
            httpClient.DefaultRequestHeaders
                .UserAgent.Add(new ProductInfoHeaderValue("HatenaClient", "0.0.1"));

            var requestUri = $"http://b.hatena.ne.jp/{userId}/rss";
            if (0 < offset)
            {
                requestUri += $"?of={offset}";
            }

            var rss = await httpClient.GetStringAsync(requestUri);

            var document = XDocument.Parse(rss);

            var bookmarks = document.Descendants()
                .Where(e => e.Name.LocalName == "item")
                .Select(ToBookmark)
                .ToList();

            return bookmarks;
        }

        static Bookmark ToBookmark(XElement element)
        {
            var bookmark = new Bookmark();

            foreach(var e in element.Descendants())
            {
                switch (e.Name.LocalName)
                {
                    case "title":
                        bookmark.Title = e.Value;
                        break;
                    case "link":
                        bookmark.Url = e.Value;
                        break;
                    case "description":
                        bookmark.Comment = e.Value;
                        break;
                }
            }

            return bookmark;
        }
    }

    class Bookmark
    {
        public string Title { get; set; }

        public string Url { get; set; }

        public string Comment { get; set; }
    }
}

実行結果は次の通り。

f:id:griefworker:20170405153751p:plain

はてなブックマークREST API で用意してくれたらいいんだけどな。