RSS 監視して Discord に投げるやつを Raspberry Pi で動かした

これをしようとコードを書いた。クロスコンパイルの容易さから Go で書いた。Raspberry Pi 2 Model B で動かしている。

feed-trigger

ひとつめは feed-trigger。

github.com

これは RSS をチェックして更新があると指定されたコマンドの標準入力に新規エントリーのみを含めたフィードを渡して起動するやつ。

discord-feed-post

ふたつめは discord-feed-post

github.com

これは標準入力から取得した RSS フィードを Discord に投稿するやつ。

これらふたつを合わせて cron で1時間に1回起動するようにした。

課題

RSS 2・RSS 1・Atom のどれか(もしくは複数)で失敗している。

wd コマンドをリリースした

wd コマンドって?

これがしたかった。

$ wd ディレクトリー コマンド オプション

とすると「ディレクトリー」をワーキングディレクトリーにして「コマンド」を「オプション」付きで実行する。

pushd でもできるけど popd と合わせるとタイプ数が多かった。

インストール

GitHub のリリースページに WindowsLinuxmacOS (x64) 用のバイナリーがある1

github.com

自分でビルドする場合は cabalghc が必要。

$ make install

気に入ったら GitHub にスターをよろしくね。


  1. GitHub Actions に macOS (ARM) が提供されるとそのバイナリーを追加するつもり。

初めての Modellbahn-Shop Lippe(ドイツ型鉄道模型)

芦屋のモデルバーンに行ったらドイツ国有鉄道(Deutsche Reichsbahn-Gesellschaft)03形蒸気機関車サウンド付きが22000円とびっくりお手ごろ価格だったのでウッカリしてしまった。

www.instagram.com

ESU LokSound v3 搭載の2004年製品のようだが十分に恰好いい。キャブにスピーカーがデデンと鎮座している以外は何も文句がない。デデンなスピーカーだけあって音がいい。

単行も悪くはないが、そうは言っても引かれるものがほしくなってくるというもの。

調べると急行用機関車だそうなので客車を物色する。

ヤフオク!で一等二等合造客車と荷物車のセットがあったので落札。これもちょっと古そうな製品だけど悪くない。2両で税込8635円、送料1130円。

www.instagram.com

ほんでもうちょっと引きたいな~となったのでドイツのお店に発注!界隈で有名な Modellbahn-Shop Lippe

一二三等合造車と三等車と食堂車。実はちょっとまちがえて DRB と略される方の Deutsche Reichsbahn の車両なのでちょっと時代が違うがまあよかろう1。それぞれ54.54ユーロ、送料35ユーロ。

www.instagram.com

8月1日15時に発注して着荷は8月8日午前だった。早い。

最後に走行シーン。

www.instagram.com

ほな!


  1. 1924-1937 はドイツ国有鉄道(Deutsche Reichsbahn-Gesellschaft)、1937-1945 はドイツ帝国鉄道(Deutsche Reichsbahn)。

Windows で Haskell SDL2

Hackage にある SDL2 ライブラリーを Windows で利用する方法のメモ。

hackage.haskell.org

Haskell-jpSlack の質問をきっかけに手元で試したことを思い出しながら書いている。

sdl2.cabal に下記の記述があるので C ライブラリーを事前にインストールする必要がある。

    pkgconfig-depends:
      sdl2 >= 2.0.6

今回は stack に附属する MSYS2 を利用する。

stack exec -- pacman -S mingw64/mingw-w64-x86_64-SDL2 でインストールできるはずだが、MSYS2 パッケージメンテナー入れ替えの影響で証明書のインストールをしないと次のようにエラーになることがある。

> stack exec -- pacman -S mingw-w64-x86_64-SDL2
…
error: mingw-w64-x86_64-mpfr: signature from "David Macek <david.macek.0@gmail.com>" is unknown trust
…
error: failed to commit transaction (invalid or corrupted package (PGP signature))
Errors occurred, no packages were upgraded.

MSYS2 のサイトに解決手順が書いてあるのでその通りにする。

www.msys2.org

そうすると stack exec -- pacman -S mingw64/mingw-w64-x86_64-SDL2 が成功する。

pkg-config 自体がインストールされてなかったので stack -- exec pacman -S mingw64/mingw-w64-x86_64-pkg-config でインストールする。

これで使用できるはずなので試してみる。

GitHub 上のリポジトリーに examples があるのでこれを実行する。

github.com

clone してきたディレクトリーで stack init して stack プロジェクトにする。

examples は無効になっているので下記のように stack.yaml を改変して有効にする。

- # flags: {}
+ flags:
+   sdl2:
+     examples: true

ビルドする。

> stack build
…
sdl2> copy/register
Installing library in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\lib\x86_64-windows-ghc-9.0.2\sdl2-2.5.3.3-LQ1fiw2pm1OGrmM1xeYJnd
Installing executable twinklebear-lesson-01 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-15 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-14 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable twinklebear-lesson-04 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-01 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-08 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-09 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable userevent-example in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-05 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-03 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-17 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-02 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable audio-example in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-07 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-10 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-04 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-19 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-43 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable twinklebear-lesson-02 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable eventwatch-example in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-11 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-12 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-13 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable twinklebear-lesson-04a in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable lazyfoo-lesson-18 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Installing executable twinklebear-lesson-05 in C:\Users\kazuki\Projects\Sub\haskell-game\sdl2\.stack-work\install\723b28be\bin
Registering library for sdl2-2.5.3.3..

