# 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
```