netflix in train 4

1

chef's table シーズン5を見た

www.netflix.com

ていうかこれシーズン5なのね、今気づいてしまった。

これは料理のドキュメンタリではなく、シェフのドキュメンタリである。

だけど「シェフの」と言ってしまうのも変に感じる作品だった

確かに主体の職業はシェフであることに間違いない。

だけど、客がいて料理があっての労働的側面よりは文化的な側面が強調された作品だった。

シェフという職業を通して食文化をとらえてきた人のドキュメンタリだった。

シーズン5がそういうテーマなのかもしれない

2

ある生活に結びついた文化をとってきた時に、食文化の存在は大きい

だけど文化としての料理が何をさすのかはあやふやで、レシピをさすだけなのか、家庭で出された事実をさすのか、ある料理店をさすのかはわからない。

ありきたりだが日本で肉じゃがという料理を考えた時に、家庭で出されている事実はあっても代表的なレシピは存在はしない。

過去の肉じゃが発明時のレシピが今の肉じゃがを基礎づけてはあっても今の肉じゃがをさすとは到底思えない。

だけど普遍的に人々は存在を認識はしていて、それこそが文化としての料理なのかもしれない。

そのような中、料理店を構えて自分の作った肉じゃがが”肉じゃが”だと示していく行為は、一見各々が自分で料理する中で生み出す肉じゃがと変わらないように思えるが、それこそが文化として引き継ぐ行為なんじゃないかと思った。

あくまでふわふわした存在から形を作り出しそれを示していく行為をしてくれているのがシェフなんじゃないだろうか。

当然、職業かどうかは関係ないが

鮭に対するアンサー

1

先日作った鮭の昆布締めに対する考察

hiroqn.hatenablog.com

経緯

鮭は油が多いしサクのまま巻くので長時間寝かせる必要があるのでは?という考えから24時間かけたが、昆布と鮭自体のにおいで田舎っぽくなってしまった。

ので、調味料を足していい感じにする

 ## 2

試してそんなだったもの

日本酒と塩

アルコール飛ばしてないと調味料としては微妙かも

煎り酒は時間がかかるので断念 

マヨネーズ

全てをふっ飛ばす。昆布締めの意味なし

 

たまり

シンプルに醤油

悪くないけど鮭と醤油はちょっと違うかな

結局両方グルタミン酸なので旨味がバッティングしてるような

タイムと塩

一口目がタイムで後味が昆布、意味がない ディルがあったらな〜みたいな気持ち。ディルは常備してない

レモン汁と塩

ちょっと酸味が強すぎるかも

3

良かったやつ

エシャレット

エシャレットを鮭で巻いて、たまりを少し塗ったり塩振ったり

玉ねぎ感覚で使ったが苦手な人は無理かも知れないけど、さっぱりしてて田舎臭さが消えた  

オリーブオイル、塩、胡椒、バルサミコ酢

これが一番合った。後から昆布の旨味がしっかり味わえるし鮭自体の味もしっかりしている。 酸味が大事に感じる。けどレモン汁ではダメで酢酸が必要説。 今あるバルサミコ酢は結構マイルドなやつで甘めなのでそれもあっている感がした。

f:id:hiroqn:20181218232658j:plain

bs-winstonを作ろうとする過程

1

winstonjsありますよね。jsのlogライブラリ。

github.com

BuckleScriptから使いたくなりません?

というわけで、作りながら書いていきます。

今回は作る過程を描く感じで完成してpublishはしないです。

2

READMEを読めばぼんやり使い方はわかると思うので、まずはtsの型定義から見ていきます。

https://github.com/winstonjs/winston/blob/master/index.d.ts

createLoggerに色々オプションを渡すとLoggerが出てくる感じです。

今回注目して欲しいのがlevels optionで、これがかなり胆になってきます。

型的にはこれですね

interface AbstractConfigSetLevels {
    [key: string]: number;
}

