闘魂Elixir ── 2022-12-31 大晦日ハッカソン2022 をElixirで楽しむ！（元氣と闘魂を毎朝投稿（とうこん闘魂）する！）

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと、}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだとおもいます}$</font></b>



# はじめに

**闘魂**と[Elixir](https://elixir-lang.org/)が出会いました。
**闘魂** meets [Elixir](https://elixir-lang.org/).です。
[Elixir](https://elixir-lang.org/) meets **闘魂**.でもよいです。

本日2022-12-31(土)は、**毎年恒例**[大晦日ハッカソン2022](https://omisoka-hackathon.connpass.com/event/269353/)が開催されました。
今年も参加しました。

[elixir.jp](https://join.slack.com/t/elixirjp/shared_invite/zt-ae8m5bad-WW69GH1w4iuafm1tKNgd~w) Slackの「#autoracex」にイベント情報を投稿（とうこん**闘魂**)するボットをつくります。
たまに気が向いたときに自分で手動で行っています。それをボットに任せてみようというわけです。


```elixir
iex> "Elixir" |> String.graphemes() |> Enum.frequencies()
%{"E" => 1, "i" => 2, "l" => 1, "r" => 1, "x" => 1}
```

# 完成品

![スクリーンショット 2022-12-31 14.49.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131808/614294c7-ca07-2c20-da58-bc4962d702cc.png)

毎朝08:30にイベント情報が届きます。
ちなみに、私が主催する「[autoracex または闘魂ex](https://autoracex.connpass.com/)」は毎日もくもく会をエンジョイしています。

# 設計書（指示書）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131808/b9b93b51-cf4d-fce0-0629-247063ae891b.png)

ポイントは、

<b><font color="red">$\huge{元氣}$</font></b>
と
<b><font color="red">$\huge{闘魂}$</font></b>

を毎朝Slackに投稿（とうこん**闘魂**)することです。

ちなみに[指示書](https://buzzap.jp/news/20140206-samuragouchi-mamoru/)と言えば、私が真っ先に思い出すのは

https://buzzap.jp/news/20140206-samuragouchi-mamoru/

この話です。指示書そのものはすごいものだとおもいます。私が**指示書**という単語を使うときにイメージしているものはコレです。

# ソースコード

[GitHub](https://github.com/)に投稿（とうこん**闘魂**)しておきます。

https://github.com/TORIFUKUKaiou/binta


|  | バージョン |
|:-:|:-:|
| elixir  |  1.14.2-otp-25  |
| erlang  |  25.2 |

# ソースコードの説明

ポイントとなる部分を説明します。

## プロジェクトの作成

```
mix new binta --sup
```

`--sup`オプションは付けなくてもよかったかも。実行環境をどうするか見えていなかったのでとりあえず`To generate an app with a supervision tree and an application callback`で作りました。

## mix.exs

```elixir:mix.exs
  defp deps do
    [
      {:req, "~> 0.3.3"}
    ]
  end
```

外部のHexは、HTTPクライアント[Req](https://github.com/wojtekmach/req)を使いました。
`mix deps.get`で依存関係を解決します。

## lib/binta/connpass.ex

[connpass API イベントサーチAPI](https://connpass.com/about/api/)を呼び出すモジュールです。

https://connpass.com/about/api/

```elixir:lib/binta/connpass.ex
defmodule Binta.Connpass do
  @moduledoc false

  def event_now do
    utc_today = Date.utc_today()

    ym =
      "#{utc_today.year}#{utc_today.month |> Integer.to_string() |> String.pad_leading(2, "0")}"

    %{ym: ym, series_id: 11144}
    |> run()
    |> handle_response()
    |> Enum.filter(fn %{"started_at" => started_at, "ended_at" => ended_at} ->
      {:ok, start, _} = DateTime.from_iso8601(started_at)
      {:ok, ending, _} = DateTime.from_iso8601(ended_at)
      utc_now = DateTime.utc_now()

      DateTime.compare(start, utc_now) in [:lt, :eq] and
        DateTime.compare(utc_now, ending) in [:lt, :eq]
    end)
    |> Enum.at(0)
  end

  def run(query) do
    Req.get("https://connpass.com/api/v1/event/?#{URI.encode_query(query)}")
  end

  defp handle_response({:error, _}), do: []

  defp handle_response({:ok, %{body: %{"events" => events}}}), do: events
end
```


`Binta.Connpass.event_now/0`関数は、現在開催中の「[autoracex または闘魂ex](https://autoracex.connpass.com/)」コミュニティイベントを取得するように**早すぎる最適化**をしています。
コード中`11144`は「[autoracex または闘魂ex](https://autoracex.connpass.com/)」のことを指します。

@koga1020 さんの[ExConnpass](https://github.com/koga1020/ex_connpass)を参考にしました。ありがとうーーーーッ！！！　ございます。
こちらを使おうかともおもったのですが、先に入れた[Req](https://github.com/wojtekmach/req)と依存関係の解決がうまくいかなかったので、どうせHTTP GETだけだし、雑に自分で書きました。

## lib/binta/slack.ex

Slackにメッセージを投稿（とうこん闘魂）するモジュールです。

```elixir:lib/binta/slack.ex
defmodule Binta.Slack do
  @moduledoc false

  def post(message) do
    Req.post(url(), json: %{text: message})
  end

  defp url, do: Application.get_env(:binta, :slack_incoming_webhook_url)
end
```

メッセージを投稿（とうこん闘魂）するためのSlackの設定やURLの取得方法は下記のドキュメントをご参照ください。

https://api.slack.com/messaging/webhooks

## config/config.exs

環境変数`BINTA_SLACK_INCOMING_WEBHOOK_URL`にSlack Incoming WebhookのURLを設定して読み出して使うようにします。

```elixir:config/config.exs
import Config

config :binta, slack_incoming_webhook_url: System.get_env("BINTA_SLACK_INCOMING_WEBHOOK_URL")
```

## lib/binta/inoki.ex

```elixir:lib/binta/inoki.ex
defmodule Binta.Inoki do
  @moduledoc false
  # TODO 将来猪木さんAI

  @messages [
    "闘魂とは己に打ち克つこと、そして闘いを通じて己の魂を磨いていくことだとおもいます",
    "元氣ですかーーーーッ！！！　元氣があればなんでもできる！",
    "イーチ、ニィー、サン、ぁッ ダー！！！"
  ]

  def build_message do
    message = Enum.random(@messages)
    ":fire::toukon: *#{message}* :inoki: :toukon::fire:"
  end
end
```

**将来はAI技術を取り込んで、猪木さんが話しているかのようにしたいです。**
**元氣があればなんでもできる！**

## lib/binta.ex

上記で部品は揃いました。
上記を組み合わせてひとつなぎのものにしたものです。

```elixir:lib/binta.ex
defmodule Binta do
  @moduledoc """
  Documentation for `Binta`.
  """

  @doc """
  post https://autoracex.connpass.com/ event to #autoracex channel on elixir.jp Slack

  """
  def run do
    event_now()
    |> build_message()
    |> post_message()
  end

  defp post_message(:error), do: :error

  defp post_message(message) do
    Binta.Slack.post(message)
  end

  defp build_message(:error), do: :error

  defp build_message(event_now) do
    Binta.Inoki.build_message()
    |> Kernel.<>("\n\n\n")
    |> Kernel.<>(event_now)
    |> Kernel.<>(
      "\n\nThis bot is https://github.com/TORIFUKUKaiou/binta .\nThanks for GitHub Actions workflows & William Henry \"Bill\" Gates III."
    )
  end

  defp event_now do
    case Binta.Connpass.event_now() do
      %{
        "title" => title,
        "event_url" => event_url,
        "accepted" => accepted,
        "started_at" => started_at,
        "ended_at" => ended_at
      } ->
        """
        *#{title}*
        #{started_at} 〜 #{ended_at}
        参加人数: #{accepted}人

        #{event_url}
        """

      _ ->
        :error
    end
  end
end
```

## test/binta_test.exs

testじゃなくてもいいのですが、[GitHub Actions Workflows](https://docs.github.com/ja/actions/using-workflows)はハマりがちになるのはわかりきっているので、`mix test`で動かすことにしてみました。

```elixir:test/binta_test.exs
defmodule BintaTest do
  use ExUnit.Case
  doctest Binta

  test "run" do
    Binta.run()
    assert true == true
  end
end
```

## .github/workflows/test.yml

```yml:.github/workflows/test.yml
name: test
on:
  workflow_dispatch:
  schedule:
    - cron: '30 23 * * *'

jobs:
  test:
    runs-on: ubuntu-22.04
    environment:
      name: secrets
    steps:
      - uses: actions/checkout@v2
      - uses: erlef/setup-beam@v1
        with:
          otp-version: '25.2'
          elixir-version: '1.14.2'
      - run: mix deps.get
      - run: mix test
        env:
          BINTA_SLACK_INCOMING_WEBHOOK_URL: ${{ secrets.BINTA_SLACK_INCOMING_WEBHOOK_URL }}
```

カンで書きました。

```
    environment:
      name: secrets
```

この記述がポイントだったのかもしれません。よくわかりません。とにかく上記でGitHubに設定した環境変数を読み出せるようになりました。
なにかのヒントになるかもしれませんので設定画面のスクリーンショットを貼っておきます。

![スクリーンショット 2022-12-31 16.14.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131808/9c30efc2-2169-acac-b652-91af9e02d6dd.png)

### mix test

[GitHub Actions Workflows](https://docs.github.com/ja/actions/using-workflows)上での`mix test`の動かし方は、@mnishiguchi さんの記事を参考にしました。
ありがとうーーーーッ！！！　ございます。

https://qiita.com/mnishiguchi/items/8e709ef617a3c3deedaa

### schedule イベントを使うと、スケジュールした時刻にワークフローをトリガーできます

[GitHub Actions Workflows](https://docs.github.com/ja/actions/using-workflows)での`cron` Likeな指定は以下をご参照ください。

https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#schedule

That's all!!!
完成です。:tada::tada::tada::tada::tada::tada::tada::tada::tada::tada:

![スクリーンショット 2022-12-31 14.49.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131808/84f4b3ef-cec3-208a-572c-0da3480ef7cf.png)

# 動かし方

念の為、ローカルマシンでの動かし方を書いておきます。
Incoming Web Hook URLの取得方法は下記のドキュメントをご参照ください。

https://api.slack.com/messaging/webhooks


```:CMD
export BINTA_SLACK_INCOMING_WEBHOOK_URL="https://hooks.slack.com/services/supersecret"

iex -S mix
```

```elixir
iex> Binta.run()
```

または

```:CMD
mix test
```

`mix test`でテスト以外のことを動かすのは当然ながら非推奨です。私はダメだなとおもいながら、やっています。相当たちが悪いわけです。




---

# Twitter

Twitterに制作過程をつぶやきました。
これでだいたいのことが思い出せます。

## 09:43 参加表明

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E5%A4%A7%E6%99%A6%E6%97%A5%E3%83%8F%E3%83%83%E3%82%AB%E3%82%BD%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#大晦日ハッカソン</a><br><br>Twitterに投稿（とうこん　闘魂）された「井大晦日ハッカソン」付きメッセージをとにかく「いいね」するボットを設置、イゴかしはじめました。<a href="https://twitter.com/hashtag/autoracex?src=hash&amp;ref_src=twsrc%5Etfw">#autoracex</a></p>&mdash; TORIFUKU Kaiou (@torifukukaiou) <a href="https://twitter.com/torifukukaiou/status/1608987105908387842?ref_src=twsrc%5Etfw">December 31, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 09:45 制作意図を表明

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E5%A4%A7%E6%99%A6%E6%97%A5%E3%83%8F%E3%83%83%E3%82%AB%E3%82%BD%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#大晦日ハッカソン</a><br><br>connpass に毎日登録しているもくもく会の開催通知をSlackチャンネルに投稿（とうこん闘魂する）ボットを作ります。「おもに」二人で令和の巌流島決戦をしているだけですので通知はいらないのですが自分の行動は極力ボットに任せたいとおもっています。<a href="https://twitter.com/hashtag/autoracex?src=hash&amp;ref_src=twsrc%5Etfw">#autoracex</a></p>&mdash; TORIFUKU Kaiou (@torifukukaiou) <a href="https://twitter.com/torifukukaiou/status/1608987734487760898?ref_src=twsrc%5Etfw">December 31, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 10:28 設計完了

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E5%A4%A7%E6%99%A6%E6%97%A5%E3%83%8F%E3%83%83%E3%82%AB%E3%82%BD%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#大晦日ハッカソン</a><br>設計図、指示書 <a href="https://t.co/SLEAXWDhX1">pic.twitter.com/SLEAXWDhX1</a></p>&mdash; TORIFUKU Kaiou (@torifukukaiou) <a href="https://twitter.com/torifukukaiou/status/1608998608124407810?ref_src=twsrc%5Etfw">December 31, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## コード作成

コードはさらさらさらっと書きました。
コードを書くうえで一番悩んだのはプロジェクト名です。
`binta`にしました。
**毎朝、朝一に猪木さんから闘魂ビンタをいただくイメージです。**


## [GitHub Actions Workflows](https://docs.github.com/ja/actions/using-workflows)の設定に悩み続ける

コードはできたので次は実行環境の構築です。
毎朝08:30にSlackチャンネルへメッセージを投稿（とうこん闘魂）したいわけです。

[GitHub Actions Workflows](https://docs.github.com/ja/actions/using-workflows)を使うことにしました。

環境変数がうまく読みだせませんでした。いろいろ試行錯誤を繰り返しました。いつものことです。あの`.yml`の書き方はよくわかりません。カンで書いています。

## 14:47 [GitHub Actions Workflows](https://docs.github.com/ja/actions/using-workflows)上で動作するようになる :tada::tada::tada:


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E5%A4%A7%E6%99%A6%E6%97%A5%E3%83%8F%E3%83%83%E3%82%AB%E3%82%BD%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#大晦日ハッカソン</a><br><br>完成しました！ <br>毎朝 08:30 に届くはずです。<br><br>次はQiitaに作成記録を残しておきます。<a href="https://twitter.com/hashtag/autoracex?src=hash&amp;ref_src=twsrc%5Etfw">#autoracex</a> <a href="https://t.co/LV8qiK9kcO">pic.twitter.com/LV8qiK9kcO</a></p>&mdash; TORIFUKU Kaiou (@torifukukaiou) <a href="https://twitter.com/torifukukaiou/status/1609064466163060736?ref_src=twsrc%5Etfw">December 31, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 16:45 報告書という名の後片付け

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E5%A4%A7%E6%99%A6%E6%97%A5%E3%83%8F%E3%83%83%E3%82%AB%E3%82%BD%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#大晦日ハッカソン</a><br><br>闘魂Elixir ── 2022-12-31 大晦日ハッカソン2022 をElixirで楽しむ！（元氣と闘魂を毎朝投稿（とうこん闘魂）する！） <a href="https://t.co/i7bWp1BvvB">https://t.co/i7bWp1BvvB</a> <a href="https://twitter.com/hashtag/Qiita?src=hash&amp;ref_src=twsrc%5Etfw">#Qiita</a> <br><br>完成🎉<br>元氣があればなんでもできる！<br>また来年の12-31にお会いしましょう！<br>よいお年を！<a href="https://twitter.com/hashtag/autoracex?src=hash&amp;ref_src=twsrc%5Etfw">#autoracex</a> <a href="https://twitter.com/hashtag/MyElixirStatus?src=hash&amp;ref_src=twsrc%5Etfw">#MyElixirStatus</a></p>&mdash; TORIFUKU Kaiou (@torifukukaiou) <a href="https://twitter.com/torifukukaiou/status/1609093302753832960?ref_src=twsrc%5Etfw">December 31, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## その後[Advent Of Code Day 5](https://adventofcode.com/2022/day/5)を楽しみました

<blockquote class="twitter-tweet"><p lang="en" dir="ltr"><a href="https://twitter.com/hashtag/%E5%A4%A7%E6%99%A6%E6%97%A5%E3%83%8F%E3%83%83%E3%82%AB%E3%82%BD%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#大晦日ハッカソン</a><br><br>I&#39;ve completed &quot;Supply Stacks&quot; - Day 5 - Advent of Code 2022 <a href="https://t.co/EnXouUid0U">https://t.co/EnXouUid0U</a> <a href="https://twitter.com/hashtag/AdventOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#AdventOfCode</a> <a href="https://t.co/NDw4NFgd6n">https://t.co/NDw4NFgd6n</a><a href="https://t.co/LnDP7TX4rx">https://t.co/LnDP7TX4rx</a><a href="https://t.co/xVsVNZXrf7">https://t.co/xVsVNZXrf7</a><a href="https://twitter.com/hashtag/MyElixirStatus?src=hash&amp;ref_src=twsrc%5Etfw">#MyElixirStatus</a></p>&mdash; TORIFUKU Kaiou (@torifukukaiou) <a href="https://twitter.com/torifukukaiou/status/1609155795958255617?ref_src=twsrc%5Etfw">December 31, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

https://qiita.com/torifukukaiou/items/a2888ac943fcfb1774a3

https://qiita.com/torifukukaiou/items/b9f2c101b1c10691e7ec

---

# さいごに

この記事では、[大晦日ハッカソン2022](https://omisoka-hackathon.connpass.com/event/269353/)に参加して制作した作品のことを書きました。
来年のことを言うと鬼に笑われると申しますが、もっと積極的に鬼といっしょになって笑おうではありませんか！
**元氣があればなんでもできる！**
また来年の12-31にお会いしましょう！
よいお年を！



**闘魂**とは、 **「己に打ち克つこと、そして闘いを通じて己の魂を磨いていくことである」** との猪木さんの言葉をそのまま胸に刻み込んでいます。
知っているだけで終わらせることなく、実行する、断行する、一歩を踏み出すことを自らの行動で示していきたいとおもいます。
**アントニオ猪木さんのメッセージから元氣をもらったものとして、それを次代に語り継ぎ、自分自身が「闘魂」を体現するものでありたいとおもいます。**

<font color="red">$\huge{１、２、３ ぁっダー！}$</font>


<iframe width="910" height="512" src="https://www.youtube.com/embed/AWxwmqzbOaw" title="燃える闘魂 アントニオ猪木  追悼VTR" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

https://www.youtube.com/watch?v=FSz7N5hCltw

---

https://qiita.com/torifukukaiou/items/5e96f4e9f12ec3c4b3f4

https://qiita.com/torifukukaiou/items/b6361f98194f3687a13c

https://qiita.com/torifukukaiou/items/4c35ace6db3f02ac3897

https://qiita.com/torifukukaiou/items/17d55cf896c24b13350e

https://qiita.com/torifukukaiou/items/44db8a4997812518730a




---

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>
<b><font color="red">$\huge{１、２、３ ぁっダー！}$</font></b>