# ElixirForum Discourse RSS OPML Generator ```elixir Mix.install([ {:kino, "~> 0.12.3"} ]) ``` ## Section ```elixir defmodule Discourse.OPML do defmodule Behaviour do @callback outline(list(String.t())) :: String.t() end def generate(usernames, forum_specific_generator) do outline = forum_specific_generator.outline(usernames) """ RSS OPML Subscriptions #{outline} """ end defmodule ElixirForum do @behaviour Discourse.OPML.Behaviour @impl true def outline(usernames) do inner_outlines = Enum.map(usernames, &outlines_for_user/1) """ #{inner_outlines} """ end defp outlines_for_user(username) do """ """ end end end ``` ```elixir default_usernames = [ "josevalim", "mhanberg", "wojtekmach", "nicd", "dorgan", "axelson", "benwilson512", "LostKobrakai", "Fl4m3Ph03n1x", "NobbZ", "hauleth", "astonj", "michalmuskala", "mbuhot", "ConnorRigby", "derpycoder" ] |> Enum.join("\n") form = Kino.Control.form( [ usernames: Kino.Input.textarea("Elixir forum usernames (one per line)", default: default_usernames) ], submit: "Generate OPML" ) ``` ```elixir output_frame = Kino.Frame.new() Kino.listen(form, fn event -> IO.inspect(event) %{origin: origin, data: %{usernames: usernames}} = event opml = usernames |> String.split() |> Enum.map(&String.downcase/1) |> Enum.sort() |> Discourse.OPML.generate(Discourse.OPML.ElixirForum) |> Kino.Text.new() Kino.Frame.render(output_frame, opml, to: origin) end) output_frame ```