objectで表現されたMap<string,number>型なんですが、winstonはこれのkey情報を使ってmeta的にLoggerにmethodを生やしてきます。

つまり

levels: {
  hoge: 0,
  fuga: 1,
}

というオプションを渡せばlogger.hogelogger.fugaみたいなmethodが生えるわけですが、それに対して型をつけるのは厳しいのでその部分は諦めます

ただ、どのlevelがlogに使えるかやどのlevel以上のlogを出力するかというオプションに関わってくるので上のlevelsオプションは作る必要があります。

2

logに使うlevelを文字列で渡す方法がありますが、そんな安全じゃない方法は取りたくないので今回はそれにうまく制約をつけていきます。

イメージとして、 log `Alert "message"みたいな感じなれば嬉しいですね

ただ、どのようなlevelが使えるかというところはカスタマイズできるように作れるようにします。

Variantからstringにする部分を自動生成するppxが最初から入っているのでこれを使っていきます

一旦Syslogに対応するということで

    type t = [
        | `Emerg [@bs.as "emerg"]
        | `Alert [@bs.as "alert"]
        | `Crit [@bs.as "crit"]
        | `Err [@bs.as "error"]
        | `Warn [@bs.as "warning"]
        | `Notice [@bs.as "notice"]
        | `Info [@bs.as "info"]
        | `Debug [@bs.as "debug"]
    ] [@@bs.deriving jsConverter]

こういう感じにしていきます。

上記から本来はlevelsオプションを生成したいわけですがそれはmetaプロになっちゃってきついのです。あとlevelの順序を定義する必要もあります。

なので一旦どのlevelが使えるかというenabledという概念を用意してt listにします。

let enabled = [Emerg; Alert;Crit; Err;Warn; Notice;Info; Debug]

そしてここからlevelsを生成できます。

let levels = enabled |> List.mapi (fun i l -> (Level.string_of_t l, i)) |> Js.Dict.fromList

結果は

{ emerg: 0,
  alert: 1,
  crit: 2,
  error: 3,
  warning: 4,
  notice: 5,
  info: 6,
  debug: 7 }

こうなります。

3

そういえばFFIの部分を書いてなかったので書いていきます。

winston_internal.ml

type transport

(* ここのオプションは諸事情で一部省略 *)
type mk_console_transport_option = {
    eol: string [@bs.optional]
} [@@bs.deriving abstract]

external console_transport: mk_console_transport_option -> transport = "Console" [@@bs.new][@@bs.module "winston/lib/winston/transports/index"]

(* winston本体 *)

type mk_option = {
  levels: int Js.Dict.t;
  level: string;
  transports: transport array;
} [@@bs.deriving abstract]

type winston

external create_logger: mk_option -> winston = "createLogger" [@@bs.module "winston"]

type mk_log_entry = {
    level: string;
    message: string;
} [@@bs.deriving abstract]

external log: winston -> mk_log_entry -> unit = "" [@@bs.send]

これはもうこんな感じとしかいえないですね。

4

あとは組み合わせると一旦は動くのですが、levelのカスタマイズができません。

そのためにcreate_loggerをFunctorにします

module type LogLevel = sig
    type t
    val string_of_t : t -> string
    val enabled : t list
end

module Make(Level: LogLevel)(Conf: sig 
    val transports: Winston_internal.transport list 
    val level: Level.t
end) = struct
    type t = Level.t

    type log_entry = {
        message: string;
        level: Level.t;
    }

    let _levels = Level.enabled |> List.mapi (fun i l -> (Level.string_of_t l, i)) |> Js.Dict.fromList

    let w = Winston_internal.(create_logger @@ mk_option
        ~levels: _levels
        ~level: (Level.string_of_t Conf.level)
        ~transports: (Conf.transports |> Array.of_list)
        )

    let log level message  = 
        let entry = Winston_internal.mk_log_entry ~level: (Level.string_of_t level) ~message in
        Winston_internal.log w entry
end

こうすることでLogLevelを実装すればいい感じのLoggerモジュールができる設計になります。

Syslogモジュールは

module Syslog = struct

    type t = [
        | `Emerg [@bs.as "emerg"]
        | `Alert [@bs.as "alert"]
        | `Crit [@bs.as "crit"]
        | `Err [@bs.as "error"]
        | `Warn [@bs.as "warning"]
        | `Notice [@bs.as "notice"]
        | `Info [@bs.as "info"]
        | `Debug [@bs.as "debug"]
    ] [@@bs.deriving jsConverter]

    let enabled = [`Emerg; `Alert; `Crit; `Err; `Warn; `Notice; `Info; `Debug]
    let string_of_t x = tToJs x
end

という風に定義できるので、

module SyslogLogger = Make(Syslog)(struct
    let transports = Winston_internal.([console_transport @@ mk_console_transport_option ();])
    let level = `Debug