実行する。

> stack exec lazyfoo-lesson-43

おわり

WSL2 の SSH Agent 盆栽

この記事を読んでセットアップしたので備忘録として残しておく。

qiita.com

自分の選択はこのチャートの青線で書いたやつにした。

手順

元々「Windows の機能」で OpenSSH をインストールしてある。

Pageant は使ってないので WSL2 も OpenSSH に寄せる。

Linuxsocat を、 Windowsnpiperelay をインストールする。

$ sudo apt install socat
$ choco install npiperelay

~/.bash_profile からこの start_ssh_agent_wsl を呼ぶ。

start_ssh_agent_wsl() {
    if [ -z "$SSH_AUTH_SOCK" ]
    then
        SSH_AUTH_SOCK=$(mktemp -d /tmp/ssh-auth.XXXX)/sock
        setsid socat UNIX-LISTEN:"$SSH_AUTH_SOCK",fork EXEC:'npiperelay -v //./pipe/openssh-ssh-agent',nofork >>/tmp/ssh-agent.log 2>&1 &
        export SSH_AUTH_SOCK
    fi
}

$SSH_AUTH_SOCKUnix ソケットをリッスンして、接続があれば npiperelay を起動し転送する。npiperelay は標準入力を \\.\pipe\open-ssh-agent の名前付きパイプに転送する。\\.\pipe\open-ssh-agentWindows の OpenSSH が待ち受けている。

setsid とか nohup が何かよく分かってない。

重ね着したバービー人形 in Haskell

うやむやで終わる記事なので事前にご了承ください。

前回のあらすじ

(前回などないので探さなくていいです。)

高カインドデータ型(Higher-kinded Datatypes; HKD)というものがあります。

fumieval.hatenablog.com

qiita.com

簡単に説明すると下記のようなデータ型 D があるとき

data D =
  D { a :: A
    , b :: B
    }

D の代わりに H のようなデータ型を作ると便利という発想です。

data H f =
  H { a :: f A
    , b :: f B
    }

H Identity だと D と同じ意味になりますし、H Maybe だと部分的に(もしくは全部)値が欠けたものを意味します。

HKD をサポートするライブラリーとして barbies がポピュラーです。

hackage.haskell.org

HD のように使うには Identity をたくさん書くことになりますが barbies の提供する機能を使うと Identity を書く手間が減らせます。

こういうものが用意されているので、

data Bare
data Covered

type family Wear t f a where
  Wear Bare    f a = a
  Wear Covered f a = f a

HB のように書き換えます。

data B b f =
  B { a :: Wear b f A
    , b :: Wear b f B
    }

このとき B Bare fD と同じ構造に B Covered fH と同じ構造になります。

こういうデータ型に対する操作も barbies は提供しています。

class FunctorB (b Covered) => BareB b where
  bstrip :: b Covered Identity -> b Bare Identity
  bcover :: b Bare Identity -> b Covered Identity

ここまでが「前回のあらすじ」です。

重ね着

ここからは「なんかこういうのがほしいな」という発展です。

data L f =
  L { a :: f A
    , d :: f (D f) -- D も HKD
    }

HKD が入れ子になっててもいいじゃない。

経緯としては、抽象構文木(Abstract Syntax Tree; AST)のデータ型を書いていて、位置情報を持つファンクター(例えば WithLocation とする)を f に与えるようにするとすっきりならんかと思いました。

data Expression f
  = Abstract
      { variable :: f Variable
      , expression :: f (Expression f)
      }
  | Application
      { expression1 :: f (Expression f)
      , expression2 :: f (Expression f)
      }

ファイルをパースして構築するときは Expression WithLocation として、テスト時は Expression Identity として使用します。

こうするとノードに付与する追加データと AST 自体の構造とが分離できて嬉しいです。

ここで barbies にあった Wear を使うとこうなります。

data Expression b f
  = Abstract
      { variable :: Wear b f Variable
      , expression :: Wear b f (Expression b f)
      }
  |

ここで ExpressionBareBインスタンスになるか考えます。

そのためには FunctorBインスタンスでないといけません。

FunctorB は次のような型クラスです。

class FunctorB b where
  bmap :: (forall a . f a -> g a) -> b f -> b g

Expression に対する bmap を実装してみます。

instance FunctorB (Expression Covered) where
  bmap f (Abstract v e) = Abstract (f v) (_ $ f e)
  bmap f (Application e1 e2) =

_ の部分の型は g (Expression Covered f) -> g (Expression Covered g) となるはずですが、うーん実装できなさそうです。

入れ子 HKD では bmap の型は Functor g => (forall a. f a -> g a) -> b f -> b g もしくは Functor f => (forall a. f a -> g a) -> b f -> b g となる必要がありそうです。

そんなわけで入れ子 HKD は barbies の提供する FunctorBBareB とは別の型クラスが必要となります。

さて、ここでリストを考えます。

newtype List x b f = List { unlist :: [Wear b f (x b f)] }

こういうデータ型があると、これに関して bmap を定義できて便利そうです。

同様にタプルについてもこんな Tuple2 を考えると……

newtype Tuple2 x y b f = Tuple2 { untuple2 :: (Wear b f (x b f), Wear b f (y b f)) }

というふうに考えて進めてたんですが、元の型と Wear 版の型との相互変換がいっぱいになったり、List x Bare Identity[] になってほしくなって型族を使いだしたりして収拾がつかなくなって一旦やめます、というお話です。

なんやそら。