end)

SyslogLoggerはこのように生成できます。

使用例

let () =
    SyslogLogger.log `Emerg "yabai";;

LogLevelさえ満たせばいいのでNpmLogLevelのようなものを作れば以下のようなnpm log levelにも対応することできます。 https://github.com/winstonjs/triple-beam/blob/master/config/npm.js

5

実はwinston-transport(上記のconsole_tranport)に対してもlog levelが設定できるのですが一旦TODOにしました。 またwinstonのformat optionのFFIを書くのがちょっと骨が折れるのでこれもTODOにしています。

昆布締めアンボックス

1

昨日仕込んでおいた、サーモンの昆布締めをアンボックスしていきます

ちなみに、これを見てサーモンの昆布締めが案外いけるっぽいのでtryしました。

negineesan.hatenablog.com

2

f:id:hiroqn:20181216235448j:plain

f:id:hiroqn:20181216235451j:plain

f:id:hiroqn:20181216235454j:plain

f:id:hiroqn:20181216235458j:plain

3

サクだったので24時間巻いておいたというのもあるかもしれないけど、

正直、なんか田舎臭さというか

一口目のファーストインプレッションが柿の葉寿司っぽい、、、

(祖父母が奈良の人間で幼少期に度々奈良に連れていかれ、やたらと奈良では柿の葉寿司を食わされ鯖の柿の葉寿司が苦手だった自分は鮭の柿の葉寿司ばかりを食べていた記憶が唐突にフラッシュバックする)

一旦落ち着いて薬味とかタレとかソースとかの方向性を考えることにした。

もともとサーモンなので玉ねぎとマヨネーズで👍みたいなのを考えていたのだけど、昨日のカレーに玉ねぎを全部使ってしまってない(愚か)&マヨ合わんなって即なった

4

というわけで、色々つけながら何があうか試していきたいと思っていたが時間がかかってきたので一旦アンボックスだけにしました。

内容なさすぎ

続編書くしかない

カレー

1

カレーの説明をすると、自分の好きな食材をスパイスで煮込んだものです。以上。

f:id:hiroqn:20181215231954j:plain

材料

2

野菜系の処理をしていきます

f:id:hiroqn:20181215231957j:plain

玉ねぎはみじん切りして電子レンジへ

f:id:hiroqn:20181215232008j:plain

こんな感じ

f:id:hiroqn:20181215232011j:plain

セロリも同等の操作を加えます。

f:id:hiroqn:20181215232014j:plain

ホールトマトは手で潰して、煮詰めていきます

f:id:hiroqn:20181215232020j:plain

はい

f:id:hiroqn:20181215232034j:plain

これがゴール

3

次は肉です

f:id:hiroqn:20181215232001j:plain

牛すじは煮こぼして

f:id:hiroqn:20181215232004j:plain

洗う

f:id:hiroqn:20181215232023j:plain

せせりにも同等の操作を加え切りました。

4

スパイス、一番難しい

f:id:hiroqn:20181215232026j:plain

クミン、ターメリック、カイエン、カルダモン、あとレッドアイ

フェンネルクローブは少しだけ

f:id:hiroqn:20181215232043j:plain

ニンニクとエシャロット

5

その他の素材として

f:id:hiroqn:20181215232038j:plain

昆布だしを凍らせてあったもの

f:id:hiroqn:20181215232048j:plain

ペコリーノロマーノ

余談ですが、イタリア料理のドキュメントを見ていたら、イタリア人はペコリーノをFORMAGIOのカテゴリに入れてませんでした。

formagioはチーズをさすと思ってたのですが、牛の乳から作られているのに限るのかもしれない。

f:id:hiroqn:20181215232052j:plain

いい感じになったら全てを投入して、パルミジャーノレジャーがぶっこまれてます。

6

ライスを炊いてませんでした、、、、

netflix in train 3

1

最近見てるのはこれ

Hip-Hop Evolution | Netflix Official Site

HipHopの歴史が雑にわかって便利フィルム

間違ってシーズン2から見はじめてしまったので、今シーズン1を見ている。

2

よくあることだが「HipHopとは〜」みたいに語り出すオタクに人々はなってしまう。

まぁでもこのHipHopっていう部分にJazzとかReggaeとかPopの名がつく音楽ジャンル以外を入れても成り立ってしまうことから音楽とオタクの相性というのは切り離せないものではあるかもしれない。

そして、この作品は明らかにHipHopオタクの顔立ちをした職業ラッパーが「HipHopとは〜」をガッツリ歴史からやってくれる最高のアイテムである。

3

HipHopって難しい。中学生か高校生の頃に辞書、多分電子辞書でHipHopとは何かを調べたことがある。

当時の辞書はないからネットの辞書で調べるとこんな感じ

1970年代前半ごろから、ニューヨークの路上で始まった、音楽・ダンス・ファッションを中心とする黒人文化。建造物の壁や地下鉄の落書き(グラフィティアート)、アクロバットのようなブレークダンス、音楽面ではラップやスクラッチなど、貧しい若者たちがお金を使わずに楽しめる娯楽を生み出した。

kotobank.jp

確かにだいたいこんな感じだった。

当時「なんだよ、全然違う、よくわからん」確かにそんな気持ちになった。

だってネットの発達してない当時にHipHopと認知できる範囲って「Yo」「ターンテーブル」「DJ」「MC」「ラップ」「音楽は鳴り続ける....」

そら、HipHop自体の極々Surfaceしかふれることができないから変な認知になる。僕に限った話ではなく世間一般として。

オレンジレンジとか麻波25HipHopとかいってしまうのもしょうがない(これは自分の話じゃないよ、一応)

遠いアメリカのカルチャーの話だからね、今でこそアメリカといっても東海岸と西海岸で違うけどさぁ、みたいなオタク発言できるけど。

これは中学時代の自分をウマヅラハギみたいな顔した音楽の先生の授業中から連れ出して一晩かけて見せて教育させる作品である。

4

「一般人がHipHopと認知しているメジャーなJ-POP」っていう単語、ちょっとdisが入っている言い方だけどまぁよくある「これはHipHopじゃない」騒動

すでにアメリカでも1970年代にやっていてちょっと面白いなって思った。

TypeScriptのunknown型

1

3.0から入ったunknown型がある

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html

というかunknown型が入ったこともあってmajor versionが上がったという認識をしている

2

コードベース中にJSON.parseをanyで受けているところをunknownにしてみるか〜と思って試したがうまくいかなかった

function main(x: unknown): string {
    if (typeof x !== 'object') {
        throw new Error('x');
    }

    if (x === null) {
        throw new Error('x');        
    }
    // この時点でxが{}まで絞れる

    // (1) typeof x.y  typeof x["y"]

    // (2)
    // if ('y' in x) {
    //     x.y
    // }
}

結局 1, 2で詰んでしまう。

まだtypeのnarrowがうまく効かなくて、issueはある状態。

自分の期待しうるunknownにはまだ遠くてJSON.parseの返り値に使うのは、真面目に書こうとする限り厳しいなぁという気持ち。