From 5075e593dd428712c293b0aba654ecd32e9c5db0 Mon Sep 17 00:00:00 2001 From: Billal GHILAS Date: Thu, 22 Jan 2026 19:21:33 +0100 Subject: [PATCH 1/7] Add rtsp server --- lib/shinkai/application.ex | 3 +- lib/shinkai/sink/hls.ex | 2 + lib/shinkai/sink/rtmp.ex | 2 +- lib/shinkai/sources.ex | 2 +- lib/shinkai/sources/rtsp.ex | 24 +-- lib/shinkai/sources/rtsp/handler.ex | 33 +++++ lib/shinkai/sources/rtsp/media_processor.ex | 156 ++++++++++++++++++++ lib/shinkai/track.ex | 28 +++- mix.exs | 2 +- mix.lock | 4 +- 10 files changed, 224 insertions(+), 32 deletions(-) create mode 100644 lib/shinkai/sources/rtsp/handler.ex create mode 100644 lib/shinkai/sources/rtsp/media_processor.ex diff --git a/lib/shinkai/application.ex b/lib/shinkai/application.ex index 803f151..27b43c2 100644 --- a/lib/shinkai/application.ex +++ b/lib/shinkai/application.ex @@ -16,7 +16,8 @@ defmodule Shinkai.Application do {Sources.PublishManager, []}, {Registry, name: Sink.Registry, keys: :duplicate}, {Registry, name: Source.Registry, keys: :unique}, - {Task, fn -> Sources.start_all() end} + {Task, fn -> Sources.start_all() end}, + {RTSP.Server, handler: Sources.RTSP.Handler, port: 8554} ] children = diff --git a/lib/shinkai/sink/hls.ex b/lib/shinkai/sink/hls.ex index 0661846..9eeda22 100644 --- a/lib/shinkai/sink/hls.ex +++ b/lib/shinkai/sink/hls.ex @@ -71,6 +71,8 @@ defmodule Shinkai.Sink.Hls do ) end + Logger.info("[#{state.source_id}] [hls] start muxing") + audio_track = Enum.find(hls_tracks, fn t -> t.type == :audio end) video_track = Enum.find(hls_tracks, fn t -> t.type == :video end) diff --git a/lib/shinkai/sink/rtmp.ex b/lib/shinkai/sink/rtmp.ex index b3a87dd..6784ca1 100644 --- a/lib/shinkai/sink/rtmp.ex +++ b/lib/shinkai/sink/rtmp.ex @@ -56,7 +56,7 @@ defmodule Shinkai.Sink.RTMP do if unsupported_tracks != [] do Logger.warning( - "[#{state.source_id}] Ignore unsupported tracks: #{Enum.map_join(unsupported_tracks, ", ", & &1.codec)}" + "[#{state.source_id}] rtmp sink: ignore unsupported tracks: #{Enum.map_join(unsupported_tracks, ", ", & &1.codec)}" ) end diff --git a/lib/shinkai/sources.ex b/lib/shinkai/sources.ex index 6afb719..6f0aae6 100644 --- a/lib/shinkai/sources.ex +++ b/lib/shinkai/sources.ex @@ -26,7 +26,7 @@ defmodule Shinkai.Sources do [] -> if source.type == :publish do :ok = PublishManager.monitor(source, self()) - :ets.insert(:sources, {source.id, source}) + :ets.insert(:sources, {source.id, %{source | status: :streaming}}) end DynamicSupervisor.start_child( diff --git a/lib/shinkai/sources/rtsp.ex b/lib/shinkai/sources/rtsp.ex index 453cb79..d730fce 100644 --- a/lib/shinkai/sources/rtsp.ex +++ b/lib/shinkai/sources/rtsp.ex @@ -7,7 +7,6 @@ defmodule Shinkai.Sources.RTSP do import Shinkai.Utils - alias MediaCodecs.MPEG4 alias Shinkai.{Sources, Track} @timeout 6_000 @@ -100,30 +99,9 @@ defmodule Shinkai.Sources.RTSP do defp build_tracks(tracks) do tracks |> Enum.with_index(1) - |> Map.new(fn {track, id} -> - codec = codec(String.downcase(track.rtpmap.encoding)) - - {track.control_path, - Track.new( - id: id, - type: track.type, - codec: codec, - timescale: track.rtpmap.clock_rate, - priv_data: priv_data(codec, track.fmtp) - )} - end) + |> Map.new(fn {track, id} -> {track.control_path, Track.from_rtsp_track(id, track)} end) end - defp codec("mpeg4-generic"), do: :aac - defp codec(other), do: String.to_atom(other) - - defp priv_data(:aac, fmtp), do: MPEG4.AudioSpecificConfig.parse(fmtp.config) - defp priv_data(:h264, %{sprop_parameter_sets: nil}), do: nil - defp priv_data(:h264, %{sprop_parameter_sets: pps}), do: {pps.sps, [pps.pps]} - defp priv_data(:h265, %{sprop_vps: nil}), do: nil - defp priv_data(:h265, fmtp), do: {hd(fmtp.sprop_vps), hd(fmtp.sprop_sps), fmtp.sprop_pps} - defp priv_data(_codec, _fmtp), do: nil - defp to_packets(samples, track_id) when is_list(samples) do Enum.map(samples, &packet_from_sample(track_id, &1)) end diff --git a/lib/shinkai/sources/rtsp/handler.ex b/lib/shinkai/sources/rtsp/handler.ex new file mode 100644 index 0000000..be688d2 --- /dev/null +++ b/lib/shinkai/sources/rtsp/handler.ex @@ -0,0 +1,33 @@ +defmodule Shinkai.Sources.RTSP.Handler do + @moduledoc false + + use RTSP.Server.ClientHandler + + require Logger + + alias Shinkai.Sources + alias Shinkai.Sources.RTSP.MediaProcessor + + @impl true + def init(_options) do + nil + end + + @impl true + def handle_record(path, tracks, _state) do + with {:ok, source_id} <- source_id(path), + source <- %Sources.Source{id: source_id, type: :publish}, + {:ok, _pid} <- Sources.start(source) do + Logger.info("[RTSP] is publishing to: #{path}") + {:ok, MediaProcessor.new(source_id, tracks)} + end + end + + @impl true + def handle_media(control_path, sample, state) do + MediaProcessor.handle_sample(control_path, sample, state) + end + + defp source_id("/"), do: {:error, :missing_path} + defp source_id(<<"/", path::binary>>), do: {:ok, String.replace(path, "/", "-")} +end diff --git a/lib/shinkai/sources/rtsp/media_processor.ex b/lib/shinkai/sources/rtsp/media_processor.ex new file mode 100644 index 0000000..ae33fef --- /dev/null +++ b/lib/shinkai/sources/rtsp/media_processor.ex @@ -0,0 +1,156 @@ +defmodule Shinkai.Sources.RTSP.MediaProcessor do + @moduledoc false + + require Logger + + alias MediaCodecs.AV1 + alias Shinkai.{Sources, Track} + + @max_buffer 1000 + + @type t :: %{ + source_id: Sources.Source.id(), + tracks: %{String.t() => Track.t()}, + buffer?: boolean(), + packets: [Shinkai.Packet.t()], + buffered_packets: non_neg_integer() + } + + @spec new(Sources.Source.id(), [map()]) :: t() + def new(source_id, tracks) do + tracks = + tracks + |> Enum.with_index(1) + |> Map.new(fn {track, id} -> {track.control_path, Track.from_rtsp_track(id, track)} end) + + ready? = all_tracks_initialized?(Map.values(tracks)) + + Logger.info( + "[#{source_id}] reading #{map_size(tracks)} track(s) (#{Enum.map_join(Map.values(tracks), ", ", & &1.codec)})" + ) + + if ready? do + Phoenix.PubSub.broadcast!( + Shinkai.PubSub, + Shinkai.Utils.tracks_topic(source_id), + {:tracks, Map.values(tracks)} + ) + end + + %{ + source_id: source_id, + tracks: tracks, + buffer?: not ready?, + packets: [], + packets_topic: Shinkai.Utils.packets_topic(source_id), + buffered_packets: 0 + } + end + + @spec handle_sample(String.t(), tuple(), t()) :: t() + def handle_sample(id, sample, %{buffer?: false} = state) do + track = state.tracks[id] + packet = to_packet(track, sample) + Phoenix.PubSub.broadcast!(Shinkai.PubSub, state.packets_topic, {:packet, packet}) + state + end + + def handle_sample(id, sample, state) do + track = state.tracks[id] + + case maybe_init_track(track, sample) do + {:ok, updated_track} -> + tracks = Map.put(state.tracks, id, updated_track) + + state = %{ + state + | tracks: tracks, + packets: [to_packet(updated_track, sample) | state.packets], + buffered_packets: state.buffered_packets + 1 + } + + cond do + all_tracks_initialized?(Map.values(tracks)) -> unbuffer(state) + state.buffered_packets > @max_buffer -> %{state | packets: [], buffered_packets: 0} + true -> state + end + + :discard -> + state + end + end + + defp all_tracks_initialized?(tracks) do + Enum.all?(tracks, fn + %{type: :video, priv_data: nil} -> false + _track -> true + end) + end + + defp maybe_init_track(%{type: :video, priv_data: nil}, {_payload, _pts, false, _timestamp}) do + :discard + end + + defp maybe_init_track( + %{type: :video, priv_data: nil} = track, + {payload, _pts, true, _timestamp} + ) do + with {:ok, priv_data} <- look_for_parameter_sets(track.codec, payload) do + {:ok, %{track | priv_data: priv_data}} + end + end + + defp maybe_init_track(track, _sample), do: {:ok, track} + + defp look_for_parameter_sets(:h264, payload) do + {{sps, pps}, _rest} = MediaCodecs.H264.pop_parameter_sets(payload) + if sps != [] and pps != [], do: {:ok, {List.first(sps), pps}}, else: :discard + end + + defp look_for_parameter_sets(:h265, payload) do + {{vps, sps, pps}, _rest} = MediaCodecs.H265.pop_parameter_sets(payload) + + if vps != [] and sps != [] and pps != [], + do: {:ok, {List.first(vps), List.first(sps), pps}}, + else: :discard + end + + defp look_for_parameter_sets(:av1, payload) do + case Enum.find(payload, &(AV1.OBU.type(&1) == :sequence_header)) do + nil -> :discard + seq_header_obu -> {:ok, seq_header_obu} + end + end + + defp unbuffer(state) do + Phoenix.PubSub.broadcast!( + Shinkai.PubSub, + Shinkai.Utils.tracks_topic(state.source_id), + {:tracks, Map.values(state.tracks)} + ) + + state.packets + |> Enum.reverse() + |> List.flatten() + |> Enum.each(&Phoenix.PubSub.broadcast!(Shinkai.PubSub, state.packets_topic, {:packet, &1})) + + %{state | buffer?: false, packets: []} + end + + defp to_packet(track, {payload, pts, sync?, _timestamp}) do + payload = + case track.codec do + :av1 -> Enum.map(payload, &AV1.OBU.set_size_flag/1) + _ -> payload + end + + Shinkai.Packet.new(payload, + track_id: track.id, + dts: pts, + pts: pts, + sync?: sync? + ) + end + + defp to_packet(track, samples), do: Enum.map(samples, &to_packet(track, &1)) +end diff --git a/lib/shinkai/track.ex b/lib/shinkai/track.ex index 83232ca..d330e40 100644 --- a/lib/shinkai/track.ex +++ b/lib/shinkai/track.ex @@ -28,6 +28,19 @@ defmodule Shinkai.Track do struct(__MODULE__, opts) end + @doc false + def from_rtsp_track(id, track) do + codec = rtpmap_codec(String.downcase(track.rtpmap.encoding)) + + %__MODULE__{ + id: id, + type: track.type, + codec: codec, + timescale: track.rtpmap.clock_rate, + priv_data: fmtp_priv_data(codec, track.fmtp) + } + end + @doc false @spec to_hls_track(t()) :: HLX.Track.t() def to_hls_track(track) do @@ -80,9 +93,18 @@ defmodule Shinkai.Track do end defp rtmp_init_data(:av1, config_obu) do - <<_header::binary-size(8), dcr::binary>> = - Box.Av1c.new(config_obu) |> Box.serialize() |> IO.iodata_to_binary() - + <<_header::binary-size(8), dcr::binary>> = config_obu |> Box.Av1c.new() |> Box.serialize() dcr end + + defp rtpmap_codec("mpeg4-generic"), do: :aac + defp rtpmap_codec(other), do: String.to_atom(other) + + defp fmtp_priv_data(:aac, %{config: nil}), do: raise("Missing AAC config in FMTP") + defp fmtp_priv_data(:aac, fmtp), do: MPEG4.AudioSpecificConfig.parse(fmtp.config) + defp fmtp_priv_data(:h264, %{sprop_parameter_sets: nil}), do: nil + defp fmtp_priv_data(:h264, %{sprop_parameter_sets: pps}), do: {pps.sps, [pps.pps]} + defp fmtp_priv_data(:h265, %{sprop_vps: nil}), do: nil + defp fmtp_priv_data(:h265, fmtp), do: {hd(fmtp.sprop_vps), hd(fmtp.sprop_sps), fmtp.sprop_pps} + defp fmtp_priv_data(_codec, _fmtp), do: nil end diff --git a/mix.exs b/mix.exs index 040dbcd..8ebb00f 100644 --- a/mix.exs +++ b/mix.exs @@ -32,7 +32,7 @@ defmodule Shinkai.MixProject do defp deps do [ {:phoenix_pubsub, "~> 2.2"}, - {:rtsp, "~> 0.7.0"}, + {:rtsp, "~> 0.8.0"}, {:hlx, "~> 0.5.0"}, {:ex_rtmp, "~> 0.4.1"}, {:yaml_elixir, "~> 2.12"}, diff --git a/mix.lock b/mix.lock index 144f74c..ff5f0f0 100644 --- a/mix.lock +++ b/mix.lock @@ -9,7 +9,7 @@ "ex_doc": {:hex, :ex_doc, "0.39.3", "519c6bc7e84a2918b737aec7ef48b96aa4698342927d080437f61395d361dcee", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "0590955cf7ad3b625780ee1c1ea627c28a78948c6c0a9b0322bd976a079996e1"}, "ex_flv": {:hex, :ex_flv, "0.4.0", "9e43c833b5cbe3c6e21bb2651ae7650f3ec939eac8079f34efed8f813bf9133d", [:mix], [], "hexpm", "484f6990791e0c8862a88e4150f004deb067c7342e40b779c82d5c9a9c057969"}, "ex_m3u8": {:hex, :ex_m3u8, "0.15.4", "66f6ec7e4fb7372c48032db1c2d4a3e6c2bbbde2d1d9a1098986e3caa0ab7a55", [:mix], [{:nimble_parsec, "~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:typed_struct, "~> 0.3.0", [hex: :typed_struct, repo: "hexpm", optional: false]}], "hexpm", "ec03aa516919e0c8ec202da55f609b763bd7960195a3388900090fcad270c873"}, - "ex_mp4": {:hex, :ex_mp4, "0.14.1", "6152b9b981d5d6d5069d8dccd3d60f4f4be135f758f9b4bae039018119fdf089", [:mix], [{:media_codecs, "~> 0.10.0", [hex: :media_codecs, repo: "hexpm", optional: true]}, {:ratio, "~> 4.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:table_rex, "~> 4.0", [hex: :table_rex, repo: "hexpm", optional: true]}], "hexpm", "f9f9630406371d19691673acea83f378b96e5c1961eb28436aa5d8ded148188c"}, + "ex_mp4": {:hex, :ex_mp4, "0.14.2", "c362b27c50fa8d5a16e4f5652963fcc47d5a61215eb729a0d6f8ec521575ed6d", [:mix], [{:media_codecs, "~> 0.10.0", [hex: :media_codecs, repo: "hexpm", optional: true]}, {:ratio, "~> 4.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:table_rex, "~> 4.0", [hex: :table_rex, repo: "hexpm", optional: true]}], "hexpm", "3712c62a93ddde83419bb22e382a145c6527c8b002d8a22348202828022e1041"}, "ex_rtcp": {:hex, :ex_rtcp, "0.4.1", "e0f0c0baf329de92059e2afdc34d66d61f8b983f0801daa10f1a712360919e45", [:mix], [], "hexpm", "83ab3dffcffc6149eb404f1e1b1b62f755efd54c818e27c2c88e6ba3341c5d41"}, "ex_rtmp": {:hex, :ex_rtmp, "0.4.1", "1be8a1f75f2940d59ae07939218d1cdddac85de118370f0f001f816b8bac4576", [:mix], [{:ex_flv, "~> 0.4.0", [hex: :ex_flv, repo: "hexpm", optional: false]}], "hexpm", "58e1f993c575b6604e8256ed89887fcb7f7b80d0627e0bd71e9eea98bbe79766"}, "ex_rtp": {:hex, :ex_rtp, "0.4.0", "1f1b5c1440a904706011e3afbb41741f5da309ce251cb986690ce9fd82636658", [:mix], [], "hexpm", "0f72d80d5953a62057270040f0f1ee6f955c08eeae82ac659c038001d7d5a790"}, @@ -34,7 +34,7 @@ "plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"}, "qex": {:hex, :qex, "0.5.1", "0d82c0f008551d24fffb99d97f8299afcb8ea9cf99582b770bd004ed5af63fd6", [:mix], [], "hexpm", "935a39fdaf2445834b95951456559e9dc2063d0a055742c558a99987b38d6bab"}, "ratio": {:hex, :ratio, "4.0.1", "3044166f2fc6890aa53d3aef0c336f84b2bebb889dc57d5f95cc540daa1912f8", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:numbers, "~> 5.2.0", [hex: :numbers, repo: "hexpm", optional: false]}], "hexpm", "c60cbb3ccdff9ffa56e7d6d1654b5c70d9f90f4d753ab3a43a6bf40855b881ce"}, - "rtsp": {:hex, :rtsp, "0.7.0", "b98706e0d89dc555bee1b33266a1bf4a5c593c3b39c2be1e9781025f6305d691", [:mix], [{:ex_mp4, "~> 0.14.0", [hex: :ex_mp4, repo: "hexpm", optional: true]}, {:ex_rtcp, "~> 0.4.0", [hex: :ex_rtcp, repo: "hexpm", optional: false]}, {:ex_rtp, "~> 0.4.0", [hex: :ex_rtp, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 1.0", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:media_codecs, "~> 0.10.0", [hex: :media_codecs, repo: "hexpm", optional: false]}, {:membrane_rtsp, "~> 0.11.0", [hex: :membrane_rtsp, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}], "hexpm", "fa8f011c8eb702481ada4432d2d62065943f3a93c242d728d7bf7c680297a0a1"}, + "rtsp": {:hex, :rtsp, "0.8.0", "1e70337387eaed5f6de67997010b690633c1df7a178acf144974908eaf8f742d", [:mix], [{:ex_mp4, "~> 0.14.0", [hex: :ex_mp4, repo: "hexpm", optional: true]}, {:ex_rtcp, "~> 0.4.0", [hex: :ex_rtcp, repo: "hexpm", optional: false]}, {:ex_rtp, "~> 0.4.0", [hex: :ex_rtp, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 1.0", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:media_codecs, "~> 0.10.0", [hex: :media_codecs, repo: "hexpm", optional: false]}, {:membrane_rtsp, "~> 0.11.0", [hex: :membrane_rtsp, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}], "hexpm", "808670602b19fa8a4568d8557bbede6baf8170ccd7303bddc0d581540700f62c"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "thousand_island": {:hex, :thousand_island, "1.4.3", "2158209580f633be38d43ec4e3ce0a01079592b9657afff9080d5d8ca149a3af", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6e4ce09b0fd761a58594d02814d40f77daff460c48a7354a15ab353bb998ea0b"}, "typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"}, From 0650cbd910ccabafbb05a5b6926e0ccfeb73d319 Mon Sep 17 00:00:00 2001 From: Billal GHILAS Date: Thu, 22 Jan 2026 20:02:49 +0100 Subject: [PATCH 2/7] Use media processor in rtsp client --- lib/shinkai/sources/rtsp.ex | 63 +++++++------------------------------ 1 file changed, 11 insertions(+), 52 deletions(-) diff --git a/lib/shinkai/sources/rtsp.ex b/lib/shinkai/sources/rtsp.ex index d730fce..8b97724 100644 --- a/lib/shinkai/sources/rtsp.ex +++ b/lib/shinkai/sources/rtsp.ex @@ -5,9 +5,8 @@ defmodule Shinkai.Sources.RTSP do require Logger - import Shinkai.Utils - - alias Shinkai.{Sources, Track} + alias Shinkai.Sources + alias Shinkai.Sources.RTSP.MediaProcessor @timeout 6_000 @reconnect_timeout 5_000 @@ -21,7 +20,7 @@ defmodule Shinkai.Sources.RTSP do def init(source) do Logger.info("[#{source.id}] Starting new rtsp source") - {:ok, pid} = RTSP.start_link(stream_uri: source.uri) + {:ok, pid} = RTSP.start_link(stream_uri: source.uri, transport: {:udp, 10000, 20000}) if function_exported?(Process, :set_label, 1) do # credo:disable-for-next-line @@ -32,7 +31,7 @@ defmodule Shinkai.Sources.RTSP do id: source.id, rtsp_pid: pid, tracks: %{}, - packets_topic: packets_topic(source.id) + media_processor: nil } {:ok, state, {:continue, :connect}} @@ -45,21 +44,15 @@ defmodule Shinkai.Sources.RTSP do def handle_info(:reconnect, state), do: do_connect(state) def handle_info({:rtsp, _pid, {id, sample_or_samples}}, state) do - :ok = - Phoenix.PubSub.broadcast( - Shinkai.PubSub, - state.packets_topic, - {:packet, to_packets(sample_or_samples, state.tracks[id].id)} - ) - - {:noreply, state} + media_processor = MediaProcessor.handle_sample(id, sample_or_samples, state.media_processor) + {:noreply, %{state | media_processor: media_processor}} end @impl true def handle_info({:rtsp, pid, :session_closed}, %{rtsp_pid: pid} = state) do Logger.error("[#{state.id}] rtsp client disconnected") - Phoenix.PubSub.broadcast!(Shinkai.PubSub, state_topic(state.id), :disconnected) - Sources.update_source_status(state.id, :failed) + Phoenix.PubSub.broadcast!(Shinkai.PubSub, Shinkai.Utils.state_topic(state.id), :disconnected) + update_status(state.id, :failed) Process.send_after(self(), :reconnect, @reconnect_timeout) {:noreply, state} end @@ -72,21 +65,10 @@ defmodule Shinkai.Sources.RTSP do defp do_connect(state) do with {:ok, tracks} <- RTSP.connect(state.rtsp_pid, @timeout), - tracks <- build_tracks(tracks), :ok <- RTSP.play(state.rtsp_pid) do - codecs = tracks |> Map.values() |> Enum.map_join(", ", & &1.codec) - Logger.info("[#{state.id}] start reading from #{map_size(tracks)} tracks (#{codecs})") - update_status(state, :streaming) - - :ok = - Phoenix.PubSub.broadcast( - Shinkai.PubSub, - tracks_topic(state.id), - {:tracks, Map.values(tracks)} - ) - - {:noreply, %{state | tracks: tracks}} + media_processor = MediaProcessor.new(state.id, tracks) + {:noreply, %{state | media_processor: media_processor}} else {:error, reason} -> Logger.error("[#{state.id}] rtsp connection failed: #{inspect(reason)}") @@ -96,28 +78,5 @@ defmodule Shinkai.Sources.RTSP do end end - defp build_tracks(tracks) do - tracks - |> Enum.with_index(1) - |> Map.new(fn {track, id} -> {track.control_path, Track.from_rtsp_track(id, track)} end) - end - - defp to_packets(samples, track_id) when is_list(samples) do - Enum.map(samples, &packet_from_sample(track_id, &1)) - end - - defp to_packets(sample, track_id), do: packet_from_sample(track_id, sample) - - defp packet_from_sample(track_id, {payload, pts, sync?, _timestamp}) do - Shinkai.Packet.new(payload, - track_id: track_id, - dts: pts, - pts: pts, - sync?: sync? - ) - end - - defp update_status(state, status) do - Sources.update_source_status(state.id, status) - end + defp update_status(state, status), do: Sources.update_source_status(state.id, status) end From e9f74e91db5b19d427e040c596d65ca9535f560f Mon Sep 17 00:00:00 2001 From: Billal GHILAS Date: Thu, 22 Jan 2026 20:06:32 +0100 Subject: [PATCH 3/7] Fix test --- lib/shinkai/sources/rtsp.ex | 4 ++-- test/shinkai/sources/rtsp_test.exs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/shinkai/sources/rtsp.ex b/lib/shinkai/sources/rtsp.ex index 8b97724..c5ed39a 100644 --- a/lib/shinkai/sources/rtsp.ex +++ b/lib/shinkai/sources/rtsp.ex @@ -20,7 +20,7 @@ defmodule Shinkai.Sources.RTSP do def init(source) do Logger.info("[#{source.id}] Starting new rtsp source") - {:ok, pid} = RTSP.start_link(stream_uri: source.uri, transport: {:udp, 10000, 20000}) + {:ok, pid} = RTSP.start_link(stream_uri: source.uri) if function_exported?(Process, :set_label, 1) do # credo:disable-for-next-line @@ -52,7 +52,7 @@ defmodule Shinkai.Sources.RTSP do def handle_info({:rtsp, pid, :session_closed}, %{rtsp_pid: pid} = state) do Logger.error("[#{state.id}] rtsp client disconnected") Phoenix.PubSub.broadcast!(Shinkai.PubSub, Shinkai.Utils.state_topic(state.id), :disconnected) - update_status(state.id, :failed) + update_status(state, :failed) Process.send_after(self(), :reconnect, @reconnect_timeout) {:noreply, state} end diff --git a/test/shinkai/sources/rtsp_test.exs b/test/shinkai/sources/rtsp_test.exs index c17b13c..d363616 100644 --- a/test/shinkai/sources/rtsp_test.exs +++ b/test/shinkai/sources/rtsp_test.exs @@ -31,7 +31,7 @@ defmodule Shinkai.Sources.RTSPTest do id: 1, type: :video, codec: :h264, - timescale: 15_360, + timescale: 90_000, priv_data: {<<103, 66, 192, 12, 217, 3, 196, 254, 95, 252, 2, 32, 2, 28, 64, 0, 0, 3, 0, 64, 0, 0, 15, 3, 197, 10, 146>>, [<<104, 203, 131, 203, 32>>]} From fa4de76c376d78afd95dfe4f9390b776be2ab915 Mon Sep 17 00:00:00 2001 From: Billal GHILAS Date: Fri, 23 Jan 2026 14:20:16 +0100 Subject: [PATCH 4/7] Add tests --- lib/shinkai/sink/hls.ex | 60 +++---- lib/shinkai/sources/rtsp/handler.ex | 5 + lib/shinkai/sources/rtsp/media_processor.ex | 9 + test/fixtures/big_buck_av1_opus.mp4 | Bin 0 -> 172548 bytes test/shinkai/pipeline_test.exs | 147 +++++++++++------ test/support/rtmp/mp4_to_flv.ex | 21 +++ test/support/rtsp/publisher.ex | 172 ++++++++++++++++++++ 7 files changed, 332 insertions(+), 82 deletions(-) create mode 100644 test/fixtures/big_buck_av1_opus.mp4 create mode 100644 test/support/rtsp/publisher.ex diff --git a/lib/shinkai/sink/hls.ex b/lib/shinkai/sink/hls.ex index 9eeda22..9a44803 100644 --- a/lib/shinkai/sink/hls.ex +++ b/lib/shinkai/sink/hls.ex @@ -42,10 +42,13 @@ defmodule Shinkai.Sink.Hls do File.rm_rf!(hls_config[:storage_dir]) :ok = Phoenix.PubSub.subscribe(Shinkai.PubSub, tracks_topic(id)) + :ok = Phoenix.PubSub.subscribe(Shinkai.PubSub, packets_topic(id)) :ok = Phoenix.PubSub.subscribe(Shinkai.PubSub, state_topic(id)) {:ok, _} = RequestHolder.start_link(:"request_holder_#{id}") + Process.flag(:trap_exit, true) + {:ok, %{ writer: Writer.new!(hls_config), @@ -91,7 +94,10 @@ defmodule Shinkai.Sink.Hls do end buffer? = length(hls_tracks) > 1 and Enum.any?(hls_tracks, &(&1.type == :video)) - :ok = PubSub.subscribe(Shinkai.PubSub, packets_topic(state.source_id)) + + if hls_tracks == [] do + :ok = PubSub.unsubscribe(Shinkai.PubSub, packets_topic(state.source_id)) + end {:noreply, %{ @@ -102,30 +108,45 @@ defmodule Shinkai.Sink.Hls do }} end - def handle_info({:packet, packets}, state) when is_list(packets) do - {:noreply, Enum.reduce(packets, state, &do_handle_packet/2)} - end - @impl true - def handle_info({:packet, packet}, state) do + def handle_info({:packet, %Shinkai.Packet{} = packet}, state) do {:noreply, do_handle_packet(packet, state)} end + def handle_info({:packet, packets}, state) do + {:noreply, Enum.reduce(packets, state, &do_handle_packet/2)} + end + @impl true def handle_info(:disconnected, state) do :ok = Writer.close(state.writer) - :ok = PubSub.unsubscribe(Shinkai.PubSub, packets_topic(state.source_id)) :ok = PubSub.local_broadcast(Shinkai.PubSub, sink_topic(state.source_id), {:hls, :done}) {:noreply, %{state | writer: Writer.new!(state.config), last_sample: %{}, packets: [], buffer?: false}} end - defp do_handle_packet(%{track_id: id}, state) when not is_map_key(state.tracks, id) do - state + defp do_handle_packet(packet, %{buffer?: false} = state) + when is_map_key(state.tracks, packet.track_id) do + case Map.fetch(state.last_sample, packet.track_id) do + :error -> + last_samples = Map.put(state.last_sample, packet.track_id, packet_to_sample(packet)) + %{state | last_sample: last_samples} + + {:ok, last_sample} -> + variant_name = state.tracks[packet.track_id].type |> to_string() + sample = packet_to_sample(packet) + last_sample = %{last_sample | duration: sample.dts - last_sample.dts} + + %{ + state + | writer: Writer.write_sample(state.writer, variant_name, last_sample), + last_sample: Map.put(state.last_sample, packet.track_id, sample) + } + end end - defp do_handle_packet(packet, %{buffer?: true} = state) do + defp do_handle_packet(packet, state) when is_map_key(state.tracks, packet.track_id) do # buffer until we get a video packet # and then drop all packets with dts < dts of that video packet track = state.tracks[packet.track_id] @@ -145,24 +166,7 @@ defmodule Shinkai.Sink.Hls do end end - defp do_handle_packet(packet, state) do - case Map.fetch(state.last_sample, packet.track_id) do - :error -> - last_samples = Map.put(state.last_sample, packet.track_id, packet_to_sample(packet)) - %{state | last_sample: last_samples} - - {:ok, last_sample} -> - variant_name = state.tracks[packet.track_id].type |> to_string() - sample = packet_to_sample(packet) - last_sample = %{last_sample | duration: sample.dts - last_sample.dts} - - %{ - state - | writer: Writer.write_sample(state.writer, variant_name, last_sample), - last_sample: Map.put(state.last_sample, packet.track_id, sample) - } - end - end + defp do_handle_packet(_packet, state), do: state defp reject?(packet, state, max_dts) do track = state.tracks[packet.track_id] diff --git a/lib/shinkai/sources/rtsp/handler.ex b/lib/shinkai/sources/rtsp/handler.ex index be688d2..3bf576b 100644 --- a/lib/shinkai/sources/rtsp/handler.ex +++ b/lib/shinkai/sources/rtsp/handler.ex @@ -28,6 +28,11 @@ defmodule Shinkai.Sources.RTSP.Handler do MediaProcessor.handle_sample(control_path, sample, state) end + @impl true + def handle_closed_connection(state) do + MediaProcessor.close(state) + end + defp source_id("/"), do: {:error, :missing_path} defp source_id(<<"/", path::binary>>), do: {:ok, String.replace(path, "/", "-")} end diff --git a/lib/shinkai/sources/rtsp/media_processor.ex b/lib/shinkai/sources/rtsp/media_processor.ex index ae33fef..ec39ebb 100644 --- a/lib/shinkai/sources/rtsp/media_processor.ex +++ b/lib/shinkai/sources/rtsp/media_processor.ex @@ -80,6 +80,15 @@ defmodule Shinkai.Sources.RTSP.MediaProcessor do end end + @spec close(t()) :: :ok + def close(state) do + Phoenix.PubSub.broadcast!( + Shinkai.PubSub, + Shinkai.Utils.state_topic(state.source_id), + :disconnected + ) + end + defp all_tracks_initialized?(tracks) do Enum.all?(tracks, fn %{type: :video, priv_data: nil} -> false diff --git a/test/fixtures/big_buck_av1_opus.mp4 b/test/fixtures/big_buck_av1_opus.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..a27cf8303552759b196a9c115b87f8cb83a91890 GIT binary patch literal 172548 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

|R8eJ2D`=HAWS0*5>9=wCL#3c;# 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

t}0u#wIeHT@a zb2*tu9u!K=Oi3BRmgW0Ec)@(MRA_6_LQDfv>H#Tf<)+>bG#69)fN{|R*oc&xX}EHM z2E%`Uh5E_73*CukPMu*5k!dYq(>Qk%!_?c7N4O-yG5-}AuTL7P($dG~H)S$f-@knJ z9q5>zIt03m2TgvYgPeMY8m{D1-WKDHhTBNtZJpWpr~YDhuwS;275lFZsG{+VQ9skK zf?e<*9mRMbJ%=;`w3Z*yYNwV;MnvTfuPAa)PO)l{h@T92$P^X{HJlfUB??S%uZS&E zF}zE>U>B_r-LKLoArhWNSRo`RY@^%bFXYb5OIz35KoxR^#m=gs7VowW0T($t)8uUB z|Mw-q9a5y*Aj5xy3n(C>Mg19!x@5Z~riyE~khmI|_AC7N?+Z393rU1jH9GG{g&k3o zE^$S=yN0hYdNu^m&*iyc!tR*`k+H5k9gSeM^@qffy_~-=OYkU3DLJe(ru!-!;9E$i zaHj!LyNi^GsR=PO2!}}#9!t|eSw_SDe@$tBK69d9_{jQBJ~%sK?AIB7K9AfASqh+6 z4OM_$?c!I6*SK__ySoQrULdj$I^sgx8kmp!csC+T2EG8lym=H|yN%IO{m)p@hF(P@ z81NtNnrd`3-2AoAYjrkA`;;v8}Eda&^7liMxXY%Q`aPc=YWL>Gf z;swJ@hiHz_!Boh}In`gywM=ct4Ml#>IY)t57T6rE2)qjQ2*GsYfW}`Btp&rF7F{bc zrA4!RA7+-cb-;eVXdXp3Yt0)C*L;b^UXz1S@$_p@n7)}TX?opO5g3k$TT4bB^ocPF zUnRWgc<&0_Ha#j6yA?8HntngL{2|8br`9faM{CW@f^rI3HgP9mk|62p

@l3latn?bP93sc?YpSq2t*>eN@Z->-9g|BSLRT#O0u#y*WtQc#?Vz7U zjq)5JA3KuzoZv_`CI6`FeVT3xm_y1BN#Xl-SbkGS#NJ!qlgZOWj+9)+YxhGTot#)$ zfRz1RNZ5wl|+P*ns^ zvmXs4F6oJ0GA1H8RC<%Atn^FUyI13rDA4HqGWHC61s58qu+Tm{LP4nlAF|-{3eKm% zQ1n?=0$}x57Eo#e*#K#4_25PvqK7>Adi(8`mb}2s8~k9n#7Obfi*iiXxA%W;35QrZ zQ>Yy9F`vlS2rFjAwd$(aX*(2KYIDIzlbNn@LuTbiW*7KKQ=6o6V-nMRHb*nV8RtB3 zPj%x*=N-qPaTj2jNtUcZB5ypy2QwlD;NKXGF2&E_c<$3;k(fxisXVQ0OY$?y&>>|& zS;!I;{Xc4&=aA)ivQ*(&1cJ%NsdA(kdlF!eyW?h4H%_Flju!gIQ6dOJyamF!=w}j8 zxi%Wv`VzcdpjE@a;TGv662&|H>+pNthG;>dUcb*`f-83YU+ z6Y#2P5}8@u*Q82$g-Zs)bk58$`Y&Ms1#t*GogwVkAuXHM_MD@|vUFdWE-+%me*7Jn zMa6`3<3=I=V%8 ze3!i2KIpLAZY#MnKaG713`FQmZTvU*Tr$q(lR+|E{LcF2j1*B!uG0-$jfk_K%g&&= zKRP)?z&8f76bC*%#Trjna8yU5I~K0I@2AGh!FDV9C6k(`_c9E+4p}v-edTX zI)0Rx3xa4=^F|ZAVr9=C+Y+|dbp_nh9ci>13X_i2!R4|Wu~L1|JBA+KL)`ipdn_0m z3r$Vjov{tXFm*K)=OkHQ{Du-p*4KjwD$)iC9pNWzor9Gb^U0OE{~M*w%BD1M;a628 z=kmw!3}`O&!2;w=4sBpD$*mbp$ z^C>;*X>8*=5P#D?)ae5y`U}Sxq&7?n&UGeZxUIbsTB`UhcFuwm=Qn_2AmuUNlKK&i<6w`TFE87}nD$=)@xb{PpIK_MD3ZW@JS^ z)@CoN%3--FdOhu7+#;q2JmRW8=Kh3a0U=bD!d9;PXo@|;e5k3j6=)ft4{Ymb>26j5 z6=w`U`W%Re(16Q8Do0Y)Jd3BU@0EVUF2SHhXa9aoD(53z86Y5IU22J~ro&RowT58! z`}&qp?E5*xq!WfNxd}REUb&EALR(M^7y0!5t#_2c^aq@%TF2dRK)+{_lBiTW!y%?r zimYWWNdUX|A=3!ilDjqXBB&%X>6s>AjqKICcu@1YaqceKmJPFM-&ZsMpDm&r%D5}x zSLkKmB~OWkpeddWwHKU+Z>=?23pSU*q~0Q`5Z2>UNACz%Jvp=HoB#!90e~a&U{$&( ztsGuoI2-J+?CyO;bw}rcoKzrZ)Pr(Ghh$2+fY^~)Q{&i^PSW3;k*5ydV{TH7mz(LH zjVnof21K@Pf=&ncJ$3W52Osqm$B-=hHQf$fM{03Wdw-FJ6W3jovsI0Dnjd4vkMq5U zlyM|3Mi`*pQq=-0-8#(ft8-mthb43Z;q=4NjXDYfe^vA>>aV@j>1$!L!70OJ%w+94 zR9+?xhOJ9)3QGPFfak4YFqT;`n+QucmEvrtKA*clZs#33nuEhCG{+ib7?>+uji37o zBpo0|kgk6VfIyz*vq~$E3cIC3w^#}{CaZr#D&}Q%&^#mbOzQ&*DgQ=1Nte^`QZ*r~ z5o_n(3=(k6w6MDV+=JP|!qcc)aepQpHf{Mc+x&I1#Sz?Y5NctIfNQjBZ%W_Q)_B>C zD;GYAYh1n_Ufk0{EF7sy3s%T08UzkBSzgz8jF3c6_Le#j;fTWuqSDy9vx_t6PM|#L z^seuFq~x&WH6i6seCH}?;IVabX<>XnDV1|uOzbv9^INWeg<_jWvEPosz@R+8lBG)k z)3fZN;g=*xA>m=m)4SKX2_*-f_xA!PanJcVUjwT?3{)BHagSy6a+%(ZK>Lq;vPpwmL@ zfAmeTz3P@B)v|b<4RfWAt5_BC9XYE0M(?)t{S_#AkrLq6T~o|(Faq5gtS8d(;gi?M6FQ;Ehpt3W`yB&?v*{1 z_U~yz!VyK;_AdkrUai;!2)R{zia{dMkDA@Pq)_t}kVzn|HQ=O_Of(R1^Z**09`Uxk zT)4k8EMqJ36zklEh3L$fMrDaa&#L1~(}B@dsC{YC`;1xv-UVq&s$goSePfJgAaQ;s zalb-7(F%+;R8)!(?bVg_Gj%j=iq9CL$J&4 z&TH78t@vaDB6e4zHXrGdjQ}xY=JFSc-#`noeQ{IbUR%W0&boARVGyl_zlwVK1M{qI z<)<`e?|Z$BGi8W5@qWLow06$E+1@BbGy1PzOrPofb)qA5Cs=!tRaGCn6T zo0tb%qjYBOPFkYG3#<#_P|Hlm;m09km;>M^{Q=sSwPu3tl@w1cEyHetSHNt3m|9gL^*T$Y=3J%KDoI3r zUnClSU#FX6aN!5ZGB{U5842-G#ZTF%*h2zbX23zEr%`HdCuWw_J@}5wFuNY?!mR|w za7P%`7tb>g!u+j{sAFpV!|nY&R;=j(+DYr8J^4A!&0K+P@WZxAjcmcrbNf#U= zT8c}x4Z?+WBl^P!|5a-NdpE|LHe?{CPMquHZ8Z>-ka^KlwA;)=yB%m6U@!LG?Z<+G zP+X2A|84{SPAy>!3YWAW(B4G8W#Vr`O}PhKa4JIdAfnIlOgzG!RzO!PBLTnRgJ677 z@P3OZRf<&E&>hQ<=qziT5Jll+b>AHG^l1irK01$eDF0w$u*fkA6hT9$J}v zr`)Yv0*Bg>RfUtdquTgW6)tD+%--r!)JA)Dg#3lfHdt+q42NMcE)v(mP#Z@erTL`D^rz&g<=XJTMfF;vRNKhhFy&Ko>#>tYMT~uCzpTLTzJV#7%NI8(?<_1 zhF)=!hpP*}+Asw&fiHeqbOfOD`!qN*b13O$ZmVReLIXU(rofM3j~xnv=!CZdjrh%- zLb~nu3b;T|CiWJIutFOFN7u00A#Dn;|8x*{+qal-hrE)jZr{hfSX_jc-L*NXl#q3i z-lhxJMm0$L2)Xe!go_q`O}l_CBdh6STqxkrO3b`<7IyvWkO?@ z@MEa_dXhTXCb+CNE%)vCvFUi_#=j$8X?Z%!N6w0bWEVCnmD^e}HgG_PmCrkMbq^ZbNnRyTi{>y9n36wwW_pD6E!4j1+)#RWJGtI`Lja?{h#K^~= zlrq9dhKL#{p{G}W57v?Kl_+BR1QD`|-NRW0#z(CsCmCy=7-TsUkWJl3HIvaZS;PTx z&!?5!D|uBwp9^pQ{CK*fO7Bs4xyXbOZ+#}>^Z*{X6j9W z@LOr_SaF!Qz$kTqNE4*^!25wipa=tzDWT@^D1#)sz%-jA(aX7LXmGA7w<9ap-77goqBm3!?VGH<{<*bONGYjD9+7^b-*i%)7K2#BiK- zJ0C0d=)eK^oIy^bJ%&rcD*<(K=&ArU18x=ytk1)0oJ5w;<$F?5l#VGO}LFlxfos;N8?U%k7eAFv21!@`67FV6ynOD-z(mN?%ibNR^ z6z4521u;t8&>lwQ1$I^>x?n^57ZJM`bx0xP(=~`@<%;cGfv|#W8_w?1Nlv>QdHntS zw%Ra3EHi!Ql$e`1v*XX`4+013tB;LH!m$yUgcq7m=Nzjloc(v*Au8*b zeE?V6Z;j`aaKwW=W)n)$zdTOt|M$5Zbggwd68Th%JUz zb36o@DJcd2ax(w#FPQ=BksQCPM2wO-hg-4drlXZ=7- z9*I&+P z`!+6QBOQDr22qt?{oMHc+G&V0B2}67t~%Lg?^PwpHi8o7s0r zki2QAGCw}iOVNa$*n&_&4acvb%NXt2A|XR1>oIqCGmbZl7AEBlXs_)-NIh;k;|-co zNGL+y;%TXeeW?%3yBTt7+xLHUs*lm%h+tgp)1Raq*?}rTtqH$p4Hkw~94~GoSIeAh zZCktIAAb2Zu7U_jg%?E>4m5lg{Wsqaq$#UriBtVZa&`(1l3-+ZETtQtUdFgFOt9OD zJT)``XDsj&nT=O(-;yiW#{Opm+cW2}iXlbO*8B_|}1UPXzeXRY|AiuT+_OgW8?xKDqu(!cdB1X1M5Cj_cMMNF6!nMq8ccTj*F!&t=rCQR5`PF6#D-N}In@c%Wh~?CS zoRUqKXcP&Y4kg>R`-07i%uGZn{Qu)a0;HSU^kK5Lu;<2KQW(AmQE%(U?^I^N+!66rikY) zfaMK=J^huoFqHiVIxKTJH& zbKDg{*y%Td_n+D*%zuImJcBe@M~Rti`~vaDsBf)ZF)!}YC(uYt?S1VZhh7jxqmg+H zx2Hx>+VECYy=k4VUY8)QrOeQ8Yo$)&QEl5|d3h6-WONEdzdT`qUX1aN@Ia zA?|un3X@|{y2GmNAl42kxE#pYyu0XkH6S5>Y9O{|?<8h^V9erTW6=)WqE-9;6?B+CZ-qDdHiVupt%1 zs`<|Ojzla}{!q-{Ft+`3-wh!JJ;S0LRbJ$H&;Gkm8>eXvzH5yo|LUOQ zZYPB3qOD2S5B#TYC^_`SkB-XD54^B!UAxrTzN&a)?fe~uq+Z5J{F@tWACH5tq>QuH z@{=v`B^ABZ2fv1-3a;}uR1+o%EU8kmbhfN{v!?WE1Q~M-qVE|I?{yGUEO2EMw|%5I z1y=q`;J*2M|0Nb7|H2LbGsZ!e-ySBIz?uQ>&WXtFZZkgvdVeKm=A^1JYXqqSb!iYEFgJW+Sxn zFnHsojT3ky46$qZj@p@ol}a<3WMcoD)eT<&daIu1(Uxk8W63ofbHRB--vGR%N^~qT zg^-@y|3h`pMO&VN30oXvd^I-$6eTM)&fuyQFll_m9{}W2;#Rm~omHh-gQMos9nHHY zmAWsKFU}5mE9oX}D9irXgR=R^#E%l3z{b+*_fXp+MQ?w9HKuhevwmq? zeQTY+(c6fl!K6rTzk1~DStkat%>@}#MjjApN`^EtB#ppN2*5NMK-+|;bm?PBgG*8# zIXJ*5e-mXh8z#D3g&~IT3=0~eAsjX=r)vER($%F`Ak<4x3_c;GnL(F)0ef3ZHxvTB zarg4x7S*4&<0%N@`gq|4h@ci?gIL%FxC+md#~E)^oaq*JcV6;AVp;#0M>2+a0S$KF zK;lmCjVho3R_hK#o0L?^z63}CY9rlH|A#(wb8Lo8=SMwZ;5(`IUDbI1n_O^yV0r8N znqca=`j=he>;s=vSL6yBi;Jc3eCil?4%4NwGRQBU5FbB(t)om=a8m3DKA9l<9gr%( zWCt8#V|it_-yfn*g-KUbNvmDsOD=_!x7Qe*J$i<$#+l@!9oLLhl^Cpi!}LEj4D&?4Sgz);KD<$6)d}vM zpHKvrS^Lw0K&Wqp1?FM#XiJzAfbS%8pc`B+34?FJQ8L(!vO9KiY z0?5%rN}BP}e(BybNXt#6Y&J;d1A9#hoJy`)GQltvpMa0;9oV}2XPT3MhzU2KNajsc zcMtALug8uv<5Eig4|!4Wf5(o?;V2CGWvCSczSaPPWt8Io@)S!Q0R9^JFUhc?@7<3P z_)nX5a{}HZ)J){(y`mM|Ih_-MJu-4wi=UP!|5tWq6FuR(jG<}jN->Eq@>o#(O3PDh zm)UTkQ@aVdc!dX%lY?MXo7Fh2aO9ScgdW~TDEJahgi8Ane7gAw;li|DK*!|T4hVH< zq)5s}{k#AfQugB+6Ot+OohhSiO3-$t$wClwEG!O|ibimW2|+F&>Oz}+>E=+xzomDf15N{*q02O67zUq~ntOG6-=&m70{ikZA%*J=_dW^1ctwaP_pHYqRuo@_IW; zvi!u4EvCbE*Th=Lfxz2wx!FKx9b(kYAIQS7N+b9%jrNzRL>^&T);3kMy5VA({{D8U zweL^Hk`2pb7nnj*N1}Afg@j{e1NWji?`3Id&Hz+kk|GJ1F>aBGsNNC8!2HeDnyjnW zr2cM$Emu&pcfLK~A0Fe%nP*1NLbus+2r2Kw0~1jFyVaubi%Yv|5*m)>6*Ek*)fXV$ zRbOv&`vjseP7{Qvt0{~M@DJ^G)M4)`*sD{H>oGG0HBhkQ?gLYnG?EFL$ANmbh#}jc0iC-)MNZ5A2vy2xb~rX?@2!W^Uh^g?zo<@~GQYH4We(z2Sf{ zg{Y2w*vMWs$bGC;8()paqN$`v-fi1bOO%``g&$mQ5<>ocU@((HP$IxS(f9%^FxaFboI{kj~ zGAIS2w$z0%Cljqy%kd1m2E6cTgI0~!+jnB2yO(anL7jnUb1|8yfV>@6*cw4&FVk?I zH!)}Gg$OM=nPdlNTNQEA@b?YF!PQL0S5AYOuXQ2s`0ni*RTb;2cVO8oY+CgpTga@6 zhcWj*b(v|+lPcYC%Jj$NUil@pVD+w1oHHDuk=M>3r3o*?En{1-6Q>X>2`3Rm-``#U ziuf;e-(eTE_qDI)yAOb<{bi?<&qP)Og1L{j3foa6?<-l)Ei_9LTJx7uWJSxJ=_j?EC$`Agr{>9=@(qiL)PCo74l@0doCG6C| zQ-i@ri81po07kO>&1lwndd{mF_7pfsCCPYIDu#04mdMc0RW~@_S3To(;w;jl>avw3 zUoK*PIJIle%q%YhKmQ{NSUJ4nkaX?k^H;417Z4F~$~L85Z7aS!`Hy?$zF7{saN(ox zfug0XR{MGsIpMfI^A-LD=?M*2henEInuBJ}iKz=P;bG z#dAQgl%fn>&YM?{lQP{KMeGnS>sMv0F&k`hiIZF_>EoH+k-t3%z0mmo+!I!UEj-B0 z%$mSM3yvLj{9)=MU$i|=a3%s@adYX@{jC|-SH6fwcR2WcH;UF1Yi*K?1W^NoV?unC zAEALFW?0$?ii_~=U2mk~gfNjO8q&uwQ3nz<7zQ8P%rxVIq)~n~2^?1p4nLFz5F%6+ zqrBP7RD4l<$I8Gi@O?1(%9|o>Cna@sBKNWG)VPL0myDpb6=t#U}IcRPLh?t7A;;;zSZSj_2 z!xUVY60t69OJ`?EHT~{i?h%3y`Uq?c;D>li(JUrE>_ns_ZZf^LLTIXyb&RaVBw`-^ z_$3}vLiq8}WPYoCBO_*!hmL0{a3S8+TphBLSAE#jD5Y{g3KD+p=Wpe2z6iD@a1%Xl zr5koy#A?+q(sfN3eLk}bqC|v_D`=5|vMYTG{t5g{a42y*T|4LLGR^qo;&gMds zsA?1X(_!mm?#%%44BExFeKxnrvIJJ&8%A;zADVc)?2ZPjb4NqH0-k~gy* z1W)u{J^|AnuuhvMqc96t0p-7%f{x@c)+N%3%zYB0oQq1Wl)F@?RB8%^S`5dUzs+BA z8j?uCw}R%gt+&e|-`?JVuSw8~S##6kz=lT0dum)ZQ*LEIU?xSU{vso)%cGCrGYeOk zdM1qvqcE-Zqm<0dqOCb1b1iMOyK92$nWitDAo;^(aF@#mnKZ3(6bD>8` zq6W$uxaK*aN_aZ`Y|L-POt3fU%r=H~c2KFbQ(oq@`)M{&q)08-M;%XlU6ksZ0NSm7 z|3*jL0Ee$onY`%umXB5P(@S=ZRIC6O=Q(}#6K*WSNASBZE%P#2?8cUxr1bB(tO#DS zC*6brz39s|(Ofp^sd!OuyhYwK-;+<2up2bH8@b#v6cobX>KR326bQje>HhSFsgRBy z?9YK(a+)`(ujTha9q|1mNF@Fb>dBy{HZA4E+YP{zV-I&;$0u(gk@#b_Ag*GQQ)-~> z1s{>-HWQuu8&1^ltG-9onDD$x<@`v8{ZFtaoZ z^-qp18xUm>;&;~D!MR~02bP#oJ$!>ggGXY$NR(WQ9ETplbze`4_Z_s${m{M1jg4K! zg_^rK$ikxQKis?~O(&7zv8#Kxb1d1IpS7q=+K5(1fE^E&zr;x7|Cf?yV~GBjiYxww zHev()Z=#-$1~`-d7qD3F$BfLF`7i&l^!;gvuehSrXEnM8h!b<*gPe#AolBXU}gQy=t!)US^-z zQu_6`J0H?T^{CpAY9L%RJ4Z*iBZElGB?M;`(drqlM;q1GVtFa z+39a=ddYb+%|NKim%(!4w!UK=d+X|^3pG;XW{d0+nxYONw@sL7n;jioXmvoiIkXq* z$$_&rneSVm-(!0F%{Z391?*HDjbp~)5-C&!;NhvR7R$yefPXbcp?focen`aixDzot z@9w;dn*4XQoDbqE_}u})2-ltg_~cmO++}vrsX%hM54pr=QV&+E2mNab*yBXJoOyhI zfMnn>0=ia~-VD2@w;Jf1(eq(0+mOvwRwSa}u@EP^rf7f7(J*9Y9v(NvT$=mrGnEeP zdG)k&<<2TZT6+0LV)X*3i86RumqgvR>lyV3A;(>Tnmg@twpZO|Y${LL6>s(|uwuEt zac3^P2hD|Ti~{Ql10!bjIL@3o$}|KW`B70&ic%_}<4BGJm#ONJC$>giA7S_JMQsgF zRXv7^R|8zdR#d*8`qe7*H^4vu7Mt@gjIs2;;<6Twa)hnnGL-IckM%*C&zuZN;sDpT zF|^M|lW2+6;1bUQQ>Sq|*Ee&r(`l~1^MYu))IS~C@4cz(M|z_qq;&hV zuY8PWl9GPXrC&ETiR9#ZOd)%j;W~k)1|GR42WuZZb zCk2=P{sl8!oY{?%Mg8ImhFi!lKHMW&&_(34XNowd^ z+|AseXH3n$5-urPYr0hzUj~CyuF@EDs%&PlLa})P+I!fg>K?F-`!-J+F%VPnNh15E z_umcCu^^p8q$ollZhh$HQ;ZA_6ZW)EdY8IKzqQO1T62Bz(bLVhS;e*EP^R3;Q3}LL zEKx%xE-_&DJtl&nqx9gUqNOtcAdzO3lsu{M|0 zdr*b%ILq{}wnW3Ftu|=gDgEXZZWK1tUDCGIY{t37Ql*>7oo>KGx(gq9pl@lWA<<)Eo7DhqEWT%lU%+lfCMTasaNA z0e4z~_A5?btg}BePit8wJPAyn594`14>%{xaa*QuL^-c3{LP1iu`Q29V~|{d_DwcW?US~$YuPCD zjNkarM+BD5%zoV$Q=Y=)5PEA!GyvaWK5>!Ch`!U$FzaDx|BI@c)OaNfUj0CgPWw$fDG@`ty@8a zd>qf*X@c?P*;z#htEumzS{!i!rv3P3x%p_r`y_o&!MjvXaNiKGX{WuR(DuiwU<4-3 zkzh?pecZkt?%OL{sv6JFAK$AsD>q)mGVTnK>p|v7knJ|) z8)R&YchT&kQ;_T-=T~HrTKN&=$gBHAlWDES^O3qPa`3<1v_egdjY;26lwP#k31Ola zEfR2ETx6A``IPixB!S*QG{U{z^|*2U>|f9HFV2is*n39kW%__1f&0zd%C*eIKW)0l zch_)raxtyY8{PW?JUA)lUX)}01+cM_fANRKfQo*2n5HgOQ2cQ`EG}rUIoj8hrr`i* z96?AxkqZznid4SR zDER(VM_Y)b)8qkhZiGzdYBIS9^9b8AI8`aEwgHcNJIN^-E}UA%jW2Dulnu9qmt2lh z((R^|f|mC|-BgcTDnz;O5NLtO!7s^|l)iz_m`YMb1E1b_ahA4m((dIcJzR`$Uz^-HD%L1)_K&>vjY09ncKzTi?O>eXUjdH+t$v1S{1_sfi|)P6uw^$mIUYCT zY?xK;vMwtS9vL$x0*+XEL*g}ZN1v?Zmnbm1Ect&-nRfb@P>~wkEux@a7pJD^Ptb2C zw!&~8I(4fnbSMIl?$90fk*gnwxM;|Yn;i%%S|(3!&ic7QC@SQKh7JmgziYfief4i_ z2KMIFsGoNUlp0YB&Od`dinsLy3fS#x0g5gERqo@@!Rz?{pfqEki3y_0jYgPr9j_vp zM|*u}K?>zc$iQY-%i**jz~^fLYF4yDr1oE!@MGp-lfe-nkGOX~3+0cyLc&qXJoDl8 z>F@cwM732>PvexiNQwBE_^T@5D>{)dxZfe-6H^?le$jajxD^SmoefF26svs0CiNJh z{Wd5m{IY&or3OCZ#<&+8IJiWr7gtwUGE{#LL0CP$zRZc~8tH4HO?$pSO5e! zYiErERPsg(s)Vf!xxbjXn*)1Yi8vt>QG6PM4LYk|C2DyP_#j&twG5i&eY|Om9S$(| zlXBT#+3>ReY|IGY9EaqskP^G=p}=AGMg6%D!#uPaD943Jm*v?Xi27j5oqzYA%Vy*n zN?Qrv5l0VzZS8D+6{lJmr1WnhS<5;ZGN)g&t5U?2@CK65xs$A4l9RduD8Bt{|3=GX zpvOfIPD*p*1Zhx-V{%oRji@l5tjOt<9L6Fki_X%bGbg?i6fq-8l0M3qY0lM)nN zr|I*yHUd$tzjD0h=a+ECj>u28a9!p}%G5zzWWph3Ns`vDv%oPyMig)t1nJ!WDZ|6! zJz~`R>4q@CjOap^t@4j#rH^8T>eI(xoF2f|Kstk*X3j|xI!-gQ3M-)V23=;s1%n_k*!aB|ecXsSOl7<8nj?P&umSau@wq2=Q&)wRI!)K(OD^x9l` z_g_RGbGxC<_@v0nOvtmCIr~fJR31NWFgaLgff2Z~NCYLym@5W#2!=5V{Dt|8p619> z(veI0U!9wYKsrhyW=ZT3L~x7x5$zswr>45)M+v^tie;mZ&=wo;%)AFUk0mo7*pZfW zM_SV7a4tXX$c^FPUK+JN2-tXzxYz2O<8vK)tWV|f7I5l!zKD5WNVRQ#P9#MiWyt3K z&2~3ne#8BM!zqRfxnUlJcc=dHgOF`L}jfTqPvlrcfN2%-Qp;Qmzc+r+%T}6@U zEAA`*e2Ifer*mA%l6(RwwIT>=MVbD;)ME0$^hFa|+B8wS;Q_Jip+ zj30KM8j`wZCH*u)_+vI(a@>{F)@tCKl!Y3}8J@CGFxj-+8B6|{W08L*#PQasvsC`x z75Hmn-l0?0hr(bw-%`sDzK)_+I6hk^#Uf-a1j+unlnv23V&_H(Ld#xmjKQtq4?w6L zDZDDT&pWfrZW_Vwmz*6gFPCo5Vh3Xr7laWK-1t5Xs(9Rz>3B*YXj0Yz>H{PHOrAhJ znNgkVtcdP4P(*o1z!9oHM&CO`8T{hJ@+iK<{xQ?R5A`=4tX2vbZwx6BsDL;aexq zw*?=@cH4d*K|K>Fau~<{g=etDOC}plOW^D?k4Qm3YSM$d7v+F(N~Gq8POF*To)$ou z*ZLPpm;*4!#(zPADS%X04Bt%wGUXw1;AVQYP40)(JLV0N+$#ZXs_`=WWLfFVy&SzB zqpM$iVZCm7kssV4+-%#XrA98KC!GB>hpNl?QerB0J1j2?f@@`NwrV?slrnKO+y(xZ z@VM*s`n1&VL7yn$GjJ=mT5=20Fs;5#9-)Qgj}n$UW_1dhTlcSDajrST6G08 zjoO@xX)6BAqSY!7B4u>ZX^>mv2Epi>A-3@=$`?FfP8js;@v6dNF}kLP_Q;FAomoFd zuoHBUfzX0Ps0H6qAFjM9X*T-_q~4PFL5K~O-v6+JR{VzD$GsX6I-?7O3$J}dM9$)Y8w zdwf;T=beTuTalw~&2b*A#som3=X}%;lgYSlPox4x7{B^-_-w|o3)FK39yg^*E?v|6 zX9(<=Bv;^V|I6Re=g7ZF|C52 z+ht!hHj(Vth#0>#(UX}JMp=eKj%CKT? z?X)72ov;+;uUZ%xLLC@3$|RwJG$bYXKt1Gbskxd=eP81(JBc97gOSnAoxC{i1(;mR zzfi%HceG!;VoS`#DqgujSCWV7k=Rn#!~++#ylSkfG(A;6({PM;fg1HCLLFCDU&OZM zg#Yxsim6iU?C;v_9r}X38PHCyx%VQP4-}Ia)6iv5$>sK(A_6og6?A4&iaPsJ&;g#} zE0{u=(t@Wxd~yhz0{L5kVS3qNFZf;R%2<(SSDtD(nC3J#%sru3-iE{O0h`mLy*eAWd1vbj)eJ$ zEsu0<{=Vd_NToXRX`>@L{`3Ln3i3!O=(vRWONn)PW}mJlY6A(nCYA$_*Br-UY*c zIBJHkU6)jD0g$&Sxf?aIO~ote9t!c??s2%0Fcn!);&p!`zE$*-c9%bj2j=eZVI&Ld>-{ zWb)P-w9hsJ0+#yVZj?tbeB-74z7tS)D;Rol!tP;K%aPvUI^s~ZpIBN7hmt}A=J#A{ zgq1zuDKID2oj@2-zrRh-rN3&lAj^2_pQdZXQ1>3svE^%zcp)1)Jb|61ho&^us=^fx zu*wU1a{H=Wb04UeyYkuAu5;)w!1kDg+t5A3@U}&yOU+Y;Kj~Kz$koo|9XObgHG;nG zxC3N)#;KkAzEm<@NzOkOG0M|i_rwx@3TUYW&cD$J28EFD5}pMt3Q)u+F>A~}rRXOJNJWmHY(}Ldid};h0OlwgwzD(0^tyoSbE%#8J*JPFAMMg z`mtH-J(_}mmxRGzMBV=#m;DBu>HW)$s}uw{e8<07xRiG=YEeL0#s&!l@{(O-Epl@` zf?jp;6y>Qs&Tww)&HAlQYBvP?^6nL08^s&wQRFjZV-7aEyBWnR$9aGbdC;vl-=Lm6 zQYZQqbdJK@{NlT6M4m56mDvL{Rc~XFpTkW@{Q&w3!y~kMbMj$lt@A# zY024}*YcU~ydg4;ESRrRiMBL@MXXD(J}VPbCU{Ke5Y*!q62_&n!(kDNtUhYEHL2Ls2z)+xy#jr!PD4zee>OR+B2baeI1LLD7kIpn!{0<`uAY!|Hf5bea zljdM$Y7te@vD~j1e_u4gxCX+p=~`js>pjEqTJ<3cXsm%2e!(wsq-m^8zMlBN;a^SB zLTA62@B~|{52>m!3BCFmI-5xW3HjZ(#&%Ayu(MaT*5b3K zia$A4kbe7Mz;Emo0!_ZD;CIfP07AS%jE@1#8oZ|1CH!|E>vm>GO**t})`xP5q&c-P zTqds$x9n`J(&(C4u~ZcL{9JrAn?b)#ib-JAzDFrULXr^4L49-+r!ElZa>2biw7oRv zgZ`uvm&=y;q;5_@4c+%DPf!yRSql!+er2zSqJHVD4!wo7OWb= zGQk{?Hz|9@AH=BM8y^?F@l@d-zdLP)FvU1LaTxh{UKa}&B_wY(peI{DX|RfRvh0Zw zHmf?GA`vPRJ-oTO7c%&c6eoaLp;dkSBbF{?Fmz%uKHrp4%}b{~uLzQ0=a0{ignbtm zpR{`QVqyU^bUJG{vxoMSJ@E1Y>J~WO*qM#D@$2c0KalKoF@RCtTBQ}}9O8o0moD!g zd4SKZ^A~ZL%oUIWGj73-}G&l{8G=ogVP_GJeFSO8LS;06Idws*O z&x|Sf=0kNY^ra3T;23Z;lc*7fshy_9mWKP3e`>DNt_Qq1f>i7scuraTE^-8$f}Vgz z2CiLtj+Cr_KraHUv>+%m8A>f&zjJN;!$PM96X;&9`l0gL8EoeRMRAI)=msv|t@Yl@ zJl1yw@;hA)F}*!Si@MNn$}(2b{H%banX@AywfL;K8=YKp4(w1g}>TI?IV?PTI;nm^}8keghz6Fp# z?!2<7?Vo<3<57DSj(R=@W{>o!zwdIPPu$_=3WX?#trGtZ{GQ4zSJk7g$<@5ggBybO z9fIET2I7}$g>vk<_O;G!NK|=@b*?+MUP;Q9;dU?0a9GmQ$hyI6oZMqeyz$O-*$P*# ze#7VyBGTad?9@e?{EXr3y=K0)yw10Vu&SFf^OGL1@2>Vd2#M2k)4U^afmypiQqf#N zp|bOYAm;k-!2Eb{?pls(0T5M)*?1%mb93`PdAj|Nv(pS^6V9$^tfNapkt^7I|9nm#KU=eQZc z9=7j?p256HtW-*z;T)N*{V&R2{v2XZQ}K7GS>tx}kNPwq7C7DJE_36^>-H8}8$*zy^l<)Eo|Cj- zr`bMZwpoGOBRpT``I@1LLdU`_L|d-|Z%zKTitv~o71YUh1>SZiyP3`x?Dk^kcu}^Z za#q8EK~X6q_M86vN;;r$fG|c&D>;<>$b%O`$E=}2{ba|U!h7bHUE=vNJe^vuSq1k< zve?y7Y8-mC(BA2bpJd){lzf-qn=l6D!3+wH*k#QLJGi{~my*$R4D}@TX2RKgknMd>EZpSbRnTj zr7N1sdT5YbCpV_zH;-lt+iu3!lX4q_eq77!_ zo;(xp4(NOH5VZLmpxqmP>YMa4+slPR+TYloqpm?y-KWjk%+a{i3n4)bkIh4ee3k@+>m~9B z=gXOFd_w>eP0{PE)3gjf%@aKL;?=6tf|qzh-v}l23nZhtlsBvO288i@lAl=JJ~eRc zD=46OGX@9>R(K@QKD{ExJ&P<%rW0Q^dr8;F#x5hF%O_0-rGEMzo$@zm53@K5K#Zg- zQ7eT=Lf!(a>XqRi;v8TnAuU*c>f){$#dZbdKCipJ&~TB#HS9q#7UmE0Vp$Z3E_BDB zlY(1NDBvO2z+S@9K|3AZ@PW-Vv!YFfKPYF*oj4w4RtKofz$uq<9W;ZEQkBTjU! zZ`T}Kfs{_g-pr26ezEgSOaNX4_W5S!YP4x+F@{y*b)!Nck4@ulS8|hI;t%;Iqwlsy zDpYKMSB2gexL2DHr;!wyEPTaYSL)Lx-aX9#PARc_Py`_)3}w(52$|KoLp*%V8}k7B z8`kr1jF1NY5O_~*fnp$ao|xg9*&-fTWhO2rMkxIqZK*_A?&v;pTH7-l%Ff+$v!yp({`numFGrkW4EBH)UkGsmVk4sa>sgha&UdEAi|1DVbI#Dd&C^1OU;%m- z%cMuF=C%Iupuq7GI|H+9C$(FUJ^w{|V4g$^%4D1$%qg~hF&?CBY4!3P8{Dp)mvWHt)qb zr^pOmnaIvtC8((Q(wKlMiVlAA3W7B_1wRLjvY)`AOf{nc$2mb1B>{orKVA)(Nu_x+>T$+Vs=R3tC9X2hv z8zX{P(&*%(6nJon37B^f2}(@FhrZsai!{@)}-)gz?J#FFxFnWaqJY=7Iw!GCG5} zwr$&*WMbPBPi))Hm*;u+{;KvL z=&G)|*1EgbeXjFBK>xL2LRe{O4$K@4btKYZS|~Zmh0e5y&4H5RVuF@aFD)gUyTrxB z%GEo`Y`($1zs?F(820DT{QP3>`~Jxw`+kv~n;Bt;A`e_JXdpLr7~uf-+>3Jtx`1v$ z_A~!G8n%=GXxS78|947u<@;N_RFrH&;1F_GRX!8UvZhO<%gXKH2n?(0-M#_SDzU_9uTkhZDsztD_GvD+1F|QC5bNN) zr->#NwA{P)33GMfsL+eor(|`%E5PD15~lVvCJTo&f@lWEmd0xxN;P7j#Bh83%He^k zeL&N(?Q8RJab%#G#vOhkx-umN+7J*>S`F%*iUgc~`19A6M@=4YA;u#eZoQ! zc^~5b3ErFwVRJ5Y-kRV$8o0vJ_Fk>eJ0U<6U2X}BGjzIv0w=OR6m}?@NX$WNHW%=e za6&%51Asst@loiN#{J&$jv@A5H<-ufASq(+5&Y%}g~@u!nj`5*i(T#k0AdPB7%HeA zv({_hXXlpx>z|c==8UX4?VvTT#=E3iLpZPpT>mZE;oKLxq zbPBCl;Q>K%w)<1pfJ9g7!Jr7a!4va()8vaW}!{N)3apsjJJ;srYQ*N|qO zp?^;=UJ?ID6p2*gN;w?R-~Q<}YKUnyY571{1eFZpTOa)&|q(L~pk7TL1|>3fc~Ntkax_>-!J6inbY0WbPGT z24$!LDSF|ht)6V@W{rb+)}v@z0mB?@oLMc>&?Ba@%P?&{6Rse)bd4NIDy4Q=`{y6C z;KlV`0lL~{tt0Q}r;S?Fwd{$Pdb-vz9bn6E(ARvo;AV(lY5>mwdo7$I4(n&Yz_T8< zew`~#_H$;|dzIa33l;y-2L<@86Uw@T#E{4XF+g?Y{EPlpF|DV;Htbj{Q>Z%=s5$f$ ziDztmtq%enxpU?O+}svK=r0q04ubFD=tbAl+33IP6gGb-f3H|PPC zoyfZD95R<}{6?*={Fn?Ii$byuB~VN%P@r!4Ha$W|V5L z^G5$BE1x^6ZC8rO57@14^sJl?)L8qY`N$vfkDUn9tS1GgUmyUkBntFP!rv4Qw_wvF zte)J&`xU$Qrz1_8(*e`@w*%=m@8>N6B%}kZRU9#n&grRSY}9}_2vKS_{#G)*)XSQF zuh7(5@~3=l&P3kD==>Q+ptuAJA+!hm*9mDnQEXWeqE7e(L7iO;AHt_9rm7unMYDhk zdU5MQwKPbC_8=98f61{kOsLW!Gy{EkH-9&W)cII@os@ptUK)pc4la32T~LBKcWRw9 z(u)BxZ)Jy^FrN0f6u2w?2Q?xIqD5rlmVd9+x74ho2?n4ItslErn3!1+8t_R1X zhGm*@rtP%&CJm;k{jj6Q#gCi1bJ$;2nZUbd1flpS5YZcArrxr z|0jJL&zwG3^=+ASleAZj&<(cFBlC4z-8q9?H(7ZyUKrKGojp9$&&#KLsqQV68-eGt zI4F8Bq~9O2YJ)Rf_HL}N)dany_wo`ds!jKj_3*K}>llaQc%xy}Pzyk%6()0#)uXrZ zlcLLeeXX`|Rl51Qa=X#}R-mp2x~HwRAASm{tv?i%4>GcqI3}y1aQXI@pdESTpmyR} zUy`TMzLxc}m#t1JLk~amwe(#$xyq@3_lti_n@?C0k_pLEgjMtgXKS_7q_tZL4kX9N zFVQhn1?BvnQpdq_!ICx1E}c1^uZXF2@yNL#OEZd;9y;v>$B!q~*5tYYYpx0ZD+=w@OC`U=+Wm-g365C={D>lvRg zG<;O){z=|x!2u8YNo!BLvw|9(ID)(2>X{O%3g4g(W z`f%%~#XxA*9O)~XABo4X8xnHzIft%DXxoeqlClplGw?d`-b}?$(0w4>t$l4V@>o@d zAn2gAJGzyI97KEEgd{(K150ldyFr_dtcxfI3@iM>StLfB8C2UKrjZATq@7lqFZ!Jh zX&pzOiN2sC53H{ZZLIH&^OzJnfh^s3Xcm6LjIMyrj6SD5o0#sqa?7>C03KCThi!=; z*h@y#2x;r$)>)%(wdj(~xLi?fg4xkrL9`HLexPn1Vnd4jh4T>*Wlpg@oSbXb3vTP@ zDKq~|TKj}#!Y^_^rJyNWB1fChs}< zh?oxN!xMhCA1*+cO#$Ih-}K2V;EkClL_i=&=uQr~Or9lN#9?m|(6DeHi#7e(eZ~!x zHkNbvwaFpYN!ZcJMrnccv$sVpAx zJ8V~a|CUE`3Z#MZj9gU38n~rJnigoo3vEKr2NHH>$YtO13F@iHS+-92nlPCf zv*Lkv`DnhQv6Pyu3=z7f%g5%J`j+oZ?LpP&R#vSyO(QN;fKkYa!6Pi{eaU-5%kMG& z`0+5|0nKx_b7J4OLjTj_V>C!<&EKx08ei(HoP)BxRy*J)r6`7lp|neVtY;2buS6KT zIr!ez`pzYI`^dt89sIO3g{T$?QPB;Y2&$2)Bt|g{al9+?VzKPulOo1@?b04cZ=>)=jR5CT5;8B}3U|!U;95KVgwjZ$SP8!T8 zngi3aOXJH8S{}oOEoXCnA*piJW1^akKlr@IZ{Hp0cQZ*-*#GM@;{6*04AKW|D<#;f zTUxBB!;tYpDrv@<5Ts2f$(>pV8re%+9KJ)BB#Algt4AI=kG0lZ^#X&V0>hG-)>C(C zqHZ%`QrP~(Hs%og{|}=mwRd+ytD61(DYN>&c4OW?Z-)&H4vw+7k+8>>qTq3xfzUvg zI?`(r%tIrH1hJP^hlzMKg*HN834z8ybMfhND-pj00@vLxxSSa4(Wt$9h$0PqZ(xr- z2ad)Afr$Id_GY^z8p#%#{~Z33M_=Ct)pofSYjBF58aL*F%&Y4}VG6 z4is_K1Bs&sG>~FsZs&E#q;Q^YIZfBX3XPI@oW|qVo5$dB*GXLBedl*;CULzM>ZNDx zA9X&!mtFv=!p!aUKIlKel9hL~%}5gmh*q$wZXEpc#5=(%6U+Ujb{?;LH1{*O5?~qf zxVNF!Fys@B#X!rTDqN-WfXu#6WzwhYv6z{&GyU2~qfhTv5{+30& z#-}EU1&oErM0*cY+)F?=i4D8MnAH_t0X4_Td{$)aE zk9^>jrM=H4nf5gWeoPU6K$5PRvA%LCdHlx@c;B-x zwcp4KbgdG8Uh%jLhg*D1eoumH@ZW*S9%&(X&CFMG-Wnw3tx`!k&U63 zmwxKw8$w;eoeOlpV+WyM1&-RfobijYq=Mj6Qs$t7ey@+s|Fsss-@VqCtAgC*7kQC} zj~vk``GIMfMP&BL0(Fx|_%EfWBq~8A#D<3xIXLlX!PWJoai=_`I%e6Chy^CABmcD{ zPTUuwwhYR2yUI}{P0<1AT$UnqOT$ER4weOe&9l$&i-0kVR6Kumk?j5CPO4)^FNzN0 z+}^yIPDmnU%9D9bn~43D*t`e)2Qu|aYEg=>lc^?ms> z{?7zyWa0c4A#2nExp89sBbiMX^ZVPyc(U*SE{Mc|;`g$3L1tAI z4@XJh>Jh7@jngPzOM@tSky|3TH5tg*POoPZ6faa^)1Cv7ddeBaT=UR!l8ZIdAEr5COYHULl7nf0%KJsdi=u<8xl~a5WOsI_ zwol)Kn6^-s5$rgcy6a8VnvjkpZlxZIW0$)UII6E*u?nleo*uB{3 z--ij7Svb>{nU@I_?4ca_W_`OX_V`UF-rs$*^2Q4tv!F6+Y!K6a5P}heds9{e zCJv!{q(_Y|U7oeCEaJBrI3#Mac7G;53P+NE6h&;ne*)k(p;GCcK;V#jAhNfbm*k3yo4i<`IzYS zH+$Z!|4!b$BHaGy{REsibOdzW8hpeaFwsH;T1R2njdf_Dn*4+aw*Zz*w9|)E;GRY> ze5f_?@uJ2C?Cj48o<8sI<^&`b=mcTjnONxO#kYK)DouAm^!^B(+4oI9vBa_Ry*y{( zBHb)92$B@_zvC#P>S zL5F>G*(>N9rMa7N&VhjBL|;H8tyw#3qt@#vAdkQo2Q_^hff(=)q{$$|JM#;wFn(vE zepgmcp+G|Ew%px7b|K8s5~$6KyC>N8fq(lwn<+-swiyUDTci4%`d-bq>e5_Y;#o#A1z zEt%?>2Il$oNjgVumF%jD-O2#Ov~@lT^=;juYRDWaw|2~m!ZDCL$KOSDn#1V2>Ny$H zPLrk@-B-Kox0t+(m7zi~pC2ByUMDY;#A1S1?aumZxyt<=hLQl2P5RVFrrWuH_IXsm zyAxQt6MU=Y=RnjUaN`ww_xoi{I;}5XpJa;3_%S2w=4vejaK(J4 z9&DQd7M??8+`h&**s5GY>qwy|Jx&LKTFM;;-R<;u$JhIISM>emmfZwQ`;xGYc~lvU zsU@m0+Kbc!+V#j+bbBY2%h)4OOWzn&?VNMx-Mf-dCAOBEf>zC3GTHH{WL)-C{;4}KLyN`YqF-NLmck86ZYlkl}KJvE;`vguxgVj8IL4fF87rXmo6KL`NuyT0uxl&|Q4m2_?3Jo3o4PD$jGoT0eS-^SOg8l4 z`qu*07Hsj3&(w+{U^3|gvN^k4*L}KG;J4JkCO=CaUQ7G>D9HJwa7> z`{`MUW0s|-f4G23eNG^{=&0~|{M8FaOHLf7Ln4@BrB&Rp+f*My^n)+Cla$MbO zD`)|=z=hzyzDSEu@#>$mGin^A6>)YNg#4;yn@ z@m3@Z{YLDtmp0c+okz(wDTzP#-YsU~(ev33kV0#19JkOqkfZ@2g4j8N{g|Q z5Fck=)o3`06)vxa*pd(yt2q4r30b#8B&i96Je~CI0l`(nczzhi;<~9JwtEND zKLSX93fmLic?+r(NjHrphzK_1x=HE~3Ayt}>Z0=6{hdwLgDNk*#oNV=mxgP)30+#M zUoz?UjNbxe*|b^htcKstbP7!2`hO;(z(40aFr$2cEop184Cm#HL*8aBmh-_2Vi&9I zAdk?hg@%FmC7gmEl#r#rcIN!L_ZF|*Zl?*8sz2&Rj07$>G?%tG{t72sHNpiudjoDA zV#aJ`9%V)?9ue3jP$ge(wO&Ihr3ktg5x#5Bl5{%+x6AHX{&?BBBzN2tH~$cKmHezw z?okHb@<&SLd!x6A@x9U$l^;AZIYO{U6%V#G8%_XfD!DQYGP^n3K+dIUXbqgBPl17i zo-8m5xA%>+oN*WHn*dI=0wpP^PUAr|;4`D-)(@Au1U=rE%3|ziqXY=6m@+uSxK&;b zQ%OLp{YZZ<;9jGrs@6RxZWBqxpFtvEL4>TtO1~mE<%h znWMn1Z$CX)G?S9jNzU+YA|c{jiMbgYcHIAt!wrSLzux&|%9u`+>EPh&<&SS@A<=HM zB8Mm@RolP!RV0g4HTNqe+E{C-Z;PPT3Op3MW&3S zVWX~^-chSZWMJpGdau|6#r!V`uxg9_m;uoCRQ-NUOTO%pR0Jv7VS&rm{l=(^ttd+1 z=9T=Qybol(y3<-Cj^!j&^g9bmxhF4 znXx$*IM#7Qr~ut`d&X>x1OlswV+I>|9&R3u7;E{fPjGP_Y|9dLx%oSI^$Tj{petpw zavvfZcqC^r!8__|yCHwrV4_wAcM4@VH>dJ|p602xg8&XaqFq6I%PUH|r899uU%PRf zch!i{$RVPV=a&v6Hh{sQSwhbJrXn`u11Z}G_=@VD0&5$CJ*nAa7Sg1$aBPmiOH_QK zd$X*5opr&?GDP?FRnI%r+n`|YOn^)jYpR#wU=3U4pL;w8TKdYw>l20&l|o4t4hgkP zJmyN8?Z5c#t0jh%?n9umq-!#@SgQvH4-k|kBej7@S#QZRn_B)_iRO>EE}cKyuJea4 z{35gmmSWIEU5wxRbznN8nc;2!XPu_92y-YZrJL*wE`hFw(KX@B=A1S~68hvkWCM0l zZ)#T9rIMbN*2U*Fz+Ita+a+41G=x{!P2l{urlqUXH1B)3GmpTC#MNg&My)MS1ePPB zO+GW0*}dBE7$1(by?N4`f;P4>J;|owXZHVUlhJTU+hGF!1E7cq{z3j*pIEAA18#;9 zT3C#-e@z`B+cT67eQz^iK_YybSPG>x>()I?y?X2f%ABAcW{7LklwM^-5j_h664v)W zegM7zI$`Q(rpnGU@D)jXxcwY70}4sf^5H+==Ng6xCRvAf7F1~;S%r>K<2P@z3Fcwx zmZDXACD{d*1pA{@yjnl_->mVOvBaT0$NTuvk$L!^tKr4GB!`$P-){!Q07syB9hup^ zdqq$cV}1%@@%|D8#S*2KNUw=|W=uE{SL6ih1Pw=WNW6NA?remzzaax~ zt>Qoj``{~oVZ+;|6qm^?zCm#;o4tr)?*}2@JH~xCGflEqGHkdV?WKXNA%)-&cd&(Q z*W4+HXu(HWG1}5%9$j7#rn`Xz+aH&@*C7J6UN;XGa^`v!HeMoIYS$V}HD-nP_-%Bz z!77s)`Gf(*#iW5-&`rrFCB&th*q>lc-WqUrj#NiDYOyBiY6Iu4p#2qbvZV&>nj`$Q}$%;nutmc^O~aZLME^l=qWf1Nm$e<5HK12L*fw5XQT zYNNlAAU#+wZOl(hDzW|;Un;5fwZ@xBdP20giOd@b1t%(+^n`9(IruN{*)g8kEeggIX0m~K~ z8*uWLF=7fJO7J@DyjCH`YVW_s6%0e@BF*iKAR6M75#2Jo%$sOQN{1!>lhl<-gNchV zElv~)Y&&#@l6KqqnDhO99BvsH;YG;P^Q(=}h~|Zp%1v`{4!lR19AZz5^WmhV%_1_~ zrjiLe1`4sfG^EKeW36fv^G8NQ72&(KdcRiJm;6*5(n|Im@M|iq?k2x3YFL6LS+a~V zmY@x*?X}d8M?m1D*2O!^m|6#BE~ujq?BXW?8D|kIJgso{P*;N!_+WvS&8b&z#XLjq@m#iqwEvP%-;hPKVj zp|W9SCRZ)SWGoIrcM}Zi3|OvGN3xlN(=ZKmO4FWO*(|l>+G3hoB?KB7G(io~)^L55 z1PFSAd4ozy_UgQkknMcxLTWCwC|*Q22uXpWf4J@%MZ_d|rT?j0J& z>z&tpxwD6P#}(pWM~NG9Z}jUo6A&a47fZYATt<&E#TZ9~YyIE6#!2~1Fp-6cQ$12= zp8VbRXRV2z_iCnF`wCTsiEDqOcev^<&tRHybq7%3**cfVj1 zwoG+P*3?caS{wxaf^#*LJ#+=fb9u4RI+WaMe^S#bFatR*y()@Ibfu^T@gLMVoog<6 zC(T`>xktE@99m8@F1YJA)>PtkbLb2ZyxOcl8@N^s>C9wC%n9z*Ef_kLw3MlpGxEX7 z=$kxy7aE5*?IRa3t-a&h_X(B|`5>JmU@8nLMe18f8emP)n-g;outQI*^zLZNfVE zIyKbCEzK6cN`BJ+p^=;1iO)`l#n@Zbr_>gkFR2#pspx{gMbcs~c`=W*a5wf9jyqg- zwj?Rtta_q7lU{%;8cWTQx0$X3r&fMKglw0Ri6Srxrml%X@B_M>C(SQif-oQ=_a|vr4}j--#PQklLM)5v0+j;e zUm*wlUm-^jXd3`@{f*?TPP+Ucz0A2bTFF|PnZYlP3#Xpn%1`VVCfMc`-|M}&I%06vY;uglBF=I^6?%+H@R$2* z?e>nL3E56z?ROJiF*CGlBRJ7y?PdO?oD{;rn@f;bXzn`nh>Aje{e7p;$Y)T~T9^4l zram4aMC5^Dg}TRgBvRkw=tXUsAxks1{N2J{MMGxKf#8o=!%T|1gO&qaQlq6R$s+G9 zC8A8u;X&YQL(*%=MRm2B-sX!@DN*ygi$s@T3CMA(3n~R~Ira^{L2_VGW4}`jHWQkM zHSpUi#IPT;C5gHMdCL`m>T;U+f*d#Nh&pr~YAoHfm9>)lbk6p}NfHH7{ zO0pYRnH&_%MuQT^8AqD6jfc?;P;Z}Jb6*>Y6ko%xQ$G$2**U(LLP%z(kA4pq>ZvoJ728 zAQH0Ex5FwmkEtHbsuFdH_5 zO+ay1y1DN6NBv*!TkV;SPK7369VGTK@WgQA4e{xNUsA1}p=Ki^&!8QiEN&F`)328$ zENK^xEVo7tl{YlWL}#F?bMyLBy6!}sc5q{w0$o2qYLj5nr8vhH%XNr$Z~p2lYe>Bm zgW{kgg~r$q!mWT0wD7vtTT>9UR=u_Yg3Qp6NK9X}k7P|o;z=<2|A>EN!7{|i4gHHuVAZ8NO0$(}|6c>jCCMAaZy4YGgqzZrw_M zLz!Kl=7sdrSMP!hZPH)6;X6o2*@k%1JW^jh`XS%vsHQ59T-2dta%@3x&?=^i>{?dM z5Ju3P9QE5{WJS1~Xp3QH3Q3<}%KnbUBs`&(SU(sj-XhmDVL3XAnbngVUKn9T(xWGt z^*Lbi%ktPMcoS-`!7S$dvsJ;*4Z3Z^w~uSV**+H~ALq-d(9>Wvh$XtFD^%ZM&D(l! z<;Rt`S1+0vrHm}=t`dG~|8b?4CT|CYtPu6b)&YHwiH^?>K|vq6V0CTQ0p9W>l~eMU z#9%OU!=Pv+uZ&K2e{90kN&*p?IprELFM}N~nx?iq#aG5zi%%g|6ON zNh?)zle)Mz800jGS09-<7w4B!(}B0vXK1v*Bt&A`v9U7lWLJ!6NqUSgZCNc|?hWli53ueNs#|t5SPkXFeI& zLX3deG31q0Wix2GP=4%i8!%@-NL~B0l{ni~V$}6*3HhqG#Pr&RPM&bO$JC|D;BHZW ze9n;WyTK2G>3H+mkBa8>Ps%({kZl({U^^xX8tC)5V6a0w)KQ|}78IU;Ea)J7C}9h2 z^f=H4CPjVb%kVTp63$ACrA99>q}YBO$Lzpt!%OH7#!&#CuQ*NteS@uBRh!2x3|U`% zY0DsHJl*)em8G=|TGymU2y=g~9+)iCe3;mxx-Y-hO*m_gR=T*11t0;<}$H7jdA@}UG zuHMOiq=JXxxGTn0PZC8X5>Hqs8wJFUMl<;DpY@+YWk!I7a>d+3YJ$IbYd=tuyRskf zjz+KE=MLgqwE1VFKlxLjVvqJJj?U}!ny0b88=B;9{9+>gnfm1N*M z@5fHRwPEQ0K)SqsLnTT0q!6XQCsW^GrwX+^$TN|hP6Vx;mxXdMpWy}iF+f@M;K7uI z3f+JE+e+n(%Qu9!H`vz*%QPaZ87QW}b_vYd(5&wOv{i`{m@ISlT3tUsA6SiCbCPxN zBL?h5kzIcfX| z_|xobv`=5W73GExs@)YqnuDnUhq83U$`V@Y&T4%8I}aC}PU~B>RidLS z7aGvYEW-aXGn~H+)sjLLDxp4AHU%!Z9XVib9&ReoV3N9y=d3Jq^F>dRK<;G@Dp=g6 ze1}dMEY=;&bfHM0>$lGF(RAPA6VpF1%$7Pc;lRFdiW%ZcK#f)B>`Jx7Y%#gc+f)kD zA;Tz;9WAC-pW>xW`4V=8iO(oZYb#FP%FY|@Q~x)V1tN^=z67?s?P`6-J|~CG%jnF4 zCsaGCK+(TTlBm|6+njvvupOWwEuAV@LwwEdCd1UPfJFZI6NfJz2WmWAs4U7o!6&?o z_GJ})NC)H9z_lFx`@byBV9-KTroWmQC5riv5QZ)RJYA|GSu6cS?VpwX=&$+P?MQdJ zw`@|Q>D&!?gv;0o6^Hk+98|0o)RiF9yRV=YzFQ)xC|o;5lZ$b3J9{3-(83Y(HSj8P zix_%{jfUI%o?*ceLns{vjvSeFay#S!*IoTqGYbs5?ZH&J@3kLf4=rYGp3lI3&|~T$ zf60tc1kz#`Rl^w!iT;RZ|7=)X!KM|4UIUvgWNs-^=YjCAmu+`97u?@Ch6>0g6zXy5 zspSN5*L=xd69ai^N~ty9Xk1a1#4U zoS^_|ZA9R>gt+~IfSY8cf}e(8%&6}%%+r^mj(53(_u`r0o;;cq3?osdE#{ghU`8VY zzFdlvi*;CmL#UoYVEt5fyC7Y-0uH@ho@M>&Yj31zdKC>6UXIdyK`((oq!fLJ5( zCya;LW+JBW{13$U-w#}``gTOn;_Hq%{=jbd=4Rj@F;Otw{YU2G*a=0t1~3393sf=p zWl13@GiOL)lSRe-)(qDnc$nUS#KTj!#?I0mao^B3sY;h&s2|K@9PiRQh3yKOh2hb6 zZP3LE77TwL0$sIF@lo%;xa{h@m~Ga&Ls}{~2<`tB`AIHEb)s|jm26VU&!8v)xkzG!t5S<2C*@eH1(Knc;xkOA0BEE|ZCTE$GulLAMRti! zWp3ydZBYLacT`;4%Xywfwc4dWtI7)AzPj~_Ep|ALn}|X)CjQ2z`lLx$CvQdVsr24X z?=u#`a(Pg1-rBpM$%^Ct;d|Bnqy9vf8Ei*GYUb?PMQ6Aj*^0)v5%Y>0$st~9$bN^BAUNK$HK&p%~1 z08Q4w5$|L;L=g@paf+~aB};FQ!>hm25AxOj8nn(F}r znW=>dT2e((=#0-NCf0w|hNeHp-4j0-6G=*p6*w)38s^oD78|Gn-@R<*9^nKw7zOSp zq@!m>2xvhR54Ls~LB1A%i{T_`<+n{lc&fF_pGp%8!jtU2J^&>AHy7<)J>TK|Pa~g$ zeae>_G`5DNeCbxzE~`jhu2OK{Pd#)JZQ~w;kAVdWwDL$np5cBdI@)+8VqmG&t9QuY znSER$@_7Ylw4UJjW@1Hqd?V2UzE!{eI?v&_+KgXkEz%(7UvO_-MV;Qj>&|>9R7p{y z6`pIJ^c^0A#B+lZ0Qp$3@q)`~04h@+0|Mo+i1e!a0O)4YcIFPIhw|*Jzm>mpGI72H z0*uZ3q?pHq!>rX1Yh~GX1%rAzeN~mUrS=7z?dF|Y=pUc~csTZt9!VyAwp~(n#Q-HH zREEd@2!8)vRy7{8-<53%bimd4)tY0qjf(@novTvVO^x9w(xjFx(2*GdZ3NihOytXL zJ{@BiRbh$|6RREi8fF2Nk-o4lMfW{|BXV2Q#Bh95G}BY)Zh3Cz&2hlbMRAaML~T89 zxDf{VZ+pz}7C-%%3}M@^W!<}J-E5agh7g_Awv_$`HdG1|wy;DHWh8je3n*f@E!E%=(lPW2x9XU*Gh|Z$abw z(^V6t-iuwsYMP;@Y7KJQvW9hh$zc|&x$$eHFa>_p>M?Ka_d_0EGD9Lv#N=vaQlJMR z{2Myar=}TDKX=GW9CQqK*i}}lqPa`AcJac2T2T#7$|9sKlrPdxGP8SOaGi#zKrx^+ znzt#U`B&_HuXFLf&*V12NjKAG{IOO5uL7mxwea~ZOjJNp8*Y@M?UQqq8Y%WxHpey| z`JckFUBkuiq=d)T$hlL&IBt8Aa7*e6J#U#~fF?DtsF#{Zb4c|fxsSlGl8>k14q`|# z&hf+g!3-g@TB)p_w9`B}MZB^sJU*EZ-|DE>^ix@y?QSv&RT>fVOzvSpPBZJ4LfD-u z-C2}Iu;%LSx;gtDO=&*?I4;c3y#O25Nc&Y`2uPuHDXCdtPU}#;&^mdzXMmilv9}me z>X{Tbcc;`)mNTX}r(5aIf&qkWnyC(x5ZB)Qy9*l#yauUR4KJjLhh5v=no2?_17Tn2 zeMCBKe@<3E4HPC)3g7=|e*gaoz@I_pd(i21^pKz{FoqxLacG~U16EEAxL2i zq#g_}_?mWRZ?KZmGoX=ndC=_D9m0_2K=@*mez5XJL=mal^oN>5+IbrF@jkzsEwbXV zzOfj={SGIvQCVSJ?p525siA!oJQ2R$_~2PE#rXaU0AZ@b#0L9 z`g!p8Rxs@rH=z}WgbRNG|8)bs!ySp`i`<4_jIXla<-v4`-OwIiAVVpT#==3pE%kHz z@i*!r^b-A*M4G^N0qZ{7DL!LKqm%uBU7k*`kt;Ky&jn~9!cbeONTt-0_l7h%lID0KkTsqSw1EM-7aJMRpA0G%dwB+uYbY_#Em;X^^$!(!&}PHkiO#H_z3}@X|ib6?M@He?0p5>W!@@zGg+^PDm=VE zXN2c;aLCw<;!q!Fn;^sr%~!=OB@!Re26T(woek+o2*Iy>?M|UXM8(5@ZO~hM4j>}} z1Ju_qOiS9jUMj2^fm6!IqUXi2*t-BkS^@d;3rPm0TNFIZGJvZ$p`vFf&NS+44?mz{r)?Y!2AC1P-Y5UBwPmq#GXN%ab4}-L)vnc3;UER zuYRNatTMy7W;sVnI3b{}-ajZigO=%#9=P}}g1KrnhJCbv-^^6s@pPa+Ja+XR? zfeamYt2~N-@}$fr_Ke2FMRGpI{^g<9)-DWhDF7LjK7F1#VQi28P`T8P{g?nO$Nu8_ zM3GDn2BL5%`A7G_SVzcTZZCP zLsRi6qPZQJrxkcy*hdj|jrSSWg5JYi54F<#!>aeIvyllvdn_24tN$}!=-n*c>888{ z)vwojsn(6xOV1oY%wX?4Or-4(^&VX$-JClE9;~@W%J~RrH;l{wz!82t$%`b5LeM# z(R~Y|oqH_?U?FiV@g(qONnHKD+4wgf&me6BT~k%)RftS2vd~K$LJk^0uHK_la3vj` zKe?g{={2{gqZKF8bu5Q+if>&;l9J=B&(pnBiG#Q3yR@{mfU8Pz;Lo$Pt|)Z8Q?v61 zQ1>ztI{g`oH*>d-gaEPBLw`%Z7nO9l@$lD%lvy8rx3~i0`Ux^h+5vJ*I-;$)$fUbe zerKhR8kXRWu~*I3YlppFDS2yJgZ0-*z5T4gC>ZeC)RZ9O@yNG5M4%GeEZW1e!Pc*W z2Mt7UUSLjLXlJ)53R8F%Pf2eX0w)_d%p`NAE)a$_aErX8hg*xDJIT-7IUZ4|0nERJwyojP~J?9gtt%73&UcCS+aUyR7O%fl#~| zqU9GypV5z3_e4;jiOE_cWbqtTNPaZ*lwex+YsnCH4KFR8soL3!2*^65NE~p z(F*9?(x4Z~_Mk2-$?|gcUVTPGHxbx+20X5GWn^AKgeP&z^+BsJSUZF;S{TbW zj5^BUDEHar(XuP6$-es5fe`07%}J0IG)504qmRYv7LI=b_0@g27AUgKg^t1D^qZ21 zvLF(~RI3-98rekaWN{zVPW^z|se)iWS^ga)3|N|Hh??+bC`Xm?vK+QK%fD)+QOEY_ z;^bHLeB|vc@;_TG%4wTa&4^TMR7%rD@!o<}2mWI;#i?_vZ<so8id#+i%D}!9At; z;fMp<4Kp!MEFEHkR`*gij9LO>>Q4pOK2Tq27v$Q zC*0*#^K)%4=x(R5>T*|gIvQi)7N*oa*p)M6ji5g9-$4f~F>R?oL=Q%OX}sf6=}6Ma z?Z?JUZ{uwrEHeWBx_rrW6pf7fMCQHCBj?EKZ0B?bMa3~E^`2~UuH%fRq+T9vs8*XNlPoFO#nemy~ zzdrQP+e`BIL#KM~DQYG8^Q;!dz< zqx%sq6(FCcOWPD-tAJXWFS@;#wX^5E*e&1GHBj%Tb)pQK%4@|>_XH)n&18}lG^(=h zS2K~}90;gwT#wpx9BezRp<)O3cj)ig1pi;p?|U|ZHHtH3651L_T|+Uyw&;#_y!HBM zHfuxdCbfPC$Atms7$9Z+Mwtb%=qRc?1zd74qh@tKYmhI&f?xOrGK=Wtd~KsKWFF^S zg60gTJc@%y*4QpN4yJE7kQo<{mI|2^Y*Lpcbd;Um9p2D-QhsUC2*1@OwQhYsZd7_z zMvnfX*xc8u<@WZXZq%W0<>Gwp>uzX7ChgE)KQ)qDgRFDc;eLfrN+@0a`bxb(aw#JS z6dgt6MHM_~o3u^)wJ}pceay(X-|;0#0yLSb*_EmH`u>9(4JNXOQVz>z8E=_a9b!_k z!2^>jDIAHNTeF1O zJp0}CeEa{Zy6d{Ddo@<~d9)?m7GgcjB$J-PpCb}LH05#>mJw{-2-o00kq{!xaki*d zbUX6K@x&xMM`CaM&a89lie*4`zoL4Ooc&Y11PDN{bbizIl!$b?0sK7a^Hs6CX0}3Y zahtXbryR#_qlfFcH|3KcLi{7a>}v<;Yl1&h)!vryTU7q!9Rx%j=Xmjl>cei9VqhQx zFKJG%6g2L7MfKgz4NdQ3>XCC(fd0`Gbg1UFcflVOKO*d=0>rO0JO4yH!nW-w-bH}@>m`aTK?|SBbcVBq#!)iedB;R-YixAqmt!&|O7O#M ziq^^fXy#b&MJS;!?`N0wS-VE@AW{&uu#I>GGz5Q85Q_!TCU(p15cM6yVq9h;3LOuMRyM^<`RX_KkJnT9$Tf}DbO-wj0O@xnP4`7bsNAeHPUQrhZ$?S-ieX#45 zK}2kYQHP)gZ07}|vMo1!dAcHOC{Q9Uzz2DqeB%i-pT-<00NXjz!lunpz9v7bBU|x$ z;$B`G%D3v7p;4-@+=W@D%=qA#hK#fdy^PsUX3K3s5z^#HH51A(PFA{Pk{z}^RhXa+ zc_i=He2*OPOoXLLlX0K^Ui?P2xzkHMl>O8PwM?31EcY!S$XegEYZ@;lgBG)lKVMn=L-yqd)jlg{CTDNk zG+YW77el)9kF%QHZa0y@>E!9Lg&Nqx>WF3dbG+6V>jiZvG!Y4iP+_v)r6QNA`>|ct z3Abi044n`tG%mP#Mkz9bhDA?S?xciXV`f}df=^UW66t;1^Iv9oH*hdr*`y{9Wxl=|tVdM#`P{uFk4@AT?p>o4Q=FQxv(FD!$5@btsl9 z)I5Q4D)-effDMYVBBf-fby_%hz59tWGMH&(r(ix{>ld(dAj-5f)bRB4Jv|8kAy#;~ z^Hrn)*bU%Ixg{rbK;2gNhxcQN{#{j-AS1J%)(ZI{)->89$njh14GEv1Hzs-!^n|4! z#|Sw66(L;v*pIz);%p_%I%H#Ho(b7$0&x{! z47F?CccgA$y*5>Vt5U>g_JehF6w%qb3-EpJp^}N2rVHQM5kLRhgw}_OR2QGRK7MQ= zHs})`5vY?ZKOTyrNe2il9*6atI3X#Pa>JiE$aF*Xc~z(G@$}5QM~qiQuE~h&YN@pe z&8>s33_6>mu#2dGQ6#yp+%iP$xXF6UIG$%h!;Q11r$Ywnhi>`zEip^Km2t);J~-&4 z)86k(yTbb`(}&%Aucg`B=h5DHx#lb}LjmB~EL+CHHPTO3(+f9EQwjN2nVC;jVt4Wl z+1FSB0^%?M7y-ce>a}elNI~GVDM2B|Hp3Zl=;8hg2mH@$^B6OXU*ck7ScHXXzwbM} z47B6V{z)ej0lPr5Ed^tXx(^EMCIrt)2{%+~v_bJubBgf~aWm^gD_;n~P2sZ?k+ZTNV>{qBKROs@oc+{j*>Y zZz)GMYTWD%lgErwd2S}c{7!w?2T7ALR>Vk(Rgi^TL0v!A8e}o1=zW#reDJAI$z+2g zem(T}!Ol{9N^2em3@^S^fv4O+NSgU7WWGRSDpvZGM2>5EZT8&fW@;W?VlH*49OxD) zQbJ*YA^E&wXC~X@WWa#KsoAC$P)#kN*YWUu*sJ?fJi)s_r&pAfLskr5>vQ0K>e!#ao_5m{f8J!hh_t#|tQ-i8b zfCvW^%8@~q#+Q;q#B0xAQvFvKYk0Vre@>AxOnNae=w^v{2A(!42&`+n4B&Rata`_@Xh*&4KEsX(d!9b?$@#zOl4oWEt+B@3){Zy z0kweQSFfZ;!md1}z%@}$~d)CeT zr%{93 z-aJ8tobvTOu$R`WVzebk_y;72^LH7}H$WF)TQ5-g@Ogga&pCtSyoY#II088sT{SI? z`D&|OXx#O*2{f<#>+fTpJsn>B80~w@J7&0=jSHYJ8~S#Rnew`+#+Bj#=fF2Ghzy3# z%`duZ%V#{~`Id^p_+5%&*N#MAMjCRMe;|ebtl$0p#Z4~Z#NTxnBg3o3RPkgv5l36N zSkY}^sRSk)R7s2kL21FV65kPFaVR6V-!D zWus;*{lxb!z-ZkcW3NO>6o?fKBs6C;7opJIenc|Ej4xz6EyfN)fPU0%JYTcGugAmw zsDVedy+qIOYJ@!(WRsxJ)fdn`*|{N{<5tzSY+SH^iH!f+0z=-^rE`DZBuFn(EftgUD4 zv@f=*+`LvC-QhG1mjUx&x;3CiKZvC^+OH*w z9=&V#5U=U-Qy#(jWUJPS1NvMVQOtR80KCA|c*nLee*y`&)fh2Wx5puPpACHl@4yYr z85L15ZB_FM5o)nDAtv_ysrFn&5eo1C+vhBY)fM8#}2GLQgxJ0f1dhWe84`_qBGu~5ra>e95{3P63DQeBJe*%os#E0VX!NEj#Sv;~w zbhg8iExq8cHol)6I$geV6@XDKw|=4K#?s}>i+w_3M2m-t9e|`X#>30z1b0oG7J|aF(H_d60y-NQp@I2oVcHAEyuv}K&m{5yq0uph2q&%#MF~P zS~nGbgc%&Hi^eFL8oW`XLe&h7%BHr-2kK{d?2@!5@9WT!)3&dOwXmG_P{3|xWq*4& z_k74BlF(_BFTi8>gCHjKc{3f7N?j)y!0QJ%nCZ);h1m3V$C?k;z%gUv|zY{2u$%VfSFcZzGr@I*$>d z5~QWl|C)9vaf?%;_N#q@5!gdvKDjP4^6-$ksr9A7r^eX+p7!I>6OKc zQz}HeRg?D;BWQ$i^@*ZJ#zobuIzZp%ir`i{yH7WnNg9Q%7EOm#aE><7%_eUK(oEcl z2MUihK6;k4cjFmh=~o}?AtU$$xUFAku^f!OW>Hun4M}x`F+Hz zQP~Zk!p`gYoHv3I+DS-@;+FbEoTM1g{kwxORIWbaQ$xt+1W-OLYTae9t^Yip@bR2y z!ti3Z!9w4gd0>}_9l3cK?t`zd9rZ^I^|{q1T-I~`>|*$%#avM4HgNNZ6T%{Cuy0q4 z+>Bl_1$E_yPODH)d;mx3EHbYAl%$yGs^^EVWu`JlubA%2u9QQLDfzk|UPse&jfgNI zjRTF+G?f-0bu>2OnU!^~XNsr9=*ocID>6Hr4S=4MDFh(h7sFMzxVG%tT?umSO3kef zVU6AKoGJU0tQp9^@-rA;Cr6WO2a9dak(~bbB~`%nFwmVw47V}`x4L6Ckj>2_`p&qUz0J{kv7L?w*C~=9M@_bTf z$p%g%XH5v1p7V+1TjVo|N(;G(yMf`RLZ_}UjWRl-wSK>-+}=s4s*Gm24Wco6`VVDS zp@GXWT>A)$!g@8c7U8)$+-jf8-51%XuLrxRc!siFLnioZwL|3$!a%lMpI+pz%N>Bk z>a>+rTa=#Ry^zwip488hRan7^`vSwL%aE?FRU51#^S!qw{w`l3kE1?nT0k*a^(UdA zi!eqka=3p9h=1#|leYnWv%FcHN~#Sj6ZRIB+V<*F@>J%3BqZ7kJe>%e5t&<@^^b zCoJ+5j(RusQfkvcRJ*8AT@NVrOFt`p(<^+|5NNPa_G1tnrKxJm%bl6 zL}17Do!Y9C+hN>cNtC>kos_p!+s%my^cvubR7~a8qNJL-dVazUhqVML2m2c9%KL41 zGhjkhhYhVuYOEaE2znhyI>MB~1W8x&RBBpYvy;dMn9oB|q(^ZDhdC_v4994rpzEAj zt$jp*KZ)67-ukwSm=bb}W&mzBvcZzhd~aXk{+Fxxy#@Do`w}VlyX;hvc7B3l7B}X< zhMA>|$FUW3i+5t%z^I%Lt&{~bUnIBtq#9K`ALpc4Sq0G*Ooqz4EOyirUG(Q8D-RIV z*DeNuV`kO;INK1MqpK>K)~h|+b^P`5FsUu&EV*2Exze=4;e;--^+34A0$oG?Rias3=#_p+ON8ti3qgbP$P!azo$ zo>awafI>I;177xAV#kEw9@EQp?YW`OGccm4rYwG%Sn#f_oypmPNEjWtX!BM+Ls8;bdpo{Ri-GxEFN;gdkT}jFmIdYW z+_bSgArI%5OQ0`iwvooD!;a0j^z}D>qG;Vsc*%Y?gZ}7mXMj_J9TGSToz~D zF&TZZT3?#FXLfP=>D`WEeH?0mmU8lfa>ogf6I#zni$7xDIX?1#kc_^6i;(XtIABt2 zE;<+7So;3BLC1!vC6^JG9PwX5SW_AY}IG zv}bmA-j8^+j5OaOd%#EJIB&_B-K%Ba`#B=qqj}qXo z9*$e+DM^aR!p+p_O87qCa@jq9v^GPB4S7oP1;%5{k0yyjX#Hh=8Z+nBw4Yf14AO*#e!sBs%3{i$@=v=?V5`YNpf3w5zUh zqyzM1D)1<1>;YmM6=Yn3xa>lf(2X`#-<0s7O-lpgbg57PtH@q2LHyz_7Lz5f07w^? zz4%%Kt1UiljsoXc9_LS8&@<=9x+n+v(IA?GiME&vcb#Za$uD7$oEjrK1LHJiXMYY{ zBL2f14kK+0mf+tfLvaO%DXYXAro7y?sI3hrpnp^TBhs2lv7J83Nu^n+g?!4|S&@4k zWeNfa%S5i}F<$06RN#uSFmC(x`N3OsvAk%L=5&?iR5ac-qX;SBgIRT@R`Jv-L?$^l zduNQIX>=)${7~zQyj)EskWXU1pNFo-i`LA4ve1C<-OqKN#tcSmfj`0f=~mwPM87T? z$KixDvY65`u2S0akt)^=W$YdG8{%}&_GLVHQ3}iILs?ESwqkNLSVMKe^T9e5LTpCi zq5y3#`CfaQW{BtP4NGz8E8J$215VW=F^W``$75$jL}q{Pa_6v76nrZjO^v*08vu^R z93j;G=*zFp-+)5cf_dwBT?{hkujhRuq@%0_l(4y%(?sHVQPhyVOeYQHh*+i9f=7FT zG@lbMB%Woys^E=B^o-R zT$I8l5hAM7#0Y+NGg=g@IOt*UAxr>x)CX2)RtdFy)Cai0za1SBDzMyb5l2zUfRa#O&D7s)VQQQKFwvNoR9^lRDoW7atw5RZGaaCv8X z!t8RcAm^sdR)mm?<@I1htWbbNkOTw7JD6tOH+BvTd1Np2I47DBtI4ySbF`oVGQFtz zaz;*uNI%3X`w8u~TpgM9eMtPV#`J2;7MNWg~b<&07J$I}(V#f*Qpi;4*75^OUR zqS7ng@-He7bPdepBH4#^cU18io@}IuN02f*~1Lacmp)bUZ#S(Xt4plMT1{TsD zV>;C-$p!7!QLp*{`v}`9h>fX!>@?~T99aEPPFs4%cfR3SK?jt-Iw62F%YvPBTBXSp^%--QCA|kzA9tH;9UuA3g+Mq3WdIDYg7G zI?_qQ^UTpRbt)bKaELh)*RVV@qrYm5F@{lvSXZS7Rs2PxQ+cR7{1u?z=1cAmwd9~t7|-x^?m=56ihS_mC|H6^ zhuf0TnmvhfQ&r370}%Nu3!#j9rufqFTcN7kXHqFSzL^AJdoR{Y=$Y}&pTUYR6#I#z zN{HT<(L1U4PoAiJ{QXqXj5OjjUd$1_Sn_NJ-8G*fYL4&7McR%0yiFNl-O?G?*Qts5QI< zuFF`AvHIPMf-kc?Pll@COv};66c;=VLoBl?f&rhb#~Q9P>nCrbS8x>D$$mmKXozwuyJ2jAO)}Wo59i_vc zWEH$ja_3%99ACNgUsa)Jm{DbmXAcaPSZV@uQUyYEg5<8m(E-FhZUE=twO}oTPId=C z%&nw5rpD2(*=`BMPZ+dbw+zuQ01K_pXkKpT8pm>BQTstHWOa!V>GqLM4hTl216 zw>Q#Nl-oEtKPkm-HxF}&B96T*@)f*LBxFV&u0UzO#IoM$mZmm|h{Lpx3&}AYOhye`D*g(#YxO zx0x~`!>R)5cY7(t_j8=GW~yBM2D* z-DR^Yt9+`GoEGERW2?ks%ME?&XM2G8L+Zi?06ox>-0Z|C{xm;Hi|{6+G?Xf+ri_`e znF)jU$}p8Y_^+J+%*tuJB)h`SwJvmJe6m68dOd!d6ljQIKc{#|1jRcWT&9=fu~r5h zCnr!xM=R*eFRHQ2;nFK2T5j-S?a8iaaYMO>cl+q*#m(;^68c_DG8(iTfHXFKZ#*A1 z2Z@TPdQ*ce2brk11ncvY3Z93PJ&6e$$29Loh0nh3NIAK-Zq?DQwNq)92^|FMx79&` znaw=P1Mss~U|b{l1Gb-SnniJG?cy%FfCtj}bscMytZ9TCm$7XKO25fd5Nvbd8Tbq4 zu{UVS*F&rK3ie{3;8DK-z1W%=A;awVdTe=2XwjVfp6 zpKJq-2{k=w@S21xCfxUMMFPw90i>CzK9&JxfqUx}{#9pCc1ClUM(G?C>7C+dZCQo&)5J3z zFOkQ~$5ysgUPd*q;gBwo9&FZ)<)+G4B&id|ZPnrQmv( zNIBMLEL2c^D__CZ*!m2q_qMTc!B`teFJE|=_?Pc$Ym6$+CsNd}j{c<#i^*T$NzZ4H zmOzrd*ua9d$u=3^6IIzjlg-A?_q{r47SrbhBm=6tO{AEj_m|aSEp@$cN`jXR{bFp&=Z51xcg-NwMZF{NO|Hdn?B7#kbk+9-Q$6-LWwryZ z;z|;vb&fH$YM4`~2pGYCMdnRC$?()Dept3{QzxUw(1J6YMZ*dnb zvUka>ctQ3iNZuIy&{!2_QGldF5v?ZBEk7#pEu@S64^$Ha;QwmDydNCf4G3i1D&J#i znE$dh|Ay>(E5z^1knz88&3`Y$gPY5g)#PObnc>UEtkCDVGoqqdg(MZ&p^gYhtJf?g z?f4Ev*nm=ZW||H9jRD1Foj{Kto@KGQCw9rz^wY;Cf&0ku*@QeLsFbi>;dW-NlApp_6f(#hjMDQz$=`wjVOn;-GF z=@2{(QsKzJ*hp`q=4WPBy!K_%W(O0g|C4O;oLlLJ%<5J?bwW>+bzg~h-g2OFOx;Y~ zDAq=67uO{LQ&s+n^Xf^;VouM-iTPS(?1NY)q{EcY4`optN)aI6xa&@VqL;eFPRbD9 zHac(#0R{d=dpacTeC_uK0OICaU@Y`(?YH|egdTXdFdxCOVfMx(ikD!G12wgtxe2Rms}jKn>JJQH z_*X!w$8Y8K7RFt+p@>1O z^G<2rI0c)>3{h~qTa{$+TNE5z>2_nySh=5MHDxM};4XctVWF%c$};0%-te)#7Ch5r zuT1hX)QDKRVCPl6c_qP0yeYJez=2%w-Jt@6Pp3~(?$vu?*aWI$0rdq^f@jBd!s~^z zV#NL#P@a9jFznGo0IWw z`h-6VbD{9&jAQ;8;Fx7NLC;Z}*jSprrc%OVd-MA?o`LZ?#wj5dTI=H5C0G7pV$;eB zaf>V0i>%0`D~=60=&r!U^^4(w3?)#{TWtg4tn7Dw4Ap(rpuLFt$goazu7>IWpsDn# zEo=3KnJ*8kiySaa9#C_@;GpX^`zm8DxFX^n`XDT`M@Lw}q2*6t zfE6{n-33%>bFo8mzl><;a+d$8i;1#eVn43zwFsPykuAP8$*tn;W`4Qrge|~6td;g( znXcTdC*M*&4|X_?)jcw!nlR&cOlKtp(pc6DGS`~=bfINk?MKwK_S2ylq+b-TR>>GL zrc?r8L?g%jUr=YAT32Az;_(1JxI6GcDZVHkzl8(Cxv7uK(Ll_nHAXlMZk0gj+%cD$pVT~_emXc_VDMbtC zZ%BK!nd5i&!vV|i+>66~7UfQFOdbi)c7t`H3sj;g#y@AWqh2WML#*s0*K2)Goy(Wy zKfc(w1)UilHc3oPUU9&IFC?TU%H=Q-vN=F&#r;Cry%!%nH1^;~22QH=Uw#i=5TlA5 z6ThRp$B*;@H(FGkE*!*+)g*JRH40FY``TgxUJ7Gi28R!vk)D$$eF>A4Hl--sX6u-p zMwP$B{BeI_hi&+&=a1Pml5~r%S)s#FlY#GI2tEq7vB37g6i>UBkaQp|NxyPl+`K%y z(S{0(>PP!!T0lp#jhAtB(ceYE@{7!X@9iDCAJCec9ypkuT~M(g_S~8!NnK`aRNodF zNSAJDzuF_^QnwD(m62W>N6c*8r`htT{ny;FjZ~&rFWhyXwt%);Kv~6;21)Yrb+DZ^o&Ml2BJW!F>bz9WZf6>D(Jik~CPDu*FR6 zT+cKOO@~hy0$6O9FwTx5%G%xR)ns497N<9(xuxSs2gDiNXZv_qylbQ)Vl4ya-jj^s z*i*lihyqhNsm6SSx;_5wLLbHiD<&xKJQI=^j{p8G-wD zBa)x_G($!^hgT|vB0T=8bZ8~6Ff2#GPTPAFb6A zIfj?}T@r3EuPjjZVGGQC;kf7ap7OhbNhpugcZHxe;+lcbm}L^mDL^zeiE4HXde06s z38ljuTxMyBD>=!}TwUU}r{>2c15~lfueQEcDe1b&-y37|(Pwq$>|F!L!PXPEK9NIj ze?lBv>3po4Q?AMRHSO}u4kHFs9vA+w6G?hc8uYu{CgY8ZN^30F%-z0#?HX9lQUN-~ z%+r*BaY+lxYw_+&0;jU(|53w^W510O0AgYsi&U(1z3VAiLop#_x#{jBtz@Zp_gukt z=?J;iqmu}V7;UyW43u;A=UcIV^c`iDXBc-sayH_+I=n5E_r-%*IelYn7y;T*t3fCe zXVY?on^**$J)q)hZ{gjvr={LbEAcwOQO`|Mb7h_ERa*v*f8(>{+4@hU^+Ssy#_VOe zf-2CftAIPmrJRDJ&^26+Tr3qb>!<$B+X?r*y5K!QM&iJz6nuwRQd8z1Js>JO$E0T! zK|A5;)LViv&(Y7~>q&@by^Vsa^`3+4UjYK9YbK`PCnQA0psL$1>mE8?oE^;$vNl}@ zw+@&5N|;~Nuz37iaa|1*6VL@D-+E+3Mv${EX3-4aO9S087Uxa8-?K}Q=>;0n$s{f9 zBKBa*u`T$;Y2eO$M8z&EJ|aD|ii7y%`SMguo%dudnlQ)y>X`kYcW^%WD4n_o7?<^k z*ZjhnCIMgbULsK-2;)sJ8<}J?CuoAu`-+ozUO4r*0+(i|1E{V)JkmQ8beV)*m3<;F z4ror_H(lvG4wo{U*V~m#*KXzlfrACG6j7?SnD)Vte)cJ}G8&OzrsXWDd=lDcUp5&^ ze2#Y{9;zRDhlx_4t-zL9&G3RJAN7ARg@=HrTeicT??6lt-9joKN+Y@T&lD@6>!mHS zFyfOF|AP$0{F~_me5dneK$Qmc{M0buVD2jx zUlBqTgEfCMt3Ne6)|14FN1?KU2UkS25Cxg z+|ETSP!`QyW&EMz%JJcMTtFd@W@|Xv<8`>A45{Nj&j-Oz&)0-2_pIU zAp#b|pbvz9R>%~=khE)3QvmZD@Q;^kc5zfFvF4+#O)C}kGaEW=#!q^s!r-&?pNZ%C z;H}o<9L9>PeSO!NyEp6mf_dj@v7e{KwJtK057*PABzXX{3K;8VFimf-*rs@2*0RWu zPzSe#zH^m5Xj9|Q!NBrB&7;3%E`DzaQzB&~k|Og^!)Ga$da6sQccSrTo$8Dw_x);@6 zGc_p_G6j-D91Baz?S5A!$izHZfcmGMK_gy*vg7p6<<-Wwjf(umjQ+2UqJo`qG96zi zQKW7lDh_P>US4S-D6BX_XUh<`iflf!HYFF5>^(Q)=fzIdBL8wF^O9Xup^quhLHg7q zK~6#1+b2+|bXbi&@|!l4K(i(HA-=dXAN@e!G)fCQ zuQp5}bXBG>HchA3n=UA|`daj}ds+H3rX z{Y4S2=bitmSb2cSCEZDl6ib~o0TJDyF(P96u1T-lHn#>kW*E+xFXLy4@$Wxy$igr_ z4Z_E6M-Xl~BqJ{r26WY|HNlUS-|J~lTKqv*IJkUO8Ih zahjIlBgkIfS`fqxE7KWX(OLgZ_4!SHMEPucWT|h*rI;8q8~f`TXQDzrCmvI*UHZ0! zwkBh)EpP%nP%K93`}X8|i1Fiqh80VgyPUIe(^Tz<(nP^guf!VK*aBqRPfsN#@_qu`inEFEJW%$} z1Tz1Lt+q`gFcajQBLdY7jD_L{9fy-V)^v><*g?&d37gpFukK>qm)zCe)QO+UW_*6G z=l#J+2;r>Pd$3ATE0ZW|w60{-cpjwiGCn^2&Y#epK;3RSz1ZV!FltIzNZ>hl_N@qN z<-fV$zUmeNeVZX%>9U-{iWU`a=9$TzMFMNmS>PoZr$dljaj#sSs$ z-M3FmF5Mr&{AwAS2yE${Z~x?*L=gAOr@w{9pYHFKi*k5c>%VcbT6iVJA(4@2e@>03 zQnStaCqs+T4zVA({D3{;VhNm*bsep8T*HoP+~v_PU))t1H}m%ow!mvkuhK7jkCyI( z7d@FPaf&Sd09}5Vc7lrp`pl1&k$8g#dH99iyJdXd!w*{hKG?M~cmyFnVz4Nqu?J!M8i$-{sra0n-w_;4}aQ>sR03WVJ54wg&BM^?gtcx9)UGSM4Mf>jL0eMvvcc%VW^VyPz~oYyMC|Ip&Da_> z+xu%4k^k9D?Eax@U`P(dt4Sm~hAYzYneWzU>GV<88b4!XlV|u(1!$MZv#E$FgWLkl zYF!WgCnNlrRbR}F zYCui4hflZG+T=!##H;q!qYs|@VKRX@xQ2@QFcNXS^<(;esRD5!+VjNfnO+c0z062h z1hW7)hqn6(PM!P<*Mq4yRZqq_sg3M0s z14i{pN%W9`n3As>Fs?ZMTZLbJ-H+vlU3LnG^sM1ia%bwk)aYg;iqA6L44o;<+_oH? z>%7bHm6>KBgjB0_rv3szm$55c5uEoSQ^P9?NSO0>Hy%$DKDprXkaC zl;0~Y4V4qyCC~<%LiPZ=dA@RGM#K&%lp+V)+K{7q5ufi(>Q8tm^EEV10-zD3lUzIh(iu-|O|M@2KD!=zY&W zrFWh}E9c#~;icQ4aBGHVq`!5X9{-LgbF+I7QSNUwo{k^dB98_XJ77bDHAg zLW#EpM74({XHl2-%=m4H6%xtUf7@E)Hd;n#Ulw(UxrI56j0iL2XUBr7#<#&)O8^mv zwbQG0K>60=kHNlY5b~vk_=QW7M`AO^+1Qr?K9oio0YXS6^vM>0O%1Z-X^5zlXaqy= z&QEU|ZE*_4b4@#Jb2mQkUII{pKNo8Z;*e%ncJ9>a(7~5Q!W>;s5JuVoA)V0bkiN^xIcJ+{4~C!x8Qb^lUzS`?GO8j44z ztM`hSRzHGTkNNHxNBV)m((^RHYVV671F<6Y$HjBU=Z;WG^DhI6jObpps6oTSM{|wJ z0tH$p*?9ZzPr=`!FINO;ZF$oPU$tZ~c{o?W?GKuK2Uky&U{#^{D7eTmWc))7#dHU! zEG*FQ6!MsO@NX*mZIjA4Vvnl)#ghdg#%u|vKb*wPg_p`UC5Q$K65-_*HeMxU-?Jh4V(?QTxUCDTiZbPkl7!?^V z7g^}Qr$n_MBbQiH8}$z|wry07_MNX2$x|X{lh;xi7M#qHhh`r`5orPCp&U(xE>qDk zsIemfQc9ch;K{+;!6@D&7c73?igDFlX}mcQ&}D{Vv_$m)yI|<8TSD=pigrwh-E*41=Q{yoKx1(>X1Mk{pk)6Pn4;qKODh>QuK zX@H9QGev00DICF@EJ6oQK>ge=Cw4s-iK3x2MTYUV#At)Kg&t3$O*V; zxPwbDXr74>HrH*=+aehZ1c<+EwRsgvCvOfq4pjr z4)5mi3?A4@`za@$VK|o0%5!~xCFownm0t*WCZKP3Q*~R)TnP>fkub(dUx)Z8nT%`> zLDNQUSal4yOuFAM+QZS@PPm<}_Yl$Li5TVPZIIgW=dlxbVL2i3Q11i=W!-%J$&rYN zV-`~&!zD><^5g?S?8682O%j9_@0DEPypCOP->2lM*4);lhSj)^4J4esj)JbN5^~gs z&Yr5)1Ex_b=Mou`AnuTdX=htVzK#@TD};HI7YvC?%GKe0Wl!0OaS$zs~#eNp1NnM^8#-GPSMMaj@(^8jPc+yrkJ2YLIR=AK=;eBW`YoKgpZskb| z+U-s8@Khm8awml?{$#a6_f3s(ep4_lrc{JK_{vM+5OiJri4Y!HMrJQSFseEf$07ow zzm5gyPHP|(qviHhmGam!ZXV^p$6kW5rIf<5t6zt`!~grEfIL8*b^sg+e)i|*CL$5` z(mPcoi%}HTES{-ouSvyf(Fl$yyMgOr*e?;=k&@pvZIMTt*nB=2^?VAxMA^nJ>~yr8 zj<((MHWc+cYsMYTIv-3_t#Fy92SCV6EE5nl)PdfK(NXznIAk%98NCys0R6lgmaeZV z@t3O^af`F8@6rUQjRh<6`eCfp$DuF%N=}NBwR5M~xw(V+srgp0C9IGL16-pBlXs8D zB3E8wRzZVj6xy&Ze-}mhkKEKmW{B9#gJV8*y>AJhaev^CXdF)P6e&LGVk-F8jU`;N zi-ms<0y5ip2^-7XUv?%n2^$$?Na_&Of@PTL(9oM?xmb^(VGSK1wT0)hghYflhH@K0 z7)^H>zrth{-4!0Bs~DXKC4>bMJ?V5v(*}_aCEnw!J$7p!fq75_#9;X(3M}VZFY@| zV|ydM4m3JGaXE>3}?R@+W6p4~nHKVfp$E#{sAp5N~KQ=5QSfUp2`hE$?99l<+_st$BmWB7J) zMs}aq%tBHL3;JRkN>e*urh`X=L;hL|L|FfSRJ~(#CBW9L9ox2Tc5K^8$F^^;V;T2-s&nh!wQ)vy7stboqkUroqhUvmg%EA*%2da^dM zCrQAB-|tAvq?JUI&9i!vCe2h4r$BQ?^9f&ti(L)L3(yv?zTry`)t0qNnZd?s<64hL z*uM|ZiKoRfZvw-dqJFZTV2i|<$inHudP;70DbTf(8rHFg73)7rct;pMe=B{8`VsR} zviLjXd0c58e}K^F1WE6&O|J|%{z;m4NO}%U%(FU=II&}@s#ZxZ4r8{0U$yaOK=iK_ z9JK)0(oA!cmZWBVHkj7qG|AhTtzWvtHkAlZVOW-e8A@zml@RRwAY!u7^~>=>HXaRR zbV#H$`jVr)cZ}h?-b&Ee`(tb|j@&+9Hpqgfp?+?}r6cnj>5)>DB@la=dRL-pM>XZo zy;x|7oWi6dhF;}96HqYXjHE!N-LK4t2%&eAZN=?CYqTId$r;bO#ia`b%^wTWPd(#Z zgvPBi8fd9yd7_ixeyf#xyI%n&84*9ZzH&q0v;RzPc}o_B4YUwh5dxbHzB#2-LVBrdQ-sC(9S^nJ8vO|GXA0R zE0SGGfqW-)T7q;0hs+z*WE9bnoG)Y$F{Iw1h}{X z+*`F`Q+Knuo!NP$rNC)&er+y{*RD=kXVbr3pL2?D;S6#Z?TL-~IK7Yb%Nfs7*IVW= zxh=s@=|`M8|6qy#73aSLSqUH7f%4a#^@|8uJyIsAbDdpcE262R7HuWFkxWRL(BSqV zThJR2A1USe(FI=pR1?<|SV3r|oS^X^*ddnGzX&oF=>BDtW9`mRY~^1nuwe=N5tmba z6x`95>{NFdHls21@|RR<{1?0fZc9ReWu`Ld|7MGsTip;eo$h z@o*PUHMgeCyQtzuPyHmMJ3h1lVTSzs zz^{hdzz!8AQB45laO&!$i@wM#ojTyXQHHbVh98|i1WqQ!Uo4|~QN)MVHY_u8d>~a^ zOcsADCnEVhP~i#N#6pX=%mT3k;;obV@We_uo#Gvww_6(*m;Y$cDl=w4$|K!f)0u5ts>=8uU{Sy<(3vgu z4G~E!nv06$hF{LjQndYozi4NCnk&9LV=N7QeB1%%*{-d^MRh9w)KGS~LN~txyppZ* zW0D}#eE<>ddqS|6XjcYOY(Z`;^Gekx;VWq38Ri_4nwaG?OPMNcrZ9PFHd2sadu$wC z1tzBLwkbx-Iv6>t8Bl^Tlu%2TX~WjqE9-{U02XFgv{m~tpQrU8bkhl4y+zZa-^qdb z$L0g|bxG`gXXw)M?*N{Y^mw!@1T7B6bLI=S4MhilY%H4F!(iv5OCoR= zK6QaYOxo+Lb=DRpzQ}2)GT|Hqv2Y_=!faNms$+h-MMJG0iMsz=C>CQ)JR+*J$gkqS zFjqUX^A=Tc7LDcG zn}5p*L?-`Sv{sW0xNwyP58ciBvDmQjGI3Eb{RhQ}?e{OO5&(c5Ab5O=HX$u63wb-~ z6(be9#=tqgs=9xP3|rroCsNQ+BSK+{5noMe=53V;jltj_TkyZDIUj+23k3W}@w2fF zDI-O(oF(ZM!9-tA>bR2oI#G!*WWKq(yThH)Z6N4j@jiYrfxCmt6bU%vrufT}s{MxX z{cUN?TC5GcvhYrx3I$%OBVO8&gb~>?Cwr*3hEW8I!Ru!))C3=Ij&KCG(XoQ;jlHVK zHVk?h!00=H-I^Z_XENh2rs$gl%tS*NCX+hV(w#f+${7gs>@@&l4++bz0U|d`Pgz>Dr=<=0LSid!+&DI(&0Z4y^RESfM%%t|(R8 zC#R^HZ!Cg_IYs|Gq5?aLt;e|#b=J5@-mC@+{h9O>5Puqeji#@prw~ac8gPhNt)&Dl zDu(a{{rp%B^JTkPok+bcM6xF!Xt=n8#nfgv=&Y>=ra!vFFDdug(@=I;Ko0);)<(cLT?%${Jxi~s&0G@ew+5pW#c}Ph~ zoI=taR+bBHEr89dVl-S2ICbU^E+T;bD&0l?{@^jf>483!t?A`D&aka*CKQngN*-X2 z%Y6^j_JsOo?e+)0&kkx43W;}Ga2H7Qt-AjV|K=<3|fh>91F1-O1Q6rw5 zs#dj+Kpwqser)D)m`G)R4C6t?N1rFJF7Rl!^A3xL?Mg#k=qPVu69+PSb>xB`h54wn6l20*F!{$O{2$!{ z0L0VW#|n^lCi;8`gevwRG8)FsqZV+2JpX3rUEKwHOc5Rx%;x2=T?E%3D- zp2%P^<~()p?d-M&WYAj{&$0PiLqDzU)_w@7Q^3RX)!lAF2&lYQDo80Rig+eM9e^tHp!4PeXWF-wg(iljnSwPn?@`1sv@} z=^2n3ToeZ@ZWBcO0GMBb5{wSpA1$jqxTuLsk|PSb?VAkD9GNGQsJlZUhX8Vd(~@tb z{c;hstF==Y0LA6aP(D?I#y?sZdN$_Cco@Mo1pg23UP@V!+;gW^e%0zn9v~9Wh%?hL z^{>qNCdf&ck{EXFg7-y7GR2}g125wS{7G$WVZUhnfGHX>7044;FGs%a-u9K+=Dz{7 zZ0Ae(q1FBa4%uEEb0tZ(`FS|5P(bmIsRB9u!KGVK#8b zPXOS@7X>skZVYRvSr>Sti?aM-qwOhK3Bz+cIp!A!gqp2I{bGPZVj=%A$V4_`7v8sJ z1)^=qXsp>Z-y+4NFyzH%p94)k>G;XpfRpZPsGkcgL{6_1_M!9FB#5+CFLV4)-;)Yo zJ#>Ik6qrrbbv?NY;-0c#T;y1yv041 zW={p=-+GSbsOjK+QGlAq1f9mb)Ls67NX4UIn6!0?qxKL@kQMGhGXEl7Dkj3(9Etb2 zp;vlkA4c!b-XupW!iXt2*CWR&gk+x)L+KoQv|!JG5Z*crpV#(h?qSjg!G2A(wC1`J zZ2*Dt6`DPiU?75-XscP7Acd0#?C$hS}zL=a&}H&b=9M zg}vgHYmx4u<_w{WKm|*|JBX^8+9samNR0J29@BZk=@wH?0={@lB4wOEI6JfFw0}8 z_H~SE)=k&V>`PFwTD=u>&@?i5ToOM~hM;&^o-s zCC4grUtYNLVh4x=uzv-*w}5mhx(`m*e%nMrUV7RmrG(E=C(9!#x69UtcL#KP1$JxG zksPTNF)%?IuArxjq}Y@+@=1IKnhZ0rxyc~ab|d&14AaJf9N|WjkKkmlXC}e4xgn&_ zIMv(YrLHJlH)EhbucR~#MUZ8fZ?^MS*3eDQp4PiVZzHaaD!odni*77mdbQ%Xuu!-8 zHqa?|QIbb+o6#|*1v7A##J02(*#7Uws>w666L15t669-%0BBZX9Us;QS6lI{ifPZE zIqbpD%2wJxQUn()-h{2!5gpk45ipK~MaPOSHfd9Bbq>!nJQGUG73nG2FV-s?Ro3o~ z*8sSI=de*&n24mEdw#T2&2|VGTV+Qe2V|J|`ghtaPk8D|C7+*ZX0fE02apjJar520 zou+3Zw5?Lu32rh8y$k3fgJ_TfFUx=%56X4k1t#u!7Ao#LTXUfSTszx;i3wY7FX$Vb zY%UtZ2Wb2;eZQJOE_iQE6f?6QmVXZbbwX_4atiExp-8*+M=?=BO2d>zHmUnS))huz zp_Ks*`p!m|jp$5g;?Y=7In-9(OSP(o$*nRjGfuj0zI&vP9j0cq*_1-aWtxE$rdysxM$_}2Blz*^JeV<5+~Hh*@7BgaTlrY!9+4?vpxhW831DEB$<;-* z4C;E3QfGssD^g)?U{EIU@kJQK@A5f_-1JG~aVdmFy47xqJ$^j^g z;&5Gp!iFZlUg_Sz+1xD#>QYX5Y$J{WBX#`NgUa zUSUY(P|3+CewWba!Sq0v2r(GwRSCqFc2QQsuGS#?u6#A=ryJYof%QwphCF@6USIw* z2t_(enUC8&iRaaUvCn={Bv(M#r^+_KCjqC)acD9Pj>e@%J|BXy!-u`(y)k&2--T52{AI#*91HNpz^=Hf*pCl-A6I5_TOSR2nms%Hk`c1*Xe zV~8LQl8FDPnS`m-m34_?Yjt%Ksr*sBc;hy8r>#_XiCsLA^}Vx7p)L7E;`=cbZL>}+ z0R=AN7b}~MoQL?nROWfOF&itl1)Jk7QqVgi)fDJPpu&$N#EM@gtQNE&LAnJN7 z7p|RazOMj<3N9WiI&z`Q%;dIyG$9nwQA^|Gf7W&z^@hUZdixBvLbeM-NqmH=4bN`e z=1S60#X$8YArCa5GAQfdgj#-vR8OPKH!CXNB`qxoj#JBR7G#z#wwkZlMx4#40i$K+ zlntRJxh3GWZ)FZ7=X|@51>a)JIjLf@-tVm6@ZhHuwWT+ zSwu|ps#L8@=aTrVU zkKRyfpsh(OcrlX}{10)hj)*@bBgq8c-+or}W97=b^l}JMS=E`9R+scJ8u=2=wq#;c znaxTxoN?q}XJpgz+B$w8i?B~jPK3M<8-xkH&s`%!RY5-nhsT!h6^B=<$2JmdRve8L z6BJl}D=ct~=u}HIhKH(Q zu)%m0_Ea?Vhfp7~PEx?VJd1*agl&-yTu%@=h^W}Ak|8ATdgEQzR~j+rrmqa?#M1O% zl8hTin$(+$eP@QsXci1(FWyN!FVQg3Z{R?=2G>A;Ye4Q(JY-;<>=xe!;#!#It}g*z zcQFs6kR937^r$?>dE4(L%GocB<)_qfA3JE1yx(&7G#(cPv}TqKVL5o2%XU5&l|5WS zw)+07ECvCRsni0kSf#>bzU2eZn@G$1>OQgg>AH*a1f-dI=^7d9&zU`P z!Y>@4UWISCJR@&soxDpSyM=w7(;m5N_DPX z{qUvZMzI0ni&lA3-D_+|KTx#;6!0<$`!bnLLoeK4P#|_M>6~z}6@sD@9ai<*K~VtD zk^sX-)pM0*>iA)*l82f3i-li}x_Wo(PRLo(q%tM=R&e5s+J6mD=EA}zO|Oo*Pj((K zDwmE2A=-iQX#nqAF~ml{2Q%C$MzBWgZ<1n2r&t=EvX=*s5;k`nH!hqR-oPClJvw2HvE~{vNOXR@6s#mVUDx9&-M~+5Aye1nZ*jw%$bcKx)CBuasuA|i*%E&D< zr~T9nx)Jg2Qx)`J_|iQ2zg(0n990HuJqQeUBF&9njH|QIK#4q9=!_o?q5ilF;N0Tw z)7#jG7M*EF=w#-Gy;Ni&B#!EV*w-s|_lY{XSK`;#V#_G5!E z(tqtT=CgmB%=qBfZ3DZ}j8R2oM5gc3OP=Osued*_0cK#5; z1)~AjXsS9t$wXi1Nb;{d&N;`@Tuoy&1jug+oi5(aL;#W^Ps8yYB2t2T1FI7_nM)BV z=!WHFo|`1M6u}wUEv^r|-?~^oK}&w}OZY#1A|-aMBCKUJEETf4s?`M(O{x)88%`>;f+$xKco=&UKN#q|E z4=2R_iX(?$Cw0)e=dwoyeb=npy2kRuVe|BjkI|yQe{zH^*6|zggS3q*%hbw?7R@M< zGM^Ht*8R{buuUpE$cK9Q4!Ii#IR-=L9V``3s&K4AqYzjw&%aUW**b+KLO!8obr+x} zHSnM0$l*4e;jH(7QMII|9h5PG%*qZ%V?4{H_jeKt?N!0W&k5j`Yl`Gd>d^SpBjopf zZM*Kwe)A$mEa!IUEt%-?5_I1WY0PAATKz9|AuB2;>e1 z!1U6eh+Isd7#4j)?x02I4yl8RKi>coA$AH0ZUBNjI_mfyRw#m&izABhm$-E~O}Z3aQ(2%RzbjoHI{M%$0O8|MPQC9C*ZA72akbRGF~*OXQwdnt#a zz*!ub_%DxGnevH&!I{7m>B)}RhLHf3xj}c+Ib_eW=W_G=aSquu>aqJKTi0Kmsf^pB z!(L)NJ;1Jaai>Hxh8R^gg*2&^FNT3O&pot8t=!cDGA#OKO znFE|aG9w1#fs9z9qR?*#E2Ru!JD5LIm8i>EI=C|zg77wpBqSXvwS&5S&=4J6JhyMR zKSWOZ^ma|i>#6~r12pnPvxT^*R}XQYbeWm-!pF3gno}z+l*L2B+MS+CepJh{ToLG= z7?!#E3>)+sqse?5GO^JS6kk6~gyt_@GVxJx|6e*EKZ-m62*eErz=YjIIa)5Xx!mi9 zB<#RU#%FKtamD>%Y%DB5K|+l3bs$W&Sos4R&I#mHsG8r;paT1UkbVC;)<0ihhXJ75 z0P}zY#*dO)P2kVjPX6|0t7)B_j*jDE3hm=Y{ zbOsiY8D6RdYKif^uAw0s+==gK5=li0W`f=`#2mDL7Eo%bE81DzQJRQFsrrpln@f9^ zSiePx$qM_TxFAM0*%GtB_6gZ$?#}j6G6!zqgwnYzJNAcwyVYDi-iNiI1?Z@ezq3xE z$s+Qbwg}AHhW;s2-HTgpc^v47)2EY}L28kO=$@ZZX7hB%JxBdEo4a`+t;(13s9uW6 z1Heazfo8ojLtwlI5-7% znEP#yw(~e#nEVn5VYR(*=zuw>$cOIIyl{Z+>Amg89hp+CRTMd0a(4>+%U#pKzpxR3 zOm3S#*n*-VSkTEcO}R@XYu(2d9+i$!cXE-|->!%6J{@yFSkJ%`F0T^=kBu>5lxHLT z&0F4QPe%l`KsLE>R*Wz$Xi)knPxFh(>GCuS_8U&MQ*y-u_;(iY0Q`S`D){&N<%Tex@vPP z!5?~oSjEYwVW;YpuSBHlOa#(9K;)G3?5P!oJ4RYyqye96J%1O2K>F?Vl@-qL;yg20 zU~hD57O`25K(%EHZDEAhQ&O`irKmHfq{Oniuuk8lrYKDdDwS9@G>KW7Yw88PC zavsO~NM#jNW_F$hYH$uc(wJ_CjLL#p*m&~{>)j{+5N%qPpY$r5e>A`UJ}#wTUGRSh z+!Wq!7Eiv_o|uRlgc5X2Oa1O_o(@1q`j{E16?QUEvq8lxZLP&f`kM=;XLvIJvrSAG z)V4A1j}<$Brb*<1Ili`Y0ZDUq{h*Xe=FX#}x6?d|v|s$qvexo~Y)D8}8~vx5uX{s} zJWt3McVTt*ZII9FUATjfO$gf~^kF{L08VTZSWrF6Pb@Ijc|G+*tJsHxFTH*u$S)5|ZlG<+*r{i$Z5$a)tO zCElu7;eo?P>u_QkQ1>mG31*2ZoDl{0pFO;cBweW@C<0D#r?Zzomq>k5ZQo;6g)@gV zAncOc4PWC4Wu)kDw;n=QecpXtZRrP^BiJ_wIeYFw44%2)_yd&^_nmsOtITJ1g%Lxh zwdx(o(J_RIg+$eGC}mbJ034!ZzDwyOgL`^e(bhsehcZnX~VJ;V_W+37p;b#(h6Ee%Bt=EXl7o_Bp>%aUHstl;g zO}%$k;C(h=Jno(!0!b%yi37%CzMfA$+0EP@4{tW)%;yy^koPkE0%_$mPDtV6Ff2;X zWw9gl=k2W|&N*{);UlA>>I3Nz(1dOe1 z9}*AQi6jHY4=}+2IC1Tca#5v7Brd7`WK?MGfY1K4xgJO zjsHjZj{nGj{}p~QN}S(^z~1dvCFmLyllBe>LxTHp!AZ-f=&S?+z5=YGv&X)6o`izt zQCZaQBFxE3*h#HEvfZ-EBy+&2Iha2T1U_2AJgehguy4dEl?h!b0jqFK{N8Rw4&e?l zrw4p>{)&Yw2yu18q|xyyRUS#wfm7{dAAn}L9QlA+0b;=PeT*uX2R6sT4P>nBV*m>n zs#?P1@PBNx%xX=5mU=Mu)4}DO&Tjp|?4|Q)OcegeN+Z#N*uPS_WN=iWpCyvLg{V`% zAqnTci%CN-?9u{WVMnyr`EHHB6Rnh@=E^c2dfiqV{}kUVcPe)VxT6$~8`f@zSp1YE zSNRZe$IsPYCLP5P7l$+x+}Q?kmK~-&xI*uM*c1rsf?c?Irzp?+$L4;$y}UKjfAb4L zR#g_`UX9WBuhmjb#MsNlka&BkpyAIC?STAcxvh1|UHWM&sDZGXVPwW#;kQg7^OOj% zRX*Xh_ha^LW%v-0YvUa^s$6(pS)PzQyYUS5Bzm8kPQ?MCBNR~xG$-zq!kN5fMg4kM^Z!?v z=DR)Ht{U}MjwCr>#q#hu5|Q+UUEn!U?%z0cpKTk8^og6eIy*4S!9$_Ni%WQJvmZ=+gHg5aBMOWnc1zlM}b6 z1GvD@TBTg8duD((lV}5r$w+DVj&AZ~=;lg+LfDH0Ap+>xJzILC5_pV-+Lye11Pe@U z*2BXnmQQQ2)q#52 z2UI-Dudp<{>R;l)e{oLsq7yoXXL4~T?wuw&((jgb`UzagvRuC#__P0y^Vu+*(EaC$O1Gd;%0{Y^W{Y@te}SSX>%ao+?J>4XjNFFm{Af3 zCWsSBWNJQ?D#66u6yp*b_Gh^=!}zQWq_@}l^t14}-7sfrR=I$=i7@mh$WVjcR9=H! zmOhi+EoBNBi&8J-W6WS7ROcE($RR1j?5V-gfUOi_EK|0`86u-pmYekfT=3ro+nf;F zrl>e$l$kM)s3|ITk@bpD6*ADnubUH7PcbzJ3f9urTw*pWExL2C5ea0VA zU=)8Kp_%z-{QmT6im>`YC$571b-kb1QC9DAGD!2naOZ8!%vRHrlcPT)0>4NqyBHsW zHZBPaPi=#qtDdZpe=ir;6D!S{w&tX-;Gl#;HmJaV{PU^Jcl#Wv-`cXKt)iy?I$)lx zuMak!mXJ)8=>cF15Fjk=tv3wwYhLV-NmPCyb=gtQ)>4#Vso-$QTY^S@Q;F-K#tvMf@ zJTpw~%pnfWMrX`mJb~*fjG1fU46D=+oT?O20hBUO%4d7}$mqG-NJ*%Z9DcLIs{iZ+ zYEx6I(p~dV#jA+j7dkFo^&yZos9U+=xC1OrP41dTC(q#%>Y-od12;ZHRFO!7DXwj1 z^q^QYj2s>Yf8}b7YAs3~h!~2ZG*TFLT-7>x?~Zb|#~;QZ`WOrAhz(CDYiQ_xsQr6v zc@D||=NC_z&8s-{6qLg2Vjp%*vc4dU=0a(xY4X ziXNLDU`;$4+GjUr#LkNekcD5y4si};(sm1e3ySL%B=wH$)RLTHK>-3?N}|7!NZ-=) zO0~G7Pz8+;@WxtUpAqGoW`@h+z>1mAIZ-?;Q5bH_}_h? z*ta&fdv^q-{Mk{o> zF?u$-<&F8EHGXee%=B^J7RfkvCtB%@@RnMGTh>!F3HDWEQ%LY|^jtg6!Tvgs2Z@{@ z0x_kqt}%b0=MjvUP~;25DQFTPk%#f2kd(_=HqwNNH_c7oUMw$`37TubfQ(gHD(=bx zsa}TZNb@IX_+4lk9j>uGdF3ucp8}g!MT-AO`)|KjDvf2citqhC;T#-0B}3+O^u*YX zbw>YGfN)N!Q!GIaU5b(zF1zKhO6Gi{`ZV1;3?cTUC>T#MgBL~T~nECy1mO({qOfd?AU2>OxwsbW_pUgBeI*Psvn#dXK)7yZFCXp&bx z=d`Cswr(0JEyS8@CMtH9Zb1qAKJxT+3^YT9J3*i^g~ zLd!YLAB4JLX!mn5iMc+{mzeZ~WzP*PW(a#e=+DXz*D(O|av@0(59rkBo=#Owd0m{^ zT>XZz3Zb;e$oQ>B@qL64zgY)8<+_s}bO|0E!ZyG_3)J%x#z#|t2gBMVUIhdgLqiBQ z9aRF^+0)LUov43IZxo=zsRV5tr_wnPvS3N+^f2qV_TH=BY=H0fz`O9mVJX>f1{Yf5 zksfHlBz>}f(C=d9(s(ld2MB3aYL1V-Gn5PDP~UMZmq=!o3NT0kofvo5cZN!4XpXcT zsFDTMrGQ+%tILW%RpU>0B3(qk@E1{Cz(NR*QELZvZ1o3G=X$w(%}*D>=O5?rzxwt@ z5xmR$_?TZ11)Zl?G3E-6FoO;wQcrW&ki9g1h$*@Zg~1}2u#5aSy7jg;H(-ES$g3LAS z@9O#=R#akxyOv$Xdy2!fw;|pgFci~GKY7UArW30)$$g`#*2KG~rw7?dzmM&&?8(qb zZu1lF8i-!W6qb;Q;O<%}9UT9uP!t-tI5h~_jc$emE>-Xl~N zP$aO-PQL1^GKOJEjPxm}s_Og^fI-7ciE-7I6i*$P2gk)0DF*Iq_kzp>p`x+ZaxI61^m@7Elgp&2aausTd^t z0_Fs(vjpXgE{A-26%3YYXks~^`~ z;6Dc9f8`$Tv;OIR>oxMBskO}8{sLgxqvlLvt34*dz}=0OA6v}j+eSZS#nwd|e-g#4 zkd5zyrV(2D^_++iFj(R%w7?vsF-1q&vGInGf;|L%IdLUaMY>1Qk}bBPHqUZK-Up^^ zj(vrCHAQ^3F-VkLjZxlJ7ktN`1@4G(2OVQM3>|NBtLOMP`3046iQ@8Hevvz~k$aC+b0M_^4|J%b4LP-5NKo!WG25kaHG^t8l zP{z1NND%({^_IATKzU}!XFT3AqXZ$G@tT;L>4 zE!;GWL-UvnPZN5&9=8V`?$H`_cwl)beJW#>j zguC=0oyL6>-&y0iJge;4CF^bI&RJAXR?&FM(dt!N++el+el2-IMxP>XJ-%` zA!12gH-UybGy3WnYQ~l#DA|})MqrKbNpE%*0EaC|pMn(L5wS;#7Z_b(Oc^}H2>_z@ zY8GvDFFbf?E?8!;wmg!Y`!w#r`4=2)*(S;)L!BU#yJad=<5eP{V(mkzxo;K-=E{!6 zZnB?$`O@+v;tB|-SzaObZ;y2Zse+BS(DTuxCcp+d`Nho%Bgax39$rrsHL7GO94Z8r z>(`}w5qwvpKWT{{(XYZ)yY{6)3rG6r`Mn^Hr51I$jJcg%5`mOT`M0a8dyq4Z( z6HcF~ zxd(&1wXS(VGp9!sm$+!7KhbZ#Lsp_K2tMjtMvU-$UOGP5L;N!|U;*Owd7bwmt5euQvos&iDsr77!ifDd&FpimbB~!SlNB zvYtOz{P_?`{-E31f0J+v6QLGUvOaHlgBg1a_#O4H+<`d|xQMMa?LrgqnftFTaDgazAh2EIV|(oaP65Wg-y^CViMTh!k=7}6|G2Z;?#@`t?jRk1 zzMDXm`{7^R07BB3sZv3*!HsV)eSt$uC=5MFZsXtNwj-k<6FIti?@882Kw6<+^LNz3 z_5^)8yV$l4=rl|pnjOUi5{wsPC>n^Q%A+tpUzNtXE(XKU$i89UQCo&F+Esll_{KeL zISbsc>5@>hD%x13-fsk)i{BB(y{pjC_a#=bCy3J?232I_1RH%8&{Ez+lJL-@QIQ{l zUZ$jVN*+eZ58svmoInxqsoYQQwac&+B9Dllf;g)|s?FlN36k$>)`c)KII~l8E0$f% zUA(C7%950Bzf-DKn*-&Y?M}(Oa`8BP-#u{~7?WkHXn>}|uxGRaaQy0@u@d49Dc(#_M7#Lz>BO;!U6b^U%vOw2{W=Zsl} z14nf!^{=1sNtVbgMY4sHN=?>=`fjyyJWZ-)(xH(44^9#NUpcG($+Q~N2OHywFJ@^S zK>^vcLB-UpRRts(9c~TATS+=qn%Tn~0=6NA>ZmAR@HNRVOnF8a8;1xYUoxB;eyFlA z!ee5k{5I+{1!jnEEd==CQIS)K|6h0_|Nr#y41|c#K3634s!IIRf2l0MRqvN^7VBC6 zyhw@u7n}GmT&q2R^Y~=&n4^KigZF)u@F!f0A@UzJ@xP1Gx69WG3ZCRcQ~&O^G!tF`NADC#sWy_ z_;p`M>?t&QtsKa(dzl&UCE8__(Jii|-`!Uf1mNf{ppshw)Ibu;k&!_k8_I9?Hx)2gllW zsDkQcs(`+|$7y-nP{YN}QD#Uvei}=#*dg1ntXs`%>_f4ndm*PIJW64Nrz*w4b}H3} za=!D}Di5uHO8SCkZqV6>ys3>~(b}dP!!EXcJl`s0z>BHOK+FsP?AUp%_)DJ}mE(q%})C$-UbPAdP_ybEQx z9kzu!1PH^}EstCCX?VZ}%F$@S9AK&ZuLLVgv@)B%7=0RYaon?Ipxtjm6T@{P=d7$Z z4JFo2GWg;iba8ezwjn&YqQwE1u8n!C<{B9RQOa@R0>lx|K`$?@jb3lFU$W5;M|5~? zFCGp{{m%IdzNZ;LG z(RbUqtsjf3fXGobfa3f7aq!$>h=5w=Jd2gb95F&l)2;+V$oh1Jt{!whzwDtW5R84~qH6VEkXJp`)BqLqQ*8>_d~7|0h9$|8AOehd$Ss zbzjk_-JLazG*P_`8jAxKIVrd*dPiF7ZRwQN(5w8`zbNaLhY#Qv$?u4yuK+$F;UhAb$x+^kWG1W>Q%H44wI%p3hrJE(kUZ&AJA5`vfuc zulyORii=-I-CVI>N3ukZg%Sb8`oayd4o9n}A*6P;Jm-G#_J=8y!Glx8eg=AyMCCwS zdTl*6Aev~{+hH5&%l%m){779+amP@0UJjw2wgbw1Z)6}4c>N=o5l8K=8LC*LBwnkm zL_g5;(ia>{8=dPN;*zcBZ>s!mZAlrjypIJ>--Ver4;)87Yeby zCkzqoWT02H zV04>DslS=G%pnC{L8HY*dmM{FQvC0_FLq^EQHW&)XRPLSMPYA|Qi+bQaBfsA1G zS6@i1HUI8gn)>&$`5bDKdmw$_#ixzT!F`9UQcpY_$W%;m8%+#W-#RH`6T%w7ZSac{ zWm)ukGq~>P4?)td{Pc0Ev!D6E2&F(I=$%G&#KC zDt~Z7q_znO3ZA2ZzsspO-%0Si$(x_gAHaRdp>e3!HXy%tkHUquDfWUIAXz^uK*@(Z zz*B@}HSpwdF?{!zFhuHmcj7>}dq+MtjB0lF-lJm%>z7lNu1A6DHwd*@e&VMQ5Sv{N0a?qDys=i>NZo zOW45n468uD(D9~^5n`&d2+}P%hwGxY3toTauUnU?S;{Q7wYXMxXinBQ*)-qtJD(_$ zJ7~wnL+(q{D%4Ssq$J|qnQZPeQeQ2hOx%BOz1hyM{mBNC{4e#v8=nmve0wGGW%BcOp@dKmds?ue#}05m;_nm^awMw+rXm;-!w zVfCH4n2Ybv#OV238Ok!)HnaV2f<$EwV#C3GFJdUKaq-m_Hvbsw$($~lCow+up72tM zQMKANbOl-F|NRtJKW4-4x>Ra@Wy9lTvcq;PyX z@4A>4)1avgv;3^-Y6*~|uaKC%9sSoO66Nk~1cF&PaE2Ad^_+Z)gGla`l|;0Dmk@2L zpqqHwEli6xB$yT|Y$d6XiMnK6H`R>u+P2m^)RoXurr1t*`EOcsi?$x&JbMZl7Dvqv z2MNQQIIbjw7bDTbNK$dD^Fe!2g3fvM#}9$!^+ec2gWnq`=t)3(zh*9*2BCEA4YmB~ z1*()M6b~PAZVnc4yY}HA-u@)EQ7H|+kzd(;C_~JhvFCkc)}b{=wgV0J{q0UXIv6oO z6qfmIyY2sZWYizKX2vbuUkH6~#+$kI;-i`Ir=j({W0yd?9u<@+0`U%*W}H|UzI+ZF z+ZuH5v6@=81uw%ybeK2-d_dY;ekY-G6%3lwM=;Ol1h(T7>C`q}(||F9q_Y7BY$K%{ zECARrR*D%&jq`Xndj0q7HO}LDw30^{Y=owN^2?oID36{+f&Ll@GdhXB&U-3j2Ph4CBm2{kkGOw~*j*yl{vHDd% za^#%O_&f;@|J@RyXAQwJLcqh@Es;CAYT@`%8i9@?)kw^*F+l$hdDgxa4Df43eIs#c3DI* z-v&LK=f#izL)ANQ2Nq>ryKz#nZQHhO+qP}nb}C85wr$&XQn7tg{f#^N?ei1P*lREB zx#k1)&T(iFM_{b*DU`26KHZ~SG)l=c8Ylf_avBe$VKhs(FioCtnskBi(V1$;I=4f= z#t(r8|xZaP+oB=g~s#;C{Y>Zp6341qd;nFQ$hWe;U}7<_g5JZ0%NhK z_@5BiX$+B5pO?T+Hz1_J@}%^RwfChXzgIiU%jZ7?$Zh4-z3dtx&goO>;pv-r){^~* z7M2fB1QlF{CI*12*|bwAMt4<6gthe6_DzxW`4ReoF7j~+M=Z+E$&=muWW;-W84JB3 zy#t*@gt1lw5CTN?q8}%h%y(L66fLfvDjTCfKJ+v`SaTUOf9VwfK^Wm5zIvwrED{3H zW!Gwp^ji|3|CyIq1hBM~!jvC{$3wjXzfM7Zoog#ZBV8#}!b(3n1xQ5h>k~p=XIMM_ zHphxGci4_ruEp*k25{5AJ=D+n!};h|Y!ZjZI65swW!ydWO%!ToS~jzi7lr#JTbztS z+agCMD6;XlLiNGA$Gb`()$Afz1pUZfSU`NlL46d=wb|GV=VUZLXAEigcRjF240}U! z9y1p}izyQ)zf|RN#4OZOxG!z1CMb%fs50^5WBrCjfw03Dz2eHRe2$iq60+@BS%&{S z;Vp>z4#@$*bKV7K-p)^iSdgxI&Eru^ksq|_a%39y0z);ij3BL}2(_`I(4WrA9)C=h=5j?m3!oVp z+%VialjX63$X8M)p*^;I7R`|$8))?Nzvvav8WHolYqp2=U!od-$ruKXUDlovu zA$TYqo97o%k8TuR0e2&Z3HsM&;(=E75{WP7YGn>s;aj5CV*!(U0Z81;^p;L^Q&D@1 zJtG2uf*W5QW8+U6(ksM~QcSrC@3gH?N^Ap7!J7iUjO1uWss{)}3({&6t>8`^%IST~m$A`p zXiEXQ^Lz?phan6hcyIG@^2R&0Js9a(0WcNLb-4#WP5_Q8KN?Ha=+j~<_W(rWn`yVs z7_3@YvUGLBEQJnWX*v7t!nMcmb%03wM+dh<0N&;l{zv|)T~Ls(AUUN6(3?v7*q0CE z7NRBOgfqNeLRP+5mkkMiCj7$J2LR7DWBW`v@h`Vb^zY@r{C&}?HrHTJC`vQ+wXs;KimQcFQtbB?=6wFVf>rM0G(tzeh+?4#95Qn z`*b|9cF~h%TAU{z$kxO!*nAD)Oec%h8a{>Z5T4}Wy>@Y21-X4atoSuDt`g4~WuPO- zmeJgHTc=jHR5mMX$@73=5+i zRinNtS~HV; zP)cMetN32_O|R+@&DI?*Xt*nUM9y{~rvh^b2-87>+(* zcTQKEUjBJ+*G%(T#(U&?rprrbff(2`kL53E^nN)30<(DN|1k)@=Is@{u(R{InxUOl zARaAwx%E^oK)*S%#}?w6cPI7IX(OFTU>-O&usIFrysP0fP4Io}CXMI`K)&_avRe@9lUYDsL-gTR!y-|(>X7^21I+at~ zU%_eXiJFt>?S~K@6|hCRD!=_4@!4A}CK&3m|$J_yQdeU^OqQKQ)D496s9ILQT^KZwof>$Zg zr3p{cSC4h^BT5v>-P@eqVal?xE}mEG0hf5ztH-{{ia+{~)1 zx?Jzd*bwm%a|fA+L7c9jkvG!sGAV}KQXFjVCx#)9Qykke+%5nL zl}7X2cf0#f^^yAz68e9yC=9Bh;?j@OQQvARMfTI2UYjb0eUMl*;x}tWqi5pZEjctF zzJ*ik4@3fx_?+k33)d6pey|{9;~I1M!I+~M3M&V+PwwIM(Q0Z4(3GD_`;^%Fb(8us z?-*9jW->Ob_}DYWoC2?@`7Rc4D(0P^4A2@TEf>=y_0JjVVkHwy$q>=WHLTJql||WN z=YMj+9hs>Y?eOGb2M~D6nbu8CHY7jpXzy`7mk^!?@8Ni6)hh#voCnOEt0`R~&@XW+ zxu3Y-=)%3c7opJE+!MUNE%g}cw9xc>YN%VkNDgQn2sUdIwG%*kyH`*y^ua3ho;ljw zw#RVE+O@JwKDdeVgz8IvEIxnQPa~U~UljbOXmvO0;cmlhrcQxWtvvJ)ANKxn;|igV ztH=~fBfGjNSDhb!e7qg~II%Rl)1;HJDw`9(-^0O{GVrZC@PeSI!e5fja{ZdcR zRdazFF0+7)36F`uMX5b%Zw=wc&nheSzWoUI%j&7R&0N6)byS0nz3DEURX z`1RwtkWwVy|KRL2NNsOK9jf#ANR!pH4EU)8y?F0c1PsQ5o2c`*rMC{HP@K=*WR0}z zrmLDrwk{#a08O|(cwUpjG1($fWuVmkM&C ziCXuk<9;8FY&);;kF^DB8tMlqhA0@oo(`l~X=oh^plB+9;J{l8RklayX>gvXvwz@$ zt9aEGKUIwLG##C|Qf((G79aO&eP-y}E-~YA`CJI@!2Q~tXDJ(Tm4T}s)}FN!Rk=*F zf44j}pa${}3AU>h z5o!KlVEAoDu%o``BRT&!`))`Ar;3&vYYvS=|1{S4B}v&ozV`jQtcM%5!oI%Z8(!Rc zjFH3tY|Y`qYt_@PMY;a!kB!af2ZXN2AIwoujOPL@z$oS)D>cRcVnUvJLy5Nt|0I z(1lHzp(!UVIgmj0q%W5S2-vvH4(Nx(AMaX+ zHdP!vA=%)mRh4f10-anyB}vui7$ls@yuT`{@I%IuLE6j? z&mjlxT`J4NNhIn&z9`NTnL}+}wvk~1B2`pTsv&g0WVS+$s;Y*#`<|s|D>H=&jTtJ) zsftd(EG1`C4h)Kr=%>1|Y|@5b?kc9md6ic~I)2C5i`pB^Cj@qOgfv5zKO-?&7YmU7 z$#4dW{c1TshZ|<*cZY_PGlT^P>sJkj=V{9hP^T_7_>q#)rbPgwgU$3MiI2E!Bg03Jh4RhDR?DOY|xAYbLcAh zK7f(h^e=gSx%dJ6b}D{t=>i0KCovs8HeVnV8m7;y z>x((-;l(561^{=uro#i(rjmlHd(D{TH5=-d3F`AUk>XsqTqz87WjVpKxcB*rwr_h1Bj-aAb0&$`(O=2S#yEbk5(j8;e zEEfzK=EVwHZWQbLYYJE&G-&TF&=7&h?un3sc`&(uiYIWkFRKg2${mMezm6!Dkg=pw zByUkYZSNET5forG5S$l|O*V#KaLoyA-ySo5#=2%=Rhb;LlQosHVB8-!s}tFu(CFA` z5+#ISZG{T@Q`G+X2R!{36@UQ#KftNEqmZeLyDhLaZ>3p87Y9DhRqi8T6 zt>VD8Jxd&+wMMeLQ1dQ2iVqJqdf~=n4}Be6`I8lW+~0_=r_k|>x5otX@1yU%ys@|X zr#Sn(QgTS&-Gs}^ab`N!f$!8v&!Q7^cq9rPg!QqjA;QVC@9<&IZYu!_Lf4=&Yk2mr zXGP-`#lJz=HExLB$8OwW0@k|6Ts{Yc=@T&H!1%2Ph_v6D&HBr<_G+1f)?}DMb9a2* z=K=jGx)1Pe3Z)s z_$KM&TN>l#A&z=CIKwZ55Pg#EK-1F8TAs%)AB=noYD8&3807OI?2uT_3+|qAZKl1f zIPoG0xCT8G27%(AR-5$dg${I_($`&2wx=V;$CV@l0SuHj2yAIfm(2#%_K7rV##@3! znpy>b5@3u2CbBe3#`~LoztS7gV$K5x7f%PEi)`C!*dT-w}-$SjD3tkN_tS~Kw(XtP|ECu zxQfU)4t=ylBN8r$a;fvW<&AGve>#~Xhiews6YT4?v*R8lYn9{1+Ywh8f zY4qktV2=xhu16!Wkj>0EQHQ{S{uivnN^5tKJphhG45 zNn7DB%AXlRKP3`RgKbKv-gf~|ey~eZKi0CUrJYnq{+#0Qjl<9Wm=uA(uf-{tJv~X2 zuL{Y>&~wj~qd>5$_R_aRj0+lYzJi=jblNRjo=yrfusvU2z^t`+TCC(bYEO(hnefe? zqhOGD8t6CG9G{X;qTS{Dlm^58T-YM*Y-u$u{)me_|5D{NubPzsB+6`dadF?Gz9*PDC?9ijOsX4PPbXuN$wCJ zU2BTZfWG-qO&;K-g??#jYMZk*YNHlO`QBkgOY<;E=GdvmyAKj^IHNO0pk_bUiorEn21_VrlNzu0a2#<*|760WPY?uzp+ zZ`yd3yBaS840SeAPKpY1o(z*Q%EK~k?OXiyu&h>g7=k>#B7eMxg!DJyDF@CzD{BLZ%0!Ja zRbPz7d#b|p$b&})pB@BXzs-N{{`~Ah8$fXcXno~M?^WIJh1du&n&!LcMMV$*a4zQJ zLtg@foN&yLo8KN;WUk~lgAzAAD_piL=ot>5vR)dF(Str`D}+xAiDhdd5&ZYn>ZecZ z@Jl?2G!>mwI?A66LGkn=rILn3yC?^ACFK^sORjIB2lrzl$KjUJw6ei?pfunb^h`yy z8hhk(a(#L>GC>-eyBIHDQ39Si4D@48r5z4hL|VzU)*$C*{ZCwq8`q7pPo9ZUd;eGw zBN8kQ=mJdaK}u9}@-d3MFt&KFD>voXDNV{x&V&bxFam@D3)zH2P1!c`?z0$lFH z9YFJ52jAdd13Wg;6b~)~Iqw8{Pba2&?|mO*E@Z4V zL~Kg}pwE_AO{8U-_ax5Q64Q`~aRxlMT%9>|q7V^oC2ZHDF=iDkP^Wx7XPX;r%g&}W z&#FpldcfPmE)$ngqyVwgvK^>Bd|eg>Z?PqNEF1M z)+uS+dmh&|LNlxFKOQ9V7nvI87X+4Kh!OUlp;L@tWQ<(MAo4sD@DGPDHUzEfGHpA zg|ZO;GeDAH=TvotRV#IzlX)$lm?8~`A0^f8*~bY3)1NaK5E7D=)w+vTWiidtHa;PX zx>=Zn72p~o7kVxT9}|-b-Jtdq>Opl}blYPl#d_6o9iPDoCoe29(W-{H@vO8<$UWNt z>Ym%^dK#9VW}!=Wc5_y`e@`F`}ZYJEvHM6e=JIn-)EjYuDzwTU2KR8D1$q4e&QXT#vizB4k2E^-ut z9Tv~p6F~24q9t~s4qHxQCVZ|2xMj7PbX+^QxPLK)7QAp!f!r#xX3Jy>^5WSBqpH_# zQYJyd8$xL}aQk$j`H)hu*Sbl!pt^d@7dDU|1hyyqmcp49ULqI$g^xf53+SrzG{v}k zQR^lGZzWhdjPMfE3vMtAgI2J%Wz5EE9w{2@XL&gHLXN{8GW(;ytygn}>b$0SOvr>p zn%ov$6BX%xKJ*iVK~4~sg`Y76h+O+Wv}%-}$vc1UPk%NDkQN-Rm|Fgu3%-n83{br* zLUl(~jo?lZ!~xeB-|F=7>2IWq%K`@R6;rfBvN4FIP_%akBca`gIhlNxG&DN9kS?PP zBz90;%o;dGBujh=rl^c#1aunAFA3O;6m5`2?Oj8EM9)QAN7s`tB^WVfLjgI@>up<} zat~}t64>1j#)K&P_Z|PkzsKFVp1r7yhmiOkJCM%ZD`Y&6tG1|JBSHwgaNW^_AcD;p2NU0e74*MH=JOh9ZF*6ug6 ze4(&%6jue8Jb~)%Ys6vjQLEvU2HC)N@jT%M;)MR7Hq)hnpFJ8 z_IkSAiyJnI#qN#4f@+O@ss#MDlBqenV*Gz(y{i93b^jY`=h192GOIUW4f^{3l=J2P zklp{MoR2#Se7gA=f4DRpr*+djbn`p*xyoN{LOt^*FHyh(!LM~caiE9>gCrY%01)jib3 zE&C^TslDLE)Qej(RDic)g4S79ET(eGx#za_&D=S9%heiQZsUkG1_fh^yzP;olC>V& z`7S@T=b$@3Ee8vOHjYA|YiAXrNp<))C|VO8eI`j9aKc;sW*XnqW>=b`wi}c`Iu-ck z`;tqIRsotrx7B@pmJZMnW&eXJ?*Q<;UIsgjH1Y&*gLHNtu`LN|glx;oPQdRg{!Fq} z)D65MD$y*pKbq1Uy_lz<1So1v76;3sDLjoOh&LJ5!|yqW4WbxG3njU zFr#7|#Wt*x9mdn(_o5?3_cX9zMMlkzNbtRtE?>hw*mnlhG!gfmsr?#U`{cT)UClR; zX-SwP&)f#v&X_E^Pfy5P>+cK=te)=dT8~0$zJg902t#pITw@1<=lr%*kgbtE1 zEW6=_+D+v#eI=L@$c5jZ6;M{OfiI!xr#${pL>j!hMZUBhJ=c3|qDr$Aa`51;TZdI{ zYrVCznie1)LM7CqtwndNIV-V*#)HYRPUy{JSZK8h_?~*Wo3+(IMSmGJGM(v*B&50) z<{PC>Va31ur!FC!t-0WKyWnY=6=efpCmxyxrdELOgGVw~V!oBk!OVuVbR=T{XXUW< z#a0R<-&E3RwXfo0?Ux(MvS>zHL48_t_;jIUwAQwwR$VCXy#K5|qeno6^(_-<({7s9 zQlkB3#(NO3%~@)@Ska#(4kr0k5vjGS3`!S5VJSQ!oF4Ge?e^N6n?3KD5Yq~OS>r!i zh;x5$GQJK5K^)l98he@Ou@B4<8tnT!v=`-_Cq9)H-!92umlj{-O6BVkA$^L-E-vrvrso3I63lC! zth~&61MfPG*#3o(H~dg?mFEjqjcwu-E;X(yh;6zv@6`c}nDo{E zkmdhpCHq9>V`~bR52{=JIO^JHrPMW@cp{mB^|piwU;Vj<|mZIoZM0t{9?` zTh@BL(An|4v-~M3g<%(CLtKLv{5^$p;Guj|UI|lz4i8#6gH|c8h>F~=K{*ROceb|n zu#yZH*s2fYLND8W$hFMYL?>A^j00z<>V0HAF{=cP+8d_MDx2Pr?l;SW2)M+yVrT*+ za*S|}<+B|pBkHmp!U(X@LF~>l0@xM6XIhuE3}ITmVdc2UnPin#4D4G?D6kR=*_ z_@zr8%{MW|qVph74tJrZ#6k>#xDmDWo6=!)>@T+AUbFJfogHiyf7%72xJk$?ga55tUgDI-yCdD$kvbi~!3wm71mivx&ez(jzuF3Ee*C z$$yN~6}Bxo>bF@EQBbV62G#8hGGD8B*=f$@Q!C8r0Hfr3Fo(Sd>>~(l4Usc~DZAUi z>;7GP{aM@<`9@h!mD?uoe8iEWG7j1G#J4EFHmfDo=)Z4zI-jYYm=8>X|FiUOpLPLP z#cy1JVY-zXw{q(0%w>5%LeWn|wLm+yaZ9~?7Ul=I(hMFnb~Bs!d zVWU@U_YpK)kEncuTh31q4^A3!(#5)El)nc!510*zFU?n2E1A^$5R%$ozr`?k&y$>j z<9P7`o&q@H(B;4q%d`EnYrOi=P237!zs#y3TrE$k?@4F62_ThuZ`&y2BnQ$&N%v0V zgQbC09$sxN$;jd72r8e~94%>9mB{vp>5{*>I_&TXN=)q9aK~6SbfaXVW|xX)q^~rv zx@>ebKuwaH+k63rAfTBl1*(p*Hft&atw%Zx@^N*Od^Pw9hv->{t%qm;+;PHDJ{mPH zv0bFs5um&=W`>JzPcuk5MNCKIyJgct4JbDIMS2twxVhW~lOX z9kpZh+Tg4jZ1ZotXT{l3W4+SyfS(sy&Hu%wmu}x>q}Kc8z@#{zfAU#CN#!++By1`I&ie^@qKiBU4X0KKOCh+=0chpoAiV0~H>! zHXNvh2#?c5V4)qQKTKz(_-RgtWH>H zbyRdmB`E!cHh8a?AIto&`@-^hV(!CAi975*%tR@*Yi?Kh2CO;VWYe(MxUpOksuwb{ ztij*#cTt^f#zFY?c{uTjf#mI1$Mc0{jx=+2mLwrGE(c-hO)1ZsGTI8emH(daH0FZF1jX4prLQ z8m>I%FA={*%))E_f{XQ23b(!$t36knuW%opTo+{wHG1eF38k9b?H(QZvBLvW*X30w z>h!UwXTAEVb+JGQ(+5-9IBx9=gl25?1coO7fzUU7iN2RrJzeuD#>xk*jj~!+a zylGnU&_#>}i_4`gIVQnufo)%z{PH$)6tfiFt_;ZbJPmj7gh4pwMDIs_-24yV{(n*|&>eW*4BAbRxS%<>Xhq% zd_Mrgwk{r-?kJ#s9t^}eyKZGi9Y8}Xx`M^fBI8lBZ93y5Om1?>!EtYqy+{jb7<7{#%fyCm;+Hpo#<1;LI7J4uUVEw1TB(mz z;7!tRXBA;-(H=rRt^E{K9zu+I(HR|;PsU41!S(o{q2E6)Vq%PgNChjCnyN^YK|M9G zPIH-u247szYj3d-6vWe7y8UYj?~0jD!a;mMJ%_)_Wkq6~wI%<=Jz4%kylWYS>tDT| zyG7gDsl_N$0bR&LL^x}Dm`;!4ImVap8ofNH=AqF&j_Pcv%qGEP?3fpcDqdzR$i@{r z={i}~h_8s`LKfNyC$O&=?=T>?3VfyXG=cmvhW4M>@cn6iZ=z0QT*(a&ghUaewa{_h z>^L9Dxe${^T34*zZ61&s7zE}|j(ORfcUzMI_*o~Kc~3SGe3T3#KPitL8wtznu9p^a z>*7h2g`Iva_1O1%6$Z7wuysK-PBA(Xl1rROE--=O6P_^loa|$-VfiIiUQsyU#Bk&( zaPra}sC10?9zEb-vVGWWvl<1ycd-G7CpR_E3<&CGyc-Lx*>CmN2sFMFessHnK#E2E z$47fLWQ zt&XEQt{;kFk@hw`_29|)B{hf`OwR>^c70?l_G^zD|6#L$S2`%OYwi=`&-tr@rbx+& z0E%f{*fILK3)YnY`gk*!I!^@sKK&i+vz0xevQ9(Swx3D&L8Tko(M0h13y=^nr<>G{#+$w#$@q<9t$ ztyv1D+}Z7OZx{BY=!IT%KmOOVGil$a@M)nfTc6H&1fjqP%6aWtn@4lxQZKs+uNurbN>J@l*9Y9Ygw~H)2B7=G0&f2_*? zD+2_W;DcDJ9o+qqI%!jYiNelmY;F+HGt(_{Bu_*IPjHL2|0HDQ`P~ zNUjE3xDdPO!?JIr)H9jQv&7?Ng_JuRqh^yJn>kYYt5IPEo#8bG-jTC*`jY+;kC|X; zK8=ttbA4X+haiF562b*DRYoA z<`MBnjZ7~bk`r(!cbIU%39p!LJ$ClIL5P($pO0-2svLv9N@P8`9%* zG|+*sY0*0BFU-JyMT0U#E_eipSeij~p*DnHf*)v`y$~!zwiTW(vuwJ@IXS(qI_6JK zG|n_lQB6|M_RVUQH#}Q*_5TWmD%b~ry}<{z>Y5jrS}Y=9AypRmgJBfFarN5Lut ze#D2_&ML>ELCK4eGG!rht0Z8^q$eKWdquMNT_5h^u#}zvE0{CgcTWDh21oYA?i2@8 zZAEZ`MxF%UIiF@b9%(|zu5vzXy3f*U7dN0RH_d3BrEq*3oVv+41R}1lDCRFXUejJ_ zaqeVHbMn`#EpCrN?9faRg47{v?V%-20u?ReMoPcNaYA<7%HPP$Uw=kwU1$9a)_pCM z%I}JnPBdRXVja`n(EC=)e_{kyeheF|q(h|8J)X0X0}lwgL=`B*T%8Y^$M@0xg^qGuMuP*45Og5;V>HL_F)-iLXYQN4~JquLsi+G7<(B zjUI41swdn+Dp;|xayf|Csr+P!Obvd3N`f*oM+>I&;)o}34Ze5IE_%?+xKX%8-zo-T zeYNyfW7_pXE3IZC-FL$|;~HJa%Q1XAJ{0~Ql>|#;JNnpjmWKBAS2Kw^jA$}4x#eBg zEAIw0UUK2vSxl2$Er;>@?4RgZ{ZL8`XoN=#+ghSa6XVYqi!9ncmD^TF17U~eLmxt{ zR=aasFz+~pF}X%B{7FersZ6IMgFB4Sor<%fMYqIkY4@p9+Cx(DDTYAb+%SkM)2K0^GIsBG@Z-JM6&=8xuej25Cd^>*f2gtji3{=;^~- zMAW{Om|6?BVOJQ`UBC)JPxJgn_R@taC(03?0{#F@YIhE_!vhkahl3Cy0UBk~T zPcy{1wmRAY|Fn+A1mZfue?kx8H2a?y^I$Ecl0Ha7cPRIhyRq_=O1Lvoi*@}7p^ zVcR8D$m%c2lrFW3Gs33=3K6$zlCdmIdF$$T#<6!_AkK+|GvwEwyTjc4QcAZd9Cfuv08O8YwlKE8?(SPSnobXqB`NQIq!KDS@Wzbifjf8ZIdy8T$9!DkxH>;}0=G2G34<*T)xC5tU>$)s zM=27mrzdSB-ifQ2b3lbQzOle0@odo9CcT3tZ{h$`YkCR!h zSMJh)${P_a61fLanq7sa3sg-Ngc0xbQ`lqpW)VH>3oC?cEVmq$H&Niu;#eU6^sd<< zFcpkQN@~lF3 zo8{vkptR_3a9wP#4+)&*x-oC-L9LRpM)s+f1|>a3&QJ~eFQ1J=hC;`pz27NFwoLWB zxykQBzYK`S8iN^i7n@m`9BHR&84|T(#Lg=duWfop2?+3xAGz)6Bawib$i~W3R|kQ` z0}Di>Vj6Lfm0y>87j+fe=z z5b|}`L-kf6urpXN)YIBpL<`?zwAZ?hOYk*Ob74a5!LQ4E+Im9Vz=@=oxUv^-i*pDW zAotxx&1O%r1S$|b7lo-qh1Rc_y3Iq{`LFlhW8MxJrpscihE%$LFDOPD@H9e)i}Nc@ zB%=3g0ecVavlf&%CwIO=mcQfAVBaN2f9XY-+puo;9}Tj%VJ9w3!4l+p#cy;UU}eG% zyK5X|91-XSXB>B?6JKFs^$O-EjB90xGN?-F!&mLjJD^z{Z$Sef(1isS9F7Od`**`V z#Oz6RLup_9E_9*@nCT(-hB8t}F|Gh5kHC!cGD5Gr;G+*~d<(Kev){|v=1Cw1T9E%!nRPe_|mH;yy?;rq@m0N&xMdb1sU`GkeA}Yyn$Ewl5BBH z7H4*P7u6ODshB>FuKsz)TRc_jIefB-{Y}jw?n(BBWL5w!nGdQ@ewgMEi@i57eNMN3 zjEdx%TTP@#gYegp6%#Q1r(-3-;Yop!A8A`i5qFEKT^I7xb~5;W@B*|5yKx7ivgSY; z!LH8-ysA zPQ5vS8B7y|tiGAiWp|WGE7bR`J~hbidY&Vi(N^MMZzYNuAmru+LM$GC_~N^*l$}J4 zY*BGMW%jlde1aM=@!(Sm*9w{|s&qX&Fhp?dK+BU2ahG?f%Su|w_ zErk8fj$<7(>1gudHfEkR2grB?N^T7h7=hn~){8732nN*)aNp}6bOW$mIt)BJS~L9M zA=tq$TmUHiF5HHq(K5wkUG)Bn%6o2)O=kJagH+2k>8(t6-g7E;?S!C)xF;gL@Pef# z4b6vuNfGbN=tJovc;Dp}hF-pfb?P?MEVL)UG;8fHXO9pmiQ?cZJh-2F1XL%K)qpQO zo3-Qc^%buu^lnL-H6~?8BL1v_ZJV;G9r$m#=w_BMlw(=xjSnDMl25dD<3R;Jq&i&E z=L>VD6hPJFM2o?% zg6G624C?AYP*p$6I`f)TPYA_~F*!JxOu}w^-O9zXlrYt~I z&x_KHhyHTP$Ad_R^Dog`1@7q+*YV5`n7C|~_1~qHEthV)c0HwyRs0G(4LWC!W`(6q zd;0;~Cr6%h3UkEE$+_%9vFojp{BL@Jm&Hgtc?g(7tTUr@&6@VB6j*IGfql5g%5H^T zQmmKKl{tgRYs}Z<4Wm~BEY>qSb%{aI7|m|ZfJlo`>tQG9NUH1Q&;SpIB8(#mN*n~& zDGPQQFrWxT&4~cBu9fskU_$UXZD*AVq%E@eDutRUTb=y}n!C9`?;!3#evKnn$=zbc zXUXzjh)c74_N!1*+AS|_U&?M&r3adFi>I|a z+&+7;F@Nbt*Im$S%dPT1EU{kNfk(8e#Z?U5EQIEdH#>v{F2pqcbtq(F-YzQGUk+5# zC!Oj+$PH=5A~g2D&tk`M^aBN}RHL*Jq_eSIx03bNk&aqxRLLsJzwoC(Du{B3Ai0AR z*@uKWwp$D>dZxgrnY_=Q-wH~wQI6Nc&1hTJLwQ)qo)ag)s_P$Zbfe&SPua^TMHLyt z_ zS7I3B53Ie_s)Q2*P|1I0qT~KxM*lH&{eRh~lJL+yxBzI5{YMqP$7|kFRdZ$LulNw` zz9B;P5UJXhd`>GqiGSk#e8ndm+7KE^gk*!12Cu|taL~8WerrfR@c8+oqw^Sd;&TtX z2Ot7Z7J_PB+Ze?}RqX)Omg1$x$Amj(Fk znMkI!Q%wDiamS9fvZADp+hSM`Do2JAHa$*9;H8Ik`4>J;OXfZiMNT%-C z*Ivz@(2ELcbT#>jv+DTv%R5J1CF7N0_(^D7EbERjU}4fDp*pzRhb#T0xa2mW;JzoR z4gtTTG5o&q+!dBf*L1zhtW#2~gd0#dN{IEUe8@1}3=r&9M(0l4=)OvOH_(&E&jVkJ zzJLPH;^%q;o&v~=7qr5|`N+J2JagtaMVf_ky+8z1Q*3>c{ZmNg7wp5!Ym7Y%iPd%4 z?7?>a4zuog_Y`aA=xfWRI4$8)GCbX=94@_7iqUjfm7;VDS^o6{7w8iH8M|_ekiFHei)0}JAcf1 zZ!tK>;X3x9%3Xxt$(xKVaQ4oVP)wf~`(d;sQ{~}LTbhwrWuXp^0FSciOke>h4JI=R zc*)LLo;i%j{b=d%{S{?#$`FivKKpsWiRbV`fv2-1UIS7Pad)5DxcXYYoBRWGypcc8 zH>)37hR9k@DT>XAD60BuL78&wotol{v=ye!$<|qlE;kH>C3;3N*||$8P=-620RnUO zXw7xyp`Iyg--6lCxJJaNgH*y=P_1d;De>ke+y2_7Q}H_U~r4_h>d zVa_+LoE+l_$tpmVHcykE;vCp{>k&s_jw(sLpmCfAF*Q%y`t>53kS`9*q6C7? zn(h9*NX2eiK~gF_5r;N1XS~Ql%!*8GWTs$Px3mYkN}K6p*dZgVX>>8$MtSR`>990@ z>VWHK4*@Xat50VZcNVKY(KfW5aqTBE>$7fQ9Z=rBW#b9r!Klw_hq>cYWzjtyt+r?d z7NSi0_%zRmAG%A{_Vjw8zWda@JJhs#e^cc#Psf#4RZvgQB!=Jd^GwC`X#zYm?gRa^ z?PPqyO^Cj{+7xD$0$Oz@!`Zk~S$5XIp(ZAA(hrVf<@&%7gIB-MR|6I9y+!zCC85?m zD8D(n2mquWmhrYh{WtbyW%45^^=ihqpDD}|nCkY_UtzMc`2J8f@`iT~gO`Q7)Rd>+ zrk;EqU@q|uG=_VU6>D$NhmCYB>l7pboe2Vol+AP|5U!!cfbK9oQ@fRAlww7zk4R`@ zZqjhmdA^oE$vdwpr|bi8bygbI(hoj>UoueW7K#r0v{=pcKV_3VB53d&nL(rePN>zow91#bx^8_ML(Q-YG=+{8m7RY;EglqavKHGXeS=&qef(U(I6@@+;n!=? z!|G0)MkIM(Iz1K`T>Xh7VNI(y@vZ=WWf;Yz%QBkqQ5~@usNi?i^?bJblv3f<3(~Bh zRe+p6lsvQFQfSe@)mfCF0hQYY!M{C5%H`dQWu{IZZK`f6w6XVJrkB)jLJxS11u+b$ z??ZUFVe9VzDM;=LK-ISHv=z168F?8b^&tn+{WD!t zO2)<{-)-slPXfI;)N8P&=CQAy6>_5HP)nMcx*LaXr^XCc<5?{YZJM$WQ4cTo3DE}p z%JQC>=dNMFIEoC$l`Hfm!Q{UI-%L%>--5-EE_&Q6$+>>V>&-Kfr57$#I#!jZ{j1g1 zC_M1Ds1`J@G0Nb+EF*lSlN|ffAt;EVM7EMy?D#_sH|7#Xg6n|gk|o3m{9EL)OJ)6- zosy!XeO&zK@BioHOC_n}p1@T5N)WExc*wrMDWLp$Wk%?<;Q$#27RM9XdjMG-{dt7S0P$+8yidc!D~B`ZQHgz$>#n2 zcdy+&ANpfo-KV?isj9BJD_=ORqsSJ^&I|$)uvxxyoiFo)w|qqOu#!@6b@n^x1G381 znHmS(neeYZlJn2u4kfWl=`Euc-j>FOp{KQyZEC1t8ZCBoS=sl{yN?Yq!Xhq|4W!1#)o)raql z`c1HO?U!|+@kjle_i#!AA==ETeZw8iOa*dP5(7^VnSGIJOpnz&->n_VdqhROx0>bh z7B(cKd}4t3-eZ*MiL@f zKXZc4K(rEg1FqKm`^_+P6~g-4t~WB-8wIU8;UvStL5E9v@D~L?C@bD;YFFcc!?}d0 z6%#&%B?*MIBrn0wyWsyHJTCMtw%jR~7!-XHcv_5bHznA1Bq@g4NY z{!2pz)|6(~6|#Vx?pe~z9B`)Y){HmC#iY2JslpS0kTV8edW2BdiYN@wFjRseAwO-2 zFSEazLvnEeJ=zP>g1J%05#_r>KE60F=4w<+q{~Np{~i^!Bt297ukvbHo}kZJC+h^_U}TcPz=fHx5#@-J#$dI zT`K11PvtsCRQOfC3vBt;D^eHk-=6JGG(_rs4REPe2+580S|#1>e^2)nSwC$LJSZ9T zr*}hSmn)o%=CP_qL!9H}F~1++d(OR&l-&23!#b|FKy>4V13xI|693E`Q&n5IO~q)X zx@gztE1>szk*!<>sbTCY>q1IuegN?kSaBd-2$&F=@?#Z%>dI;L0y1x#vKvCHhxib8 zemL4Y1;weR4vY)}f(8Ph9k0F*%8vWV^9ABZ{**6Cbd?kC-A%BWz<}>NQT_`} z^cF91MGEnFU#59AP}X}9Bk}t8_y*5iL0-`Jw=HemN?`)&0_eU)n`Jd~2XVPyuB2IR zH^C;_?y`sQNAkR8WXN4FR?aFe(LI-TK=kpqXu^LtycXVzllm|YH3|45+(eZ@BNk6a z-%dfn8Q7UrSjP#it=bw7Bndf?5TU;-@iLpKbzF}GU5LM1xCa;G^Is8`4VH+%^uYd7 zXy0GfK#K}{%X4ISRe_2Nm@=M5xAexXrJ4#F4SL+`$w?mXp}6{-nnfnlBiWgtNkaCv zLX!?aqYFm5*h|dm98Ll2D7xUVX96tE+t6L6;r{<3$A>y zud`I8ADT;7@$c{?O9fM*(Ek#k@83F^<9>-x(A3 zqyGee0+{X<_#Avzb257!KxncF*c9%`aPr?-heS5Wt_E2)ImSDPA~H9go8cs_NsUUc zCm`AwV*69Y>rW>nyUNNdZC%@0Kd01J7!AL-uqEs<_8t;0jIGJSF8lorS-u#3I21}* z6j|B?Zvr6}shpf<*wx@0ml?FuT+(uiY}pfOzL3N8guNOtphyRFpx9<-@5tY?o-G+8 ztAehc0*={)vVoAgvyUa;`zCiQES$`H_yu(uL_qWWx^0+j|4~X!`@fsYI+v2DMR*BSo_DXGO$^_;qrLJ+EqOLpa=fdG%xt7yX`Q`u1k?wZq6JZRH!* ze6@{7wZj>L=eM+h>d3?YYawQ2;uI&f}`EteKE@eR=D^@!<7VPR}D9}XGjVU)eWd1|S> zo-p9BOCdl_v4 zR+a#s|EQOrrU!C6v*Y*6hL&|)A#|O3i^tpr*ceeKh94<2Npoxy1?kyS%Y)#)df)Me?WyX4>>9Z~4hf66a9?aHY4!lR4c&hDEl)0z;->B-h*4 zese2Yr7~vg-5kg3nf`FfDY%WiXZWBb1)V;lH_GyIkh!h;0&iGUry~frDAFB!r z<(vXx)b@aI7$YJCsul$(q^|<}lV|^$h_fU92n(*rcBcn(-?_O{i+QLCA!zeB-Y6iD zx67LGG*E5*iZy<$rJMrHbpA4KQe9Hzh@woD_Eq);ri@cBQhZl*HrG@mlq-GeVZmP| zLVO?zkd-d{7WMD|DK-RiC?dy#WR&FN8deGiNZgFGw@+;R9})y-Lq+eIrL|Iq{u-~NH89ZKhQLIT7Mk{539uz-(cUvPpoj3>E=p&aJK>U;B`c5 zgg8M=%f+E_NeSLJhbuHz>->w2ao8)SKl%I(-Q_>Ly*yVh#wQ%bJ__~WTiS1yGFliU z*j;Op&|1o^heAYc^Ns<_pntIQ;=ris&DZ2)IDJdk;OT}B0`x=rg9Ug)o-BR~`^N!S zc{y3Of1eYEZW^*UN|5lMzD>)h@4x$0Oy521FwB-BkyFb ztk=q0`#+Z>ko~HtAs$s|nAVu4!f_95bZSxr?>b&>{rjZRlidLodGX83qupV0a70={ z^y^jbgmE%p+lt&56c~*M0rS66s1@A6f^A8puId_%50_&rbzpnXe zkrJYzb^ZffM6$FVE_jtoC~E<0KkMkaqi|*%Q9>iZt^yi=`TBPz|CWI3P>uxD`< zz~^?On&b86_&thI9ZW;YFsLF=sP{0XgI~x>U%P=E6Sf=q!VxQEA)SYV@%Vu^tW;=i zuST_DGwWxMr_-bV{EeT{{^s)<5+avL;=V57>AwFQW52C&Ur830?7DAC9k32`(XxRW zT)bsV|EYrg-2C?enM~R6D3h^N$eV*`otgUvgTB{gvtAuF4Bz(iqYBqlsjV}IdidCp zs6a*n;E?y{XT_VC5{%+Jc%7}^<|32%^uQS?lt#0JczUtB(+L0B6jZaxM_JA|uu=H! zSh*puL%p+oj_M{Q1@V~qaGDP9_})sbfe5`ml*B_^LI7&qNubTi6gQ3t%O4VPT;(I? zhnzgjS+6W#OqXHSP)SS-FwB~-C+}$h0G#9){)94pOR$B6R1qyB?V_7ep!@SK24+7n zMrQs7;q!007H&Tp+}74T@s}Q&g+9NWTgwZ6N{B--Wf4Sek56k;LZF^szCj?q;qMJb z(yzWU=`tR$83+~A2*C882^Fa9;3v|3E!Q@h{D2ah9(-uldZ!Gx>8$xx4_85_lPAVZ zozzWDsEd4kvk$NcBJLuOtM<`Hcc&EH!;HKOB<9-{KR<-nMpd!?>0tv73K+qgAvIN@ zEYjo0Bxl@EM3hAiU|$qzWBG+?Y*ca9h1mrrVuo!IV1oadC&2$l0n8=a2_|HzM+`SM z@X6_^Z;A#?1U}0MDRyBf^yV0`_V%=pFO`w9X*HX1qn4#4h2-+`vj$LoIz|HHJH5{P zYzSb7OpHe?PsH3J1Dcw#S46*d71E|fI#Xi*0;YsPn#DBul}_VvhQ-l}S4rXOCvF&A z!Lq`>+a=IV6zZ5iDa;a~0?npdP%@2%*>0O0G-ujfw^9I+61pcvm+u%@T_5C6DhbAn z>m=48HE({t?Y&tY4IMQYxZdA$YX4pT&kyKC-wCNR8klPI`KX|0x3EW~%x;v$6JLvj zj}wVX-SQPuF_?(Q9Q&)-I2@5Tj|v6@_0=zp^fjaXioBE77-*9dF6cWbC!P6yQFBJk zuF@$P zHMs1OQP-=VKvO#%JP`a&I=|L$;Me zhG1;484_(aqg5)3-}?jm#F^b|UuwpVj8;Z5ABu-0-H|;mTz~M+AL4*@N#=`lrm%W* zd}Xy(M3+mHV-Sy^&h)=h$MS4IOavczhYc1|er?T$UI(lf@AkJ|Om^uv2|827nup<5 z=Svq0-4OV%8SD5G6!0-)v}1b^ja`j1m=zsf!vH`ENiz{zS)791M!5;D@$LSJup z|Mw^WyLqdTHF4JJEu&j&#;ageYGXVIqxe*9(s+!4x4hy(%yh**4~}5QvhEf}jR%6LRbuhj zLM*H%w*DY^PU|tK1sLg^7OF^1Z%TQO8yp7W&`^8`^)zZ4`gp6ZYHl{x@gyDNdb7`d zr%S#F63m_!_g)u{O}RaW{gbD--&-ux4oNVRLIReE=YdC9B+u297I}D2C}E4j{}aBo zv*e8EjP^i8TF^@c^0Lo*E2DazcEYzkA3&ky;X#YE=v5xzef0VW=L9R)3gW33b*HKMAc zM-`rWgAt-1spB7#>sqt}#hZ8#NS_KcM0q@pFo+=Pe&DFm#0L#tS=aaM4(itrA3ztU z`}JS9`Xqs-?uucF>JJ^A_Uf#`C`wxi!HzRZvW=Y!^u5-9hqs7xb{O8H=_ zAa_ppIo=XJ)dxB~1RhZjywMCOz zf*jWNQLXh!Ds?3Rw*uZxk^Ih&%~|A8v?2o)G_{R{e_S}zGm9X!!q=*f zD(`5QHVQ^Mc|C9rhAa&;IL)wJt)f%>y-Cf{Ik(gCgaYJZ-;ufT*Kc4eD>eFcjRNNF zbbL^;)T&Y8Z+x-H6EoRbPnJ4{fw(dt!p81Wr@&kzalyRWKWEwuXt-hTuVrc~T+?o8 zZo1}e5Axdel&mAm3d;>W?a44;Dv11vVkyA=XJ&3tJ2^-hlb%G;5zTS9I9)6=F|S#n z4vQf8_5^ODc8OJ<;ME>~|eeO$r~u zyVx3c^!Cppkp$*EY8#Q+Jc{^WX}Rh+aWyd4)b@!?L3Esic_P9$X!xN5h;)R8=a#-* zT0}e_x!n3E;MxHhE~R~uk}C;;JF^xEWK6*kK ziO()DFh(=gX!@)P#f}5**QisDGu;xQ zavpSBg=moc*bk52SoWkQPQ?`p5m`nj@x+zGBu3l(T*kQsAsUn zmM^s>JHV#Nl)O2KUsQK=&c5L;Wh&Mnv0@pM>Ng>Xw|egJ!`12up0i3Fmu$~82FY16 zV=J&oZJFO-#JvaDrmK#P)cySD3@De&5F?ONIDZ4nnLlg(X<4k9`y<12CmD|MKFdcS zk0)UZ2VV#S#G%<1vI>#OE5MJrX$@l!-9^cXWYhj&Mrduz&#+&nFJ*SkpB z`;nz*A`lE?iq!wwvs3A#Rb^Euv?y}%)EeP0(}+sWSZl*_sQhvg10S-`&Aa8(s~Gvb z_(sobD%={uJ2Qfc9^M0o>S#ZwCIih(b^vtuz)~wCLg>rNY z>}MLVihtK%bBP#wnv)Yy8nd`F4ujwn2<1zpeu7O6YbdJk$~sDbI@MC&9zH}2J45G$ z1OfTLgBNRW(g_L`)Yy&;9gB#I)3dK^J3;|zZKD(s^|^CfanFzTM(U|6!K;p}S00Si zEyk5%I|y|qIhJUAC1Xdry+@5`gB)ZciQ3d*nGw(I2c^RIq~O=Pkori{IfvD=z30gy z3>weO@CFl2#v$h^|9gp53bOu-x8Sv%kd0~TYy{&s80p~sAysutPQy1>sY8u`%L0M; zA>g^P&|+o=icIs@-4pM1n-5!QUy>3q{K_nJ;o7~o`rp7oNyyqHTo}mT1mDPi_Rp{#+m@1vvR?oqc_aAl+HV6*VX~!IC zCYS*Nn^rO_lj9%hQ4y4!X0-ZZ%L)==o$?-xlp?lN7jlx$9V-tktJJO&{vER34psTZ zHp30~>wFaX3k?4b!EuM1R3VZ|AcnsTq~t5ai4gzX>9clF^y>2c#fjd+@h8K>w3{JD z#K`Jxt}>d1es;?Xa`H1GMIEiCAs8KaW>RsJIfx{VUtE_hbEGa&%ut}_F}297Stp&^ zht+KBIWqjB$AX!OjWm_RjA}LAcB(ZsEGl4(AjV!^|D1Tiy#rtl*nlX7Kb-C6uWG9l}Z6*(Ra`6&$>f7atE#?1TKx zahHwSO8gh#PIB$QUWbXR#SvIhRyL8p&NIFjCV*D2M{lBb)~7)ME(8`Gz*@X=$8G~M zsq%t*iNP-mY70e8f0c5_sv?kZK!(1WpSD^Jv0$x{^3*UV{eIH^{rsRj{6@bbUN2wA;%93LTV^9WwV4;|S78s#yD6tryv zN|XFj>&nr|B2n`!Y=Q=|sGTpqav@Ml&DPZ_wviy9kp?ADR^rb`$qL<{ z>a<)=hB0d zK-}%$3KTljSVr~~b6qfGHtLTBhlS^^UF3qN%B z!z83RhN3>{rHw>xl*Tf$IGmeVB06ha=-~!0>Mj6i(0L*tF9k0t>;L30KSwF~-*#TV zZpxJ;F%@Z8fKJU34;`t~emBeoIBj`fcqevWfUUkL{`kJGJES(n*U_AYaf3IiC?$lXK`jrf=rh;S8k}x@1#qFp!h-m(2Ts zQs@n$LI36o4>2}y+sDQWGm!({VSR|0{|u6_v-K>EuO{w)8fq}w-m;GBJax4}$^$K$0NI3;loKWbO!f004qFVCM_Vz)+ZS-tsBS5v+*N z){c>cWh>PK|F>$w58A50XhdW5*?w)7ZB3LyArV==@}+lw>iB^z<^8wBBG#yh7TYg7 z4YJWG@#1rh_Rj{|X&^JIsn%Fb=#C{BE>4~d>jp+%TOS`f(c8V$sZ?WL2L!WT&!DP* z$Gka<_4U-#mlr|qX-~#?$`1nz9ki{DU_Ym%pA-Hlo7YYD^9B*c1UgSmd!|z+&`WY{ z`-csC&yuxx^od%!R;k*CY5qcPU4!nD&tbv8J^F2Q48uBY<4Xw63VR&{tIWhh(>SK-Em zUfp47h86A}_I5?)E8%5dZ?@_VR1ZRHp@*zZ1J|Cdh@O%xD>g3Z4qb&8r-D}p6aD+0 zWgY5Zgotj|18E9~`C@f){U3y=e_#LF;BtGZ;H|9736^hC?X3VoJ)Qfw45JKa<639% zNVLONlG&y6i;KQKmA%a6bGdPXJ5kZm7tb~u>p%ye>mVA6k+rmq-yhDq^EwkW8f;t8 z<6J>E$9$yBfs@!DT*VtLEkTC zq%t2~LHD9MlfN9qIO$#AbOwM7N#!TuQFkgkX+$VBB$17u#E@$vIA=a8A_1t8f1Nsi zm1C?IIjLP5Ej2z4VBqf_#dcozu|m17Y-ox=+;4s5ZWB2ep~I+HYF&?3`r8n9epF~b z`nlv?Rah=Db*+uznaDiQX~toqJfI=WUzaMfBjnX3aY@4^M zdyXL~wVn1XoJPLC#hk8D-*bm#kI&mDj0sVu(*HU3qbcHpY~g>}RugHGz{1J8SK5O- zovTSqHrbtD#=xCcEn&6l%b{?Q<`@_Fs|;5YAMVr=#j+>y{&9HARGFG98y5k{m2{h; zGi}=#8S_M9t{#J{;u=pdzgM;M}#%v|I_frjadH5yC@&MfP6pSGh z6}WGpdEM~=SveIG!ZDrNDVN;tu#G?m0`?vgt%^pUQSbquB9od=&LN4h5B5aTRl{PJ zDiHM(EkgS}C>{#H4LCuIhG-NlY@OR0hfRVl}v<~v(WCoy$NRTT=2bUQEDQqO5!H9Vs1ugJwPm> z=vyxCPNYHKO5C%a=b^(h)U+;Uxn4HYA4@-?tdB?H=CfqI~wDp)hVjRAKWo&L(%W+0$!jC^HWbzZjkS( zlZQ9pCKCNC;7}WJkiL;nLa#T{3;cD)Kcn?flSE!x@R;4VM)Z-&??QvY2mE>K<+O1~&y+G-N$WeCHt5dXEHKJZuZPWnEP&eYYf_I>DDM-PTUyaM ztly>fR-~j@`gnDvf(L}s51}f!0~I;2&|$KDJZ$ow6e?P_o|*ijOzfJX-x5eUpRNR; zucwO`wyAb=J#{IRcPOC;i&ha5dj9My5k$^UD7J$F^^H?0guwu|k0jId1cuRIgAzd} zc)2nV8-e;wFm(PEldd(p(PAHIZv&DO(n&W+Wf!-V`-8RD^jMnsbx9 zqAJgQn4CCD#<-BHm3MX13OQ^B)6*OQw;!2V9qulpZ*=ELy+Rt*9q~>eUDw43BFjcrf%+ClKx0O}`?LVf?^euk3p1i&X%orBN_ zOkAPqF=D7G5d!VNLs6}Fb-ew$ilBax?wa7s=lXgLx@~SP(*`|a%@qChiGL?3@|9!0 zY@|IVC=FAe)AgIoin+w!=MAi9?Ja2t!>CR_1;t05=c{B5qws>nNK{fxc20+NS#oh4ORQ4IM365@diC7Rz6YPG=EQ`dW=KO9IV9~u}v2hm2fsa3*`vdY&W31I(< zsRWW832~)~?`n=Hzs#_aozE=iZKVQmTh0)~VscGsL;-g{t5p44{fxcd?5DT@6S|oa zTO2P2FBXl$&BqCe8K`d)$pFwen8Ih%PD-C3WipzFvd$jI8iei$EZk&E?9CnQ zpDWe7HTxGgs1M`$)M9*Rzq&LEL09`>xZPsdDaZu_OOnIq!j}SIy~#vV92}q|$|q}r zn%TBPKjP7%$n1yw_`=s8sJM7HQoANRuX!JN00|_j_#?6o zx`zjZp15YryxS|2Qf)>A0I zM(*EYxG;&D8z&SWZMZDb|J>r%KTh-lSgA)g{WqZX+LMCR_TBg*GZ^77a7@Rg^KWIq z-ib@5)Tq7x7G=LrMDvRHV|zs14aASrT~|FA6{N~Gei)b;ZEP$;wQb(P7Z?+!wP}wH zQC-Jp$fum!Clht5x@_XryKa5hkam<2Y!u{u`DeI()UU-Q5#AC+O?~v#gsT@4l5xb&cy)b#9>T_NV)YLn9oB{v@ngHNM`)^bU6lxa( zAmkIoS|*v_^hjX`nt$aEmn$QXYK}mC=N;&hn8N2~Ggfq{2X6zhX&oc)*iD)>q2B+N zVSr%NlikY&TvFid@Wk*C(wg%9DaSxddsK|B1BAX)`AHwfr(}5SzUo>@7z1KwayPCm zrt@4(j(OOk{_9%zMKxSjtL!wU-?pT5rR@Xj&&jLvh<@>s@QI-TnaMs^bjGIHT=K0% zzju=Uur@F)8w&}+LNWYQ2MYR@5tRF| zz-HEN8tV}U3!Lj59~YaRpEX7P-#K2VLC8Hw2P&+8k2vMW*`0h>$3n7sk1hJMTXjwS z7;%e$w8GBQi4wKwBnZX$T<7l;A48cjI_y48N0=bCPfK&?0r*p0d`%4Qr}GxSu*}xs zgD*>>Lxbh8foG1ZgTJYWl z?E7TPXTsnh5!gi_j~)?J(2R@+f}z$8l$WMky^=;d_KVv`rMcgL7Hp{(GA4{Q1a2K@3!Gl2G|GlBf zgnwU6jVP|B(>Hf`E;7tTq=1S|%+lP9GO}`SnnKM2&g4#&0+dWUN5BfUP1k2u)_DN} za+1P^ubsn=i{ne&xsx=>V*|!gr9>s2%3f9_i{_QYfmd&%XPlF$X)8Dx4MG{uz?8*j zfmD-98dP-=d6at$OxCuiP-wVWvs;ms$+Xk*XvLgToUnRSO%(Yf(orLmJ;0P`SFXcv zdTv`zRHiu_l+=PGVT{7RMDnd$dE&2szUldyBg^hk$J7Bt;T{Z{VAF-+|DP#9-eLeu zLtOXrGwIzdN1yM=4Rlmk;c>HrqfY7%B~@p;L&q*_ zd(Q1GQ}|zz*U8oS;+YgEoWnsAn!B+5|7#M0w8sFzDOBT|u42<7KWLbAcx)edeFxb^ z)&@?GDEvVf9noH1jp7=vC?X!8T60+;ZDnFtsT08pggTw(x@y-8Bk5S7tMH6W7B_^HweT!SN-u*n-%n^GGw0Jc_-U$u}7mw8fiE z&Dx``7!kM3+#Nc=V<;dF@sB6b)1dIe28NKz+L_N@M8xk#|7mx=OpaO9IZm-Hx)S2P zPYR67;1e)ZReML}M%~}Pk<8zXP?lo!5;y5u@RlA{24vu;KtM&hLojA8xYX<6lsCk> z2Xdfzvq;(PWc~5Rj?i?`nY9g{N~%4PxPDdad8B$>t55E_|39@PT;(R5T^{43oQsfb zd+(eMqug(GNgc95%)s{D7+!aWG;fiF292f=ardsn>&w4d^PzkqFLcnEMJP0aLK3~z zSJs~9cRW%>k)|wT|0MU{8kLy~V$bnf5G;#d&&gu%{zbTeTZiTF`ipEpa;%xL9vdxx zM_bfKUDP8(?7Edi6$>||@&JFyOH+#WcC70%e%+7r#jn)3T&04++5itcC*M?;)5xF% zP7ukYcn_<@h>!G5jLZ%6^>7gM0 zUX3)nxA3ryel=C0*?|1WCOB*w9dTD%s^^z$m9r?gK!`w4!Co_@^seQM{ou)jr0%nl zAxYT%98e)p?*EVN(ZoY4ED%466eIxm*MRiUv zKh?4m?a3XP4@3@1Xv%D9n{v9+=ph<$pzP<$LkbQLA=}W^0h%aVPv0 zAhQF(!fXK$&ejfEEybdGp@dpm`POmAa1%;Tgk1$wUf6=>03{&Ek8c{}}a z7*e~tmHss_3~0pyI{|90UDJX!bf~W)I98Xiy(nsCFtg-tBtyb#%*+muSl9qVHr!u; zY9MS3aGlb%Fsvu;MXgiOgz%{QYbp5UD62ft#Lkz^?gZU_Yx_Fkm^&S>HPBskDc z2E3~;URMCyWf`mhaO2mbS&ha<5+DQxL- zD)T!xT;Cb%Fj1-Sex5Ju)ieXDH+tfdAe6)1}F=3;0<(^5b+V%O0hi{-u#Y{+PD# z;6DogjwRTqj1^{UBvg~K^Wc-B9Ad~{sABl=kgPv}&z6t_QuuWykgVV`D`MN(y^)c< zlRd~PUW;ll&Apm;fBiN#1{nEl#7Li4Q7EPBWsKfh$Bbg3m?t*pl5;H#C8X=sV-v|d z|B@s#@2phj&cjw|tGC}ot|&gy%qL}!J+VmjoYhtn0rXG}S~Ar`YsJ=#I%`CgR0$5I z<9&(KF|3{8WTPmlTzjg0`wPugd!IoI34jBH4auQ|GAq17bN~)d>-)}e>7!QFpCY*< z{^BT&vqar5sgSgx`DaMUZkN;7Oi46c0V74WP|%;CQHB5at47UJ;-cB9rsH0U`c*9J zG0T&4Qv8oqoqm?i#HIoH?mnw(w+8)sJjr@$%{MQYP=G$m%Aznj-q?~2q2Exv;R_!Z zPUPt+`Z5f~l7W`rZP=X^7~lHkI#+f)Q_@M#_;E0iCvZHDP!*QqFfxWXJ&`R-q7cEN zkFL2mQMjTBCjhDu1v0V;8u(bO+g5 zqkISFh4%WL+Jhw7b1m{iv8Bq(sgL|6tW!Cg7ckT4E8!9LUuORD)&AL-OQf?;O4aUvRsj9uP$V)NCf!D3oLHe5B zVC#0AmL=H($J}yXibL1cH2PMT4<#bCwXe`QW)Q+mAHQ*nbeuY1mCSdX$9wn<@fI1mmU0sL|E9 zI0yw6vUlF=aI8SLn@Lt5H&aB;gWP`I&G$3UeUY+@b5q5*b>w>}e)QtUThmVjk^{re zu6b!?ZBeW#;PC|X|H9gho-CjEWVpY7V_4xLB^S6!@szjwdU2-xGo6K+_1Zr2u0OcU zE5gt8OhZH!1jty7hzCNl76&zL@QW$AsBR6X7jaZ6V_EV?eFTN;pGS(wXAD~AJ)X0$%o&EXOj4=)8gT|U{}-*l_e$Hkd_`c@QRJHdFogj1 z>ucxCZf|zQwTYx#m7E{wvYGGx2Gwa9mj00a)gcrIZbyteNOU=Z1B>HpuOv7deCpo! z5)0px_kXfpy2P*9HrZt2T(Vo1iN5x7N$Is-#A+0x77ob|24mJug20F#mN@HGn<~2I z@C4R*dL6|U@bNKY{uPYBbNYMPZOU;ZKJ3Jx6k*}k(1K&%2f=Zy(d8nV)Z?anoEv5K z4kUr-@k};1T42JS;cD{%Qd@h>qj&)*Z9Hsp^j6ugeQqdPINZd=}`IrqOT|FnaVAf5Zzx2J+0Y zwJ+q2hrlE>1MCy`TEUk7qsWQ`hcl_cPa?it$Z5|WndO>sVV>n`tJbIK4W<`k)eAD} z;v`3;SATDWE`zJ&jSQ>1`G}AlWVKM=3cBvcHtNrBmk1cX<8>ICTF`LWg*yzM^0XC^ z@}OrD&!?MQY@TWcCe1dkBWV1)I{{hf54Vz;VXoE9{GU(00FW?11pJG420e3Jv(!l; zG_SUQLsbO2`ZsTn!{-1x?X*(>lSI1Y4w;!gae9<~_6aF_S}g~?+lX^GCpu^C^@*y_ zW(*X47SL_SnmT{FrDc*Cfg+;T27@MB39`>Ed^U6Zk7R_RlzR`4d_9^9B=+kV)|() zS`14ZM>=Ie`vN86Olm5b5uAG3glkm1rbZ~cZ{P}!&hhJjHgPvk{e`*;r1y|Wd>737 zh?nA&N1uof?c*5eO=8n`Y&I8RsU50$dH>1@|L>2ftbUd*NybHxXHcqdhB&$omtprkIXiT#YWPGTt$q&`9CMD}E(tnRUIyHzDyQfw)xdgF zt!D!qp=iYgfau6fpMZ}9}bh;aE6PW4Zs6Q3tTj_g#a_G(2N5Oor>4<>-K?yNLC5hvS3kk08Fgx)e2o>^cfN&W9lkjk~

G;J3F^L;|KN*Aq~Qcsv_@bV{?*s}7Z#T74R!yf09R zCuJ()1;FHo8Il+7XpkMah~c)gL{s|kTt?1I%zzK3UQcPUYBZVRg=s2va%=lWK7wMD zNVW0&e$#hY7CFIcotQo;t1@0h=HqcqkzJKHHZb9{wM)ui(xC8$gt4*d!ug*#Lm6NI zbi^bw01dh$?Bid6ysU;lD)pg_i;V|ZS6M53oKHC*6l#uIKa`vU=27HgnPRAJ&I01% zk?Lkv?_c$S7pY=S*5$oh1)%**6cnCuFgE{Bfdh&F1CVN2hz@ev6XU${_-BLpFn$=x|CJZ#y6LK!~tgIwjXLEkY(Amf?g43tzO*DfznYMaphRqIk zCddGsOvLq!12(M^aygtnBqeT-Dbc{Bk#LvhBWu3)96-P;dyqTBY4b1j;o!)XN{WFr zh!h{ApHn)AiE7qp)(yXUqfti{u^b?vtA?FHW)E3BZu?2AxCj7I*2*5(CFQ{We1Ql! z;CIbu-C4aI(X}WBDg>9TTr)~-A&Y6W`W_19flAW!${`Nvv0o%-iv6&bge0Zs7?m?$ z$JTE~#-x9Z@SPW~;`=G_zm7KxR$lUx{eA2_fL7l z=*5Xy(IE1@^yTD1vrw3sng5%GCwC*eIcqdGU?eg$vZ)ki671ejS1IKN9qkf>qQ*K~ zoH$6K?w~O+)|Kc?Linw#buSw;C^CEIcr`9|-H4f#{*@zQiLEE{U!t7o$9x_naBLrN z;WQ+CGWkT~>2q3rE^mbB>IV*z`;Sf97RFnhF5_N1T1Rn2n`>pdYAV8ibO=LNN5;E( zy}Lu{OVbm)#){&o4>v3U8@}jfVg4-{B_KQtxy5n=BIL{>85o^)1|C+7nn*Z)C8Dm{ z32_3HI1vvuM27_5maQjQF$f;n4!=HOi!)>nH|Bl7plWwT>#{mRu=&G4r-%&!VVOTf zp8Nme>K)iCi?(gi*mf#TDz?pvZQHhO+qP|672CFL=cdly_j~8v^$XVe)*O9~hThtq zNi>*_q`x_kW`+$MaW6srtsDKerTnN$CpvHE#9uWOt#ph6TPIN8B-={2D7wd|Q$Q8z z;1*n4nO}k3;VE0a%+Z7nPXs&&Qu&X^OBR3Tso2g_!}x9qI(mnveynFqsA7qTCLon_ z^^QSIKVyT&Kr8tuEz$qnD3atmBC8c|KG&(8WnPf_CTRYMf|vf< z*EJwVg>QxilHx^1B3J>!?3C zKi~fy-{lY({+H>lSZA}ed_op+!|&kR_6>$tZ&04eLr=PlD_lYYdY-?9!D%RPYocax ze3vbU+o(lKv=(~-#o(BrQR6^K%vqd)+PeFs5|f&1toHZlRnkD#nF^-!HCO9Kb!t*} zGnNEV%1nuPK~p98>qjm4c8NUI}_;BC1^d(q>PJ^Vpm2$XXFqkh2%3f1mJzF35E9&>x%}pTt`J4q6&*S_KuP$^rzFcQcHrN62^&n^|h=^ z4S1A)i0UJJD)Fb3Clk*J`mHLA&`e7PG96(-VCrB2c$Zi=^`5PU37rimI?V6Ihm2o} z5TKSMcIQ_)7iXGW2FwAB+$p5dTEg7@8!(s4gC117nE1kGLZoIWqaZxyoRH= zIhW^??9y2e4JY_0x$oQS^}YQ|ImSE&Nd6j1b*(s6m$96nF~)333=GSD`5Noz>OS-M z6{tM*+6$rbeN1K%=oP0L;|U05@{nN%PR5VJlVpJDJK!C3N0b8de*=~EDG$<6j&Rq7+E2b%YV*9Nsp%#b|t*`J6d$~$~+lU2g;8A}`VrRQ$QWfid zjCJ4Rpkg9&Y6D4gjaLd3dQC|n=h~=>ob0il(db(SVW>XBJgQ$NfcAC4#vdF1+}316 z@jsjaQ!oIrE&bo)h)Gf(h`KRY52JSoehE^kL`j zd4*g5I&cu3XS~ToSQ7y@$GT<`aKcf$Nzo;b%hCi>wJGxGB1VO=2*EKiU~ne|(1u<& zKbNrG3vY?21p}&QU?8CLz1ADIHR!DahJwUGH(~ETa$qy#_t_VyiENAksAgAy7&JF z9oLU0`q|MR>)RIE&oR};`2LKjb$@h?ClVx`#~u;RaL%5SforG8G4q%UOQeZ|1V=o9 z$f$e0;3Jh;Ju(@7ic`##EN0X!^YvNVA!RpPl+W z4V=WP@-3@gFinUuU5gTmA{!e^rZktT*_G=TS6V^aNTdsA?UE@IKFvddWl_V89(p6O zND5FaIp!rn?hx&8E2VCSl@pjPf)^Z8O^q1IK53wOyyqtE)*8IIn(-9N&7k zE^Ra3`rH)1m&uh#T#T7g&L)=vozO0XA`5t_pwy}%AaM$N2lrgT$8^Qh(Isr>ozuHu zt6h#TBLLuio}dl7mS&-sl3a6&X)-z$x4n7m)3?OEzL7vfs}oa9Wu*1*`9ddWJdw z!N3cZHjRD91yxBpN}rp+L$e|^lL~NN>rneKz`Bb43=16UUsdnB(v}hUeGvJh(hIGU zJ`Z{v)1v7;8$CwJPi>KVI5?5lY?q}%@HDGCnD4DAh$|{hxDDu&fW|ULc2U*diZ?P` zM&{(3hQc(Qx?V6Z<#YsBReBTS#=EE5uOvbR^I>wxUfgRE375pP|YS zHigJbJWTv9LO_^kT?XKzUx5Bbf1Y%JHQ%{&W30vFR~|v%7#?xE@}qYzsH<&pW7+?$ zf;K>Uo1$#tXZZDp&@OqS&6hVh<^KDSA@Uf;|I003l5h=durtQr>ueM$X_k0~j*^0~m;_EGmhLcF(RA%o|c?RVM9 zue}KMxBgho44CW#On0pEcP@o)E|_bU?C7vA$8%N%9AP0%EDhuDs%t5M*PsOIX7IhV z;5rPigrmqpjxdm0&AaMrsBqP08G_tcECymh>d7(ZKTA$U!hwoEwVB>sjV#8}2i=d= zZXQq#d9(3lK}DX6^ufOAj7(r$;eM9DSl5E1(OVgpLDmg(Ko@4*7RsJZN%dC8Uvjlm z3N4?pir&c|MPn!PfzF95u+_5VdY)Q`;n6d%Fj0(imY{`@gbRC{9MXT8A@?^?;F z>6F^jSJH9aNs~u@mg1d?0JY%Lc?m`?%u=hyY}CFaK_iG#zSg7{ZhlON)&cfnY8Ede z(Y-xY`y5Bz{sYND#;_1l6F~*2`U+=c?0_Yhx4V?HiOg$n=db8$t}fY3aBN;U>kSjw zaWlU7PXX z<}-i?qlyc)y&1UNE~M0$mK8TSo2O#s>2@Xm46;K#8LXj*8^p$a0^U*@ovfQWBh3yY zvj;*k{Yz4dpFKK}#mlf%m3Ao=+K1g$dxfp>CBnVL(P@@?P1&QKfF4DN;932xDJXbt zYp+T_K5;NrL_N>@=#7Wo8lK~e=4nc?X<877w}MsNLFzJHsvgGDBBgcG2DxP5euJ<; zPE4Z$>*d{71*fgnu}ftH2CS)9Nre!$8G}`gn;Y4)7JZx_w_}>q$gELIgy7=+2pL>^ z&Cs)|#}>3MC_IP%H%r-{kDT3M^}d+xQ_@UEf$`Yh$N;Nbo8M|bDz}+i^IJ3yGAzWn zY+1u})4{~l@{kjm?yJR7eRwmh)dq@rtLS>PZcOzUG_4;x@Y)5Auwdcr;I;lWl*qLS zqwyo*ZV|DWQIKp6)`a9eYrPt4nO~6XEb3)KVDwgM87?)l~DOt*ff3QQ)_V7VIewT7(zZ>cj9;lC{edn-P z!xVxRoNYLcVlhG5@5m|y_~9&rB4&3ZtWmQ^3Q{hb#ITBD_i?s&0&J06<; zMzJozew<8BxT7_o1%^mKG6)c`bpUP*fPYR2s2L0Z+EP&Quh_>|QQ(QnvA^~B)(;W@ z4594XI-Ub;N&OVq$}JO%70WpiU5E*2pLBJ^$|WCXKE+L&x!wR8Sl}S(fK$pY#SR8; zaqDr6Qxh&iA6(i1Oi{UGquCI>8^ZBmEnK*HJ;wj@d`1lOQgExOXv6QpsIL=%&uv4n6r-@bQ1e|DQ*l(-~L!RX6+6nZ4s;5PY zzt3zeSP^A1#e7YTL=0UmQGVk<@}+rT{c}`+h#E4okwJt8R~5!%Z_XHBP*JEItYcf- z%Cw6TE$eA*1+`%5MuHy+ey@a2k=`;L+D6PQw(LU;zgr(<4uav=Od2obWkX!>$+Sq- zJe0If3PT=|Jo0zNG;D+>JaLfeUDj!?ZfqB&9vf9gZbx>;x^2MqI{kb=vSl5xu65OB zgqf_1(vi2XzN1R1gx($wof`C9axCn%6+}@#Z(9z8HJC znx%-zaC2TpvTh8T%?Xc|w%I;&N2h9VvFComX^K-upyg{0vJUErA{s<$`!thxRQnmH z=7=C&coqzGIMBRuqHTG8hV07^@&fZD+AVMq2Ui`{i}+A{->mV%4+CCnh}ZnGceo$$ z;b4m(W{KY@rAMn0j>E^uUe+)B{t?#CBnLAOTN!G9@@B+34Jn7&Ottmc+?jEHuDNhai1sBAsOZcY$h^9WrDfTP zu=m^SwCe?%$oAj+Yj-Iwvq4h#G1 z+h0Hd-!>?I_>Dich7vH_!mU zwk;1c3b0+)%BG@`H}7f}0c-(AduAw(`9VLk2fE=<*6Lh-x^Aei!kc`#2n|S* z*>lOOJ93w;yabfunNtkO_rO0k1)zmDIhI5H)1%KPRrjsbwYIatF)(kSfq^emlG_5@ zweW1GTWJRnsCmNCth>sEg>8%}o=IaO#%=0#Z)0sm| zMiB*9)LtE7ob06TH9x{HZ7Bi%+>L(}VN;N2xTw7%&*rCfod1>3Vde?AGx$%>PjJ^y z@tQcGk?6)gZ<(Q)hOwrac||PKj~hYmqIr!z9)p07c17{IfKv1A>ENORpiXD2h59Jg z;fhz7yn7{U!V5Q1vdjzzCQ3%X`XpHNl;d2Jk$`Vx!Z!XG6g6A^Lwe!spyDTKR- zv2wJsE+0x<9MxI;mc5yjREUe=d|4VwNFW?%wr2H2zG0#2Z6lc45-YsEE;BKW85hC7 zfAHtYNTcz6rV($yq7Kp_!}n$>>=U9TAp(?OUp&W-Mc4TA&Ev$cj{!{2ruq2~RW zZjMCMQbs0NWxNQ<_ab^-nhUP#z@Hd?X)YmIB56^8mg7M$eL@J8NxH#}k1=I+4Xacs zPkxx`mm{o74x5@%9d_EVpD*^%gSlel&;=5REEf_kETR-zsnCea%{9|{ZK?^nr51^< zv~0Y`1OmJED?oPsTacF=E@74-e%R^D67VcdgSv0W6V(4NkJmJ0hu>zVk-d#xH6woE zQNl?ncogQEN!BDa0?5KAJfEqaxLn==u)v>Lv~I%@CXdSRqz@X>deB6cLg*-rrJsl4 z)gN|FTS5WcR8Exk8h5YTYmkA24D5et`Tzj`-qaIZSj&{n&}*CcMQ=la6kLy1S3k~0 z=>M`6{~bB?Go&!!`OYt-CACji0^g}W&zWWGkRiNwdR$r~!iR-7G0Bp(Le{833A-f; zS#$ldr$5ihK2)vj2pbrYwoZP?;0r-Wh$^f`47Q+t42|5#=UY3CQ#MA;nI!jMBhg>D zWT6Bg*}LHhutkaD_RDuoZ@WYy7c39A!rb7k1^bBGgDSue9WsH=?KxeTr}4AH z7@q=_v$IAU{WuK5i@5x7`Z{nxJKKV;kOX8nTHJ92P2j@D{~_MT>j<8ETtLgSG>QQS zQlm8HpxXYdETQl4>}>{tG|%kW5?V^8RRT7_th6vmZvm<%KC4_NSDXTpAo(Bu;u=q| z$wGk5T$NY+g;X!3oLJovwV`B}j9umia+KLk*m1CPi&$DIrISZ7Orbs#mE2hXubIor z?hyZ`Inr?X8#7)SlR|By)L4wou*}5H06}u*S9)wo#1v2A(bn2Enb5k?hi6upJHhxw z)^8V-s=iIHvG^~t;j2z6_G3zqS5THiEa@$O+5Aj~uRx`ieuNbQOff5AZS%tl3*p!0 z!#O0ydj59OmnWEcGsWbDTx>9s1Fxv5ZfrDk0HZM_E*l7h#6Tp^4-TgP!HnHnGrrA? z=JuB58s(ji5K?B^>Fv8eJ>Y0p+T%MePT{2nS1Jwz2J6y3tnL1VO@g~Z>#8TU=DX*z z38%HlNM%%rI5GnnXgK$Re_!7|f94h`v)@UZVOC~JyL;<)jvje^d|77Or7UE~IzL-9 zso+^d@B?(@JV!B&QldA+;BYFFgNK!2gSaxg`BMl~;9UO?;3ujS^ze>0MyFFWUhk7hfY!Ol4|+VFn~S8Fa(sN3kId@c@z#K>lVo6S z{CR`J{nPe2{y$Gz{R~(S@H1$Zaq|6`??)-|Z30X|!f+1qoaEOz;C#b)wF_t`zmpoq zMiNG$<=?!+$8bMY_65E4opv7Mfl8?5R}3*xL0zLPn)_+;-LB)ezqQg12kgdST#m4XY=@ zmEGhPpW+MdzPjIsOE(VDY_y89z5@HRoSM?W$%HF?*pgefWm$FeMOO;>x*@k&OHOt6 zS{4}cy_E9yoec`_&5x@e1zMaHGhbj{NxbS%^j`C0(|VN(*P6enP~b zT=(SZ1NKHUx-G$h}Es+uFA|V241RtuGy93_^kxA!_8dZrVK7?2i${!hYaRNq5hYY z4FK`uV3UutrmsX_AowO<87j3b+rwjidqS@%ZfC%wL;fdb|F0t&ajKyb40GEey*R=9 z_`}Wsv|}j~MHsgwM)KTqOI2kkiLh?a~}>N9gNS`McR0zZ)nYV@OdK)eA9R zt>ZyVk>WQ9rdg>?b@q*SQ)xUCyMQZq)(f|sFt8|O`U*@P z*6fRAxm4Rmjc;0lnpPPGINkI11aw==)NKT%u=P^=1ZW{jwM4mP#t9+CDUW${znB?v z73$iup66-(*|gIVwCMRw!>zKHn@!l|tIQ>ULVI^|kG&Um&*%^!?LLR#%oQx>BhJ3K zY@2-Q^2kZ?3Qe<)f&IhS`iPdj$-fDY%H2+X774g~Q<6a9HS9v}jMF83+_4$)Bnk)} zRV${gZ(BJI=Vbqi$AkDvkkFs)I9}eD=DI4hooY}B*8-2nlqU42Y7mACGGyFNU!W(} zE46%^T$HB#-S$2A9x4Rode{!!hY$LZ@25EW$_JI!B62`Ew`WUF)P`*?!A$%6Nt@5| zX#qFJghE{`;7)Ei35+%E3?Bga2F`@|lSXj2nI2iMrU_p-32jbFZ?e{q%df9I%pZzH z+SMDe*A|IjY|CJAL&SfPG==cw07L5?N{j`)HAGQDt zO;7z_g7EU8cNU6=K_egs$d=817*U2i%kV#S8%5c91#1ws)8ZQfI#wrSwM=vZQGhq! z6_F^o_)dVm*1#Sx+~2t%IbW7b{}uP$E!*GL@?x$MQRwIpCgmb9DOWW_D6Oo0SY%2H#AUAYab zE)$9RRIti}g7^G-MO3Lz+?QfANi#sm-(wp93cIb=0^^atNdj5Pc5W_GsrZEhbFHYvApRG_#H zSV?ng5o17&FI<6|uU4era#zhf)7s{R?@teDhE?tB0zehvi|iu%I67k9)9pvi``oh` zux%88ah;C{+bf&D;RT=EUTj51Gf2rfJ7c7#CJ{i-5T)bm!|MYcc-l#@YCXk+7;#9Y^q!&dvkQG_3?Uf8=q^;-5m=eQT zl!J}6{UK^$iFe_T&6iT&WbT?Xh>%Kp_T)$E`vYipm z<l{(yhIZ=a~zZ^8+A6-yfU>FGxM$3XlH$N$2Ch||Dm2T|8XacP~O z#AAr@T@9xG_4Dl-VPLFuvgF&)X%W?_V1;5P_IwRMZsrv=(`h@uF#Qcf_-ocZH~e9Z z^~dLTdo2Qm+gHjkUfg9qo2iUT%%!Jd>{N3!Cgv1*wJs+%zrj>D@3}D|8{P_e6DlKn z49Y3hbN87I`t`wFSNz9e$lD7Q!BiY=MxHtcIVg^IdfO?gw7xSmih+l}{zov5s-)}U zHG7)Ob_v(Am=$t*fO*qgK~+agmGWD#flpDOeMpbWMxBjEM=Lp(<%s$DI3}kDyGN*| zo;b8rWb|ucYH6ZKp7l`e~+OVVB3$#W{>%Huf`wd4A_4S+Q|4_Fg zBn7yJ<=P*5m}RIZ`yq_JPP}rsLVv|lllEFe(Y_?)nf$UYkp8+!D_vpxZp-Y>;0Bg$ zxQ%m={`_>;KS$9}!5U;d-=nQm2NlKiz(BTpG`o_66-N^HSSe2O>NjGET*Jx0@ex2E z{Pa_FRWc?1Dl7U^7fleEK$;0pc(P&Bg{GFA9^OD+E;;thHw6>Fz<;(5`N6vqN1LnlJPvw zt{tE$A^=9OI}`HTHhi2XWTNOiBsIeuY(vfnTp%*;GMa*E_p@GoL06=MSl^_cP^&7i zukknF_weiXL3yA<4KU422Z7?bRHpDH#HW0+FbFl?&^EC`7_?Y6qnXigmu;J*r6~+@&>Q z*m`ghKQ3=aGYXxqYOJu#;^(J&FB;T#LH z;6|HMBJaXs&)+Uvj^=lp$EGWPhimZ16GzB8{|F4KMy%fN{7Q@#)(#JMk}Ftt&5yMv zKb6t9Ng{0H$lBD0eB1EFz>pcnV$Uhs_hjLjHkh{ZEHXTBPv&wU8%bwm`_9^pBsxEE z+*ysf#Hq^{I?V7ejf?fT%`C^0SS`=K!ow=lJ!i6jL~3~!MaOyFni=O5)1UeB?}Kg& ztd6U6Jzf2BuRxRhsQRo0M|0sj?oHsj8oC$gtn(Pppa)P2Y{0=aXs9=6_xA*O-)geG zu(|B}m&4-`TtktZ{}l(=tQ!P$-NHs=F6Bh~pH-`EF^0y{5FP&(o%j*NH9Kur-Z3^v z6#CS$O)gsUgF(+AgSg&TbLrAIap@4nw?|tNj|L@*JNL&?^vdSJv~%kFom8B2fIYw| zcS+wJ-d%$mqm0i1N}$>OgwDrVZeCp{{Q|JsmhrE7b^1exi_|YM#DFxZKnh!AfTXL2 zG@d^hHU`NIA+|qu2f{}rra~eHh7QleTSVZ;BsTtpC?quA59 zc0i}UHESJ5Hh4(^9uIV4W9LA`PxPGLtmV_5mj3gH0Jzf23#~(sDNEEme@F0`5A;4T zxviT0Eeceas_$J(8Z7x7tIEoIp6&)86d3oTa9I~`01d^21MH_3U84Vf_5H@}@14u2 z23{h;5fs`x6k@#z7Lt~pBl7PbkH5 z>{eXY_Ua|o<*#g{DTS_0{%2^(Cbr!kh$s*f=}TCpx@1;TKA$%re}Aa4k&^a-mzO>oa|9a!qRh4vZQmVV9bE`gaA^UWYAf_VGDEpw zJrHuaOLdJX_3!&r&Dhu3_g!zo_!cRoP>e-IQZ&go=RwC^Xdik@g|ZaJeuTJWrewIN zLX`P@#cU`R#uJQi(2C^Oyhzb|`To$+WFA-4OPwNR7@`8t9US9F8 zpn4(DI~nV6CpI&`;p%7&nXVQ>&EYJuk|j#0rxvASv-{bq?GSRrE{HuBM=LKTAcGcv ztvbv8awZKMAUWoyGQoyep`DtOQdn;rmRz~1P*VCfoOgC#&qNnQbyEYmqa0)YlL`2& z1)IrXqojLKdVsEwd&OGxCaPE8^pVM~ zJ{PGf$u#uGuY~*K3IO^k;P}wf)p9{V|fQc?b2o z8eE;(=nkJzv1I~#Z+!$l+L0;FEJaG)Ysl>Ml>V2oYE4_!lP0GK!giYp9Fh4^hfl^S z{J0J^mFqoRB|#5?-&+Fx@$tDDj0P^tnYSrGpx@1mxRZ0SGEsw8BbTlLJ>W*7G83gyh9{aKoYH}8 z&p4p8GqwHKPNV*uggto!su3O`uP_yxb8dP!*uQ>H0zC8m4*5~1Ub(Ap{EAy?Cd$hB zDp>Y7PK_}fTV+_{lrba`R(*tObzi(Kzp2it?ty=+50^2&4&dIL9q4RnhR{JMv^-)2 z_iTUskqV%!^$@m`*c1SR-eiLYLzc~}&Zr%WLNWBW^5z;?cf+*-8T;np_dyU~H5(?T$ngaL0P!q$PTCZ%T=4K% z)j4}DmSx}@kd5Ly(F8`RI!~<>@Pw{*t*4B2>fY%71T3AOAwB}@kHVx<+Ph#MM^keG z^#=Q2yG8A)gE;IMsk&}H0ZCLyD;Kkr9ZlKPI;`AWY^wcRNn)@AG=g*R#Q;qU>Ju<^|ID0;mis5Y;0G8LdplmC8WT)tj*FeJZgYcKau>P4Fudm zLFiooPe^Yur1Rt^z-cq;s=bLaZcU%n*B9xD|l!`Mo!4>5pcr~|yTmvfIcI`H! z*{~4aDYu+mYt6&ihj2?DZ$?1dr7K7eqvKUk(6m#S_?u8tCGxN)?7?kkC z+R5&V{x}(4gNMT1oHD22Ed&xs&Uhq`wYp=V3z#rNQPF>wF!YJ5F_rGdC8H~2jrOl8 z1gK0-H<8M%mhjdW=elpIaBvH6>A1hHw+w!@di;f|@J{*t43)9`wVzl~y2fxvQ*WFA z^Atb`#6p^d7=Z7(H@oyjy$Ska@bb|~nj4L=3SRJQ?SMG+lMN<9-X0iQtudz%_=xAuWqWjIKU^(&0ozFY_J$MTuVPSOqChX z%xL;kt>I|~+s>VZIc1$M8XyV{kM9kzWdsuUX(d^1idF$i=mUQGV%Y-PREtZHAVL6? zw6nZ0S2Xaq4q{M~$;TD02nHd5%Ylqn?; zzm7mdx=n?;#sriqP!+=x5f5hx=ayIcT4r3D8rDAd94yM#v0hH|vK401ELBPp zlGIo+u?HiNA`idEQT^}u-mYtES)Wv1<%u-vSd<^9=EINKR1VnR+RhD`tn zs;qAY)+yFiA>XrWP~K&$uJ5qH!2ggJ{j%89=`Pf8{L@kGt*hhomJ+-c=IJ$DLuYuo zgvmCQQ{1^KzhaxxU{OpX+S1{DQpR$pcaq5T zqJ8-cNGiR?^piJfyvD#9xt$qpf9Q0jmcgdJCoslN*nO{Q^bDFy5_tNNlP@0pnteN# z^GF_$wcLVUF(GjOSZr?gWf!XUxPvvQXaUs?{Iv$lbvCN{73g+T+sEz@kwH(c@Ag2! z)?#FGkq7Oze|w@`c`|ec%F<^2wy3wnh|*kNA7d#>-P^DL&CblG_2lN08668pF7+L3 zn>H_85_daK67O6~mi3VUiU?c%(2ENkO}i0rl^wN^Z?4^h4FJUplenVqcvQb@+oJ%w z_ zHyp5Xw;bY%-GtVJ8<-!dIVHaDH1I*mp&i0%7sdtQ7^d#q5L#Eek9ft{Jf=^oJJi+{ zRr&R~0@Y!SQkm66;bkofG)3eqbKBVzkJ$*TqHriJv<2aki&q^Mq^aQ7gDIdV*jFzU zc~w&sYFSR8sz7{g?!45gAJ}LBOinhTOu1KtEEaLZ)o#$wByYlPkv=J42oA_C5upH% zI>5N@_hIi@P1c?1dZIY+5WQ%)L!z)BV0=H1f^X2T%bIMPeEU~>r|e^4U_Gh#4*eA| z7GFK7v2bV1=b#L%))uak27z{sI;T992K=eN*ko)v{9t(BISyYs2Wu;r;H#wzC&nOgF&bR(`kPW`=rHAVYm9x2Y28j64`m?daFxF9 zu~H!k^F`sjXhJjR9pL6D2L3|XsSd3&=|P^v{q)NFeC_C+FMZL6T9?~oGN_nL}t z9CU8>akhME?l%=BV=4zrm8Q*X%X{Z`Cki8P7Qd_a2bLXSM6NR)?rsYqS2pVc?P(D` zt}^x07s*&+ltid^=wIN@<~<(-){+*sP{#z1U7MrO|MH3sKAE6H{ju*eT|vu~X2Z^E0gf@>so&{Wznu_+EO(DmVQ8E#qnM;=We*gSY9`-#q6O7Ig*0qd zZx*-_vEz3?U&VNV?$fXya_XTde1>&nBuHDGhL(%nF5%#Bs+H=Lp33>;)Z(hY{|!M@ zQbM=L9jV~g%|Fq1iERNsPhguq>UO7z<_H@Wmj3$M(xC^S0u`b3XQi!e=R85l*=Hlv zX)_{2Gz@`iIrzgazz>@$+!WDR3Di+&I-3TXt+m86fKQ|kF@c)fE+L}{ZN8=; z(>&4T1Xck=)Qx+ktS$VxLAVxkisFW7e4$m6_ln;I_& zqH3A3``e~oL`+&8haEJ2BPI`NDdkQ&aR=tqk=zK}W0W|OTZt8t5E<)bcM+Y>#ZrFg zu<}oOVYFPrS|hQ|12BYZD#94|3}FP9cquq#($<<6>zwP5{al~7<692z$~d(bHbW{U zFW2$);^n9miNG*iJ|`#et){#d@4ZX_h3D`DumDBx^Po`MYu}$gbmuwV!{qn}cCqz% z91rjJWq==Yv{&U^q)w{f(tn^V ztJes~Y}VGqzbqpxQ{%^5K0a!qEimMhdDN@x8#m6I`F;C@#Rg&X(L(m!;T7Ht+z6wt z2bB^&7$@NP37j}EL7C4{-->L%+I?07yxTlHA3T(%Go~vIoDCQva?%|m%c(C#?88j} zMyJ2Pw;hxX5Xgj4KOBu~m5A&nhUCoTZHfAHfe`V|+r+&okxs3|^fP|*>I>}jP+O!! z0Ub-3jMAvUR3eh?8^+SSs2)0De0u~a_rAhOfBd~+qFXNu+qE4RfK42ns4kV|TXsx2 z>X{+a?jhiy^#C%}X8TlkgIfg?;pxUP^d4w_6}~{?FAqp9KXvMs7^yExRXM-I z-Zy>SRuf*9Oe!@l~I3CfOU-jnnFqrBGc4p2t#yX z22$SlmrvR%DatdaT`eyr0XtB5o0ZsIy;Kfab+3dm2$P`%0szEwWBdLKNBHOUj8gIw zbJ(cve}e_hWA+f4wFif6V=S;weN~42)9RBlk$rc~V8TR|%`a!Ua!>m=V(vjgp!X+a z0Vxy!;Qxj!{FAtnnti*D!R6t#>BbsRdTr9c86mCv9CLvy;4A*}{V=gaKebT*nArad z%L>l$!q5BEo_Xu>e;m1nVOx%tXHqRX=@ApLXo%QZot|^IM-gJd{)0&!0JDWH@6nau zHwC&m2v2uIMeyn)ox?y>W+aNLdl*z?-EhPC2K_Dm;J4E;sC;Pb>A zG&8ZL>B83a&NhOJ z<*T2O&yYSTRQ#==yva=U?M4&Y{=PjI;buz}82&Q9?l|D-2ieH!tVM^!7ZMYgB>m*< zR|9TqM4|d>CV=@ov^sTNyWKH**s1F&{Kw4ByKOzVE_|um^kC=V=j#ob@)R1E@bQVNaH>W>eMM;dubNOC$A|YJ*-8Am`J1BT;&1IsdcE=M1vnf8#DK|^ zubLlf)sQp(0src;?vZxD?w}hHUdPKEy-G3{nkK5~oZ^sUEeaV)G*G2(?ZZ0Fd1xkaqI!Ebl9;pa1QNJZL^PFOX$@4^gAy%exFG_>r%F{g2^CJj2 zPdpCjb2d`X-YiCl#l%dvr7L_2a&SbsO)R`Lt>Smse5=3n4b_G;W7!Sdg@;j~)cNyn zyCX0%W4m{ROjsg6^P)-OWBd$zVJv-S*=7hWu4T=N%;DjD)fD0;c`he7p zGqya5*xObd_!H*(`CmYH=2)ty%0A7`cX%#`({axOn~3u*KMj}FmsRIJB}76h0Ae(L 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 s!oGdh*4C1?qTUaC1ZW{yrKL{q5o&W#< literal 0 HcmV?d00001 diff --git a/test/shinkai/pipeline_test.exs b/test/shinkai/pipeline_test.exs index 0a5c5e0..e6e3bca 100644 --- a/test/shinkai/pipeline_test.exs +++ b/test/shinkai/pipeline_test.exs @@ -8,59 +8,81 @@ defmodule Shinkai.PipelineTest do @moduletag :tmp_dir - setup do - {:ok, server} = - FileServer.start_link( - port: 0, - files: [%{path: "/test", location: "test/fixtures/big_buck_avc_aac.mp4"}] - ) - - %{rtsp_server: server} - end + @fixtures [ + "test/fixtures/big_buck_av1_opus.mp4", + "test/fixtures/big_buck_avc_aac.mp4" + ] - describe "hls sink" do - test "Stream from rtsp", %{tmp_dir: _dir} do - rtsp_server = start_rtsp_server(rate_control: false) - source = %Source{id: UUID.uuid4(), type: :rtsp, uri: rtsp_uri(rtsp_server)} - Phoenix.PubSub.subscribe(Shinkai.PubSub, Utils.sink_topic(source.id)) + for fixture <- @fixtures do + describe "hls sink: #{fixture}" do + test "Stream from rtsp" do + rtsp_server = start_rtsp_server(rate_control: false) - _pid = start_supervised!({Shinkai.Pipeline, source}) + source = %Source{ + id: UUID.uuid4(), + type: :rtsp, + uri: rtsp_uri(rtsp_server, unquote(fixture)) + } - assert_receive {:hls, :done}, 5_000 + Phoenix.PubSub.subscribe(Shinkai.PubSub, Utils.sink_topic(source.id)) - hls_path = Path.join(Shinkai.Config.get_config(:hls)[:storage_dir], source.id) - assert_hls(hls_path) + _pid = start_supervised!({Shinkai.Pipeline, source}) - File.rm_rf!(hls_path) - end + assert_receive {:hls, :done}, 5_000 - test "Stream from rtmp" do - {:ok, rtmp_server} = - ExRTMP.Server.start( - port: 0, - handler: Shinkai.RTMP.Server.Handler, - handler_options: [fixture: "test/fixtures/big_buck_avc_aac.mp4"] - ) + hls_path = Path.join(Shinkai.Config.get_config(:hls)[:storage_dir], source.id) - source = %Source{id: UUID.uuid4(), type: :rtmp, uri: rtmp_uri(rtmp_server, "live/test")} - Phoenix.PubSub.subscribe(Shinkai.PubSub, Utils.sink_topic(source.id)) + audio? = not String.contains?(unquote(fixture), "opus") + assert_hls(hls_path, audio?) - _pid = start_supervised!({Shinkai.Pipeline, source}) + on_exit(fn -> File.rm_rf!(hls_path) end) + end - assert_receive {:hls, :done}, 5_000 + test "Stream from rtsp publish", %{tmp_dir: _dir} do + id = UUID.uuid4() + Phoenix.PubSub.subscribe(Shinkai.PubSub, Utils.sink_topic(id)) - hls_path = Path.join(Shinkai.Config.get_config(:hls)[:storage_dir], source.id) - assert_hls(hls_path) + publisher = Shinkai.RTSP.Publisher.new("rtsp://localhost:8554/#{id}", unquote(fixture)) + Shinkai.RTSP.Publisher.publish(publisher) - ExRTMP.Server.stop(rtmp_server) - File.rm_rf!(hls_path) + assert_receive {:hls, :done}, 5_000 + + hls_path = Path.join(Shinkai.Config.get_config(:hls)[:storage_dir], id) + audio? = not String.contains?(unquote(fixture), "opus") + assert_hls(hls_path, audio?) + + File.rm_rf!(hls_path) + end + + test "Stream from rtmp" do + {:ok, rtmp_server} = + ExRTMP.Server.start( + port: 0, + handler: Shinkai.RTMP.Server.Handler, + handler_options: [fixture: unquote(fixture)] + ) + + source = %Source{id: UUID.uuid4(), type: :rtmp, uri: rtmp_uri(rtmp_server, "live/test")} + Phoenix.PubSub.subscribe(Shinkai.PubSub, Utils.sink_topic(source.id)) + + _pid = start_supervised!({Shinkai.Pipeline, source}) + + assert_receive {:hls, :done}, 5_000 + + hls_path = Path.join(Shinkai.Config.get_config(:hls)[:storage_dir], source.id) + audio? = not String.contains?(unquote(fixture), "opus") + assert_hls(hls_path, audio?) + + ExRTMP.Server.stop(rtmp_server) + File.rm_rf!(hls_path) + end end end describe "rtmp sink" do test "Stream from rtsp", %{tmp_dir: _dir} do server = start_rtsp_server() - source = %Source{id: UUID.uuid4(), type: :rtsp, uri: rtsp_uri(server)} + source = %Source{id: UUID.uuid4(), type: :rtsp, uri: rtsp_uri(server, "test")} {:ok, rtmp_server} = ExRTMP.Server.start(port: 0, handler: Shinkai.Sources.RTMP.Handler) start_source(source) @@ -120,10 +142,15 @@ defmodule Shinkai.PipelineTest do _pid = start_supervised!({Shinkai.Pipeline, source}) end - defp assert_hls(hls_path) do + defp assert_hls(hls_path, audio?, video? \\ true) do assert File.exists?(Path.join(hls_path, "master.m3u8")) assert File.exists?(Path.join(hls_path, "video.m3u8")) - assert File.exists?(Path.join(hls_path, "audio.m3u8")) + + if audio? do + assert File.exists?(Path.join(hls_path, "audio.m3u8")) + else + refute File.exists?(Path.join(hls_path, "audio.m3u8")) + end assert {:ok, multivariabt_playlist} = hls_path @@ -137,15 +164,26 @@ defmodule Shinkai.PipelineTest do items: items } = multivariabt_playlist - assert length(items) == 2 + assert length(items) == [audio?, video?] |> Enum.filter(& &1) |> Enum.count() - assert %{type: :audio, group_id: "audio"} = - Enum.find(items, &is_struct(&1, ExM3U8.Tags.Media)) + if audio? do + assert %{type: :audio, group_id: "audio"} = + Enum.find(items, &is_struct(&1, ExM3U8.Tags.Media)) + end - assert %{audio: "audio", codecs: "avc1.42C00C,mp4a.40.2", resolution: {240, 136}} = - Enum.find(items, &is_struct(&1, ExM3U8.Tags.Stream)) + # codesc "avc1.42C00C,mp4a.40.2" + if audio? do + assert %{audio: "audio", codecs: _codecs, resolution: {240, 136}} = + Enum.find(items, &is_struct(&1, ExM3U8.Tags.Stream)) + else + assert %{audio: nil, codecs: _codecs, resolution: {240, 136}} = + Enum.find(items, &is_struct(&1, ExM3U8.Tags.Stream)) + end + + if audio? do + assert_media_playlist(hls_path, "audio", 3, 5) + end - assert_media_playlist(hls_path, "audio", 3, 5) assert_media_playlist(hls_path, "video", 2, 5) end @@ -182,20 +220,21 @@ defmodule Shinkai.PipelineTest do end defp start_rtsp_server(other_options \\ []) do - default_options = - [ - port: 0, - files: [%{path: "/test", location: "test/fixtures/big_buck_avc_aac.mp4"}], - rate_control: true - ] - |> Keyword.merge(other_options) - + files = + @fixtures + |> Enum.with_index(1) + |> Enum.map(fn {fixture, idx} -> + %{path: "/test#{idx}", location: fixture} + end) + + default_options = Keyword.merge([port: 0, files: files, rate_control: true], other_options) {:ok, pid} = FileServer.start_link(default_options) pid end - defp rtsp_uri(server) do + defp rtsp_uri(server, fixture) do + idx = Enum.find_index(@fixtures, &(&1 == fixture)) + 1 {:ok, port} = FileServer.port_number(server) - "rtsp://127.0.0.1:#{port}/test" + "rtsp://127.0.0.1:#{port}/test#{idx}" end end diff --git a/test/support/rtmp/mp4_to_flv.ex b/test/support/rtmp/mp4_to_flv.ex index e10dec7..4ea96eb 100644 --- a/test/support/rtmp/mp4_to_flv.ex +++ b/test/support/rtmp/mp4_to_flv.ex @@ -45,6 +45,17 @@ defmodule Shinkai.RTMP.Server.Mp4ToFlv do |> Tag.Serializer.serialize() end + defp flv_init_tag(%{media: :av1} = track) do + av1c = ExMP4.Box.serialize(track.priv_data) + + Tag.Serializer.serialize(%Tag.ExVideoData{ + codec_id: :av1, + packet_type: :sequence_start, + frame_type: :keyframe, + data: binary_part(av1c, 8, byte_size(av1c) - 8) + }) + end + defp flv_init_tag(%{media: :aac} = track) do [descriptor] = MediaCodecs.MPEG4.parse_descriptors(track.priv_data.es_descriptor) @@ -54,6 +65,16 @@ defmodule Shinkai.RTMP.Server.Mp4ToFlv do |> Tag.Serializer.serialize() end + defp flv_init_tag(%{media: :opus} = track) do + dops = ExMP4.Box.serialize(track.priv_data) + + Tag.Serializer.serialize(%Tag.ExAudioData{ + codec_id: :opus, + packet_type: :sequence_start, + data: binary_part(dops, 8, byte_size(dops) - 8) + }) + end + defp video_sample_tag(sample, timescale) do dts = ExMP4.Helper.timescalify(sample.dts, timescale, :millisecond) pts = ExMP4.Helper.timescalify(sample.pts, timescale, :millisecond) diff --git a/test/support/rtsp/publisher.ex b/test/support/rtsp/publisher.ex new file mode 100644 index 0000000..c67cb06 --- /dev/null +++ b/test/support/rtsp/publisher.ex @@ -0,0 +1,172 @@ +defmodule Shinkai.RTSP.Publisher do + @moduledoc false + + alias ExMP4.Reader + alias RTSP.RTP.Encoder + + @spec new(String.t(), String.t()) :: map() + def new(rtsp_url, file) do + {:ok, rtsp} = Membrane.RTSP.start_link(rtsp_url) + reader = Reader.new!(file) + %{rtsp: rtsp, reader: reader} + end + + def publish(state) do + tracks = Reader.tracks(state.reader) + announce_tracks(state.rtsp, tracks) + sockets = setup(state.rtsp, tracks) + {:ok, %{status: 200}} = Membrane.RTSP.record(state.rtsp) + + ctx = + Map.new(tracks, fn track -> + {payloader, payloader_state} = init_payloader(track) + + {track.id, + %{ + track: track, + payloader: payloader, + payloader_state: payloader_state, + rtp_socket: sockets[track.id] + }} + end) + + ctx = + state.reader + |> Reader.stream() + |> Stream.map(&Reader.read_sample(state.reader, &1)) + |> Enum.reduce(ctx, fn sample, ctx -> + c = ctx[sample.track_id] + + {rtp_packets, new_payloader_state} = + c.payloader.handle_sample( + payload(c.track, sample.payload), + sample.pts, + c.payloader_state + ) + + Enum.each(rtp_packets, &:gen_udp.send(c.rtp_socket, ExRTP.Packet.encode(&1))) + Map.put(ctx, sample.track_id, %{c | payloader_state: new_payloader_state}) + end) + + Enum.each(ctx, fn {_track_id, c} -> + if function_exported?(c.payloader, :flush, 1) do + c.payloader_state + |> c.payloader.flush() + |> Enum.each(&:gen_udp.send(c.rtp_socket, ExRTP.Packet.encode(&1))) + end + + :gen_udp.close(c.rtp_socket) + end) + + Membrane.RTSP.close(state.rtsp) + end + + defp announce_tracks(rtsp, tracks) do + sdp = %ExSDP{ + origin: %ExSDP.Origin{session_id: 0, session_version: 0, address: {127, 0, 0, 1}}, + media: Enum.map(tracks, &sdp_media/1) + } + + {:ok, %{status: 200}} = + Membrane.RTSP.announce(rtsp, [{"content-type", "application/sdp"}], to_string(sdp)) + end + + defp setup(rtsp, tracks) do + Map.new(tracks, fn track -> + {:ok, rtp_socket} = :gen_udp.open(0, [:binary, active: false]) + {:ok, port} = :inet.port(rtp_socket) + + {:ok, %{status: 200} = resp} = + Membrane.RTSP.setup(rtsp, "track=#{track.id}", [ + {"Transport", "RTP/AVP;unicast;client_port=#{port}-#{port + 1};mode=record"} + ]) + + {:ok, transport} = Membrane.RTSP.Response.get_header(resp, "Transport") + + [_, rtp_port, _] = Regex.run(~r/server_port=(\d+)-(\d+)/, transport) + :gen_udp.connect(rtp_socket, {127, 0, 0, 1}, String.to_integer(rtp_port)) + + {track.id, rtp_socket} + end) + end + + defp sdp_media(%ExMP4.Track{} = track) do + pt = 95 + track.id + + %ExSDP.Media{ + type: track.type, + protocol: "RTP/AVP", + fmt: [pt], + port: 0, + attributes: [ + {"control", "track=#{track.id}"}, + fmtp(track, pt), + %ExSDP.Attribute.RTPMapping{ + payload_type: pt, + clock_rate: track.timescale, + encoding: encoding(track.media), + params: if(track.type == :audio, do: "2") + } + ] + } + end + + defp encoding(:aac), do: "MPEG4-GENERIC" + defp encoding(codec), do: String.upcase(to_string(codec)) + + defp fmtp(%{media: :h264} = track, pt) do + sps = List.first(track.priv_data.sps) + pps = List.first(track.priv_data.pps) + + %ExSDP.Attribute.FMTP{ + pt: pt, + packetization_mode: 1, + sprop_parameter_sets: %{sps: sps, pps: pps} + } + end + + defp fmtp(%{media: :h265} = track, pt) do + %ExSDP.Attribute.FMTP{ + pt: pt, + sprop_vps: track.priv_data.vps, + sprop_sps: track.priv_data.sps, + sprop_pps: track.priv_data.pps + } + end + + defp fmtp(%{media: :av1} = track, pt) do + %ExSDP.Attribute.FMTP{pt: pt, profile_id: track.priv_data.seq_profile} + end + + defp fmtp(%{media: :aac} = track, pt) do + [descriptor] = MediaCodecs.MPEG4.parse_descriptors(track.priv_data.es_descriptor) + asc = descriptor.dec_config_descr.decoder_specific_info + + "fmtp:#{pt} mode=AAC-hbr; sizeLength=13; indexLength=3; indexDeltaLength=3; constantDuration=1024; config=#{Base.encode16(asc, case: :upper)}" + end + + defp fmtp(%{media: :opus}, pt) do + %ExSDP.Attribute.FMTP{pt: pt, stereo: true} + end + + defp init_payloader(%{media: :h264, id: id}), + do: {Encoder.H264, Encoder.H264.init(payload_type: 95 + id)} + + defp init_payloader(%{media: :h265, id: id}), + do: {Encoder.H265, Encoder.H265.init(payload_type: 95 + id)} + + defp init_payloader(%{media: :av1, id: id}), + do: {Encoder.AV1, Encoder.AV1.init(payload_type: 95 + id)} + + defp init_payloader(%{media: :opus, id: id}), + do: {Encoder.Opus, Encoder.Opus.init(payload_type: 95 + id)} + + defp init_payloader(%{media: :aac, id: id}), + do: {Encoder.MPEG4Audio, Encoder.MPEG4Audio.init(payload_type: 95 + id, mode: :hbr)} + + defp payload(%{media: media}, payload) when media in [:h264, :h265] do + for <>, do: nalu + end + + defp payload(_track, payload), do: payload +end From 663a1a93b052ac9b506fddd22e3f8e261b83cc02 Mon Sep 17 00:00:00 2001 From: Billal GHILAS Date: Fri, 23 Jan 2026 16:21:09 +0100 Subject: [PATCH 5/7] Fix tests --- lib/shinkai/sink/rtmp.ex | 20 ++++--- mix.lock | 8 +-- test/shinkai/pipeline_test.exs | 101 +++++++++++++++++++------------- test/support/rtmp/mp4_to_flv.ex | 23 ++++++-- 4 files changed, 95 insertions(+), 57 deletions(-) diff --git a/lib/shinkai/sink/rtmp.ex b/lib/shinkai/sink/rtmp.ex index 6784ca1..e628888 100644 --- a/lib/shinkai/sink/rtmp.ex +++ b/lib/shinkai/sink/rtmp.ex @@ -79,14 +79,20 @@ defmodule Shinkai.Sink.RTMP do def handle_info({:packet, packets}, state) do Registry.dispatch(Sink.Registry, {:rtmp, state.source_id}, fn entries -> packets = List.wrap(packets) - track = state.tracks[hd(packets).track_id] - tags = Enum.map(packets, &packet_to_tag(track, &1)) - for {pid, _} <- entries, {timestamp, data} <- tags do - case track.type do - :video -> ClientSession.send_video_data(pid, timestamp, data) - :audio -> ClientSession.send_audio_data(pid, timestamp, data) - end + case state.tracks[hd(packets).track_id] do + nil -> + :ok + + track -> + tags = Enum.map(packets, &packet_to_tag(track, &1)) + + for {pid, _} <- entries, {timestamp, data} <- tags do + case track.type do + :video -> ClientSession.send_video_data(pid, timestamp, data) + :audio -> ClientSession.send_audio_data(pid, timestamp, data) + end + end end end) diff --git a/mix.lock b/mix.lock index ff5f0f0..3e1d075 100644 --- a/mix.lock +++ b/mix.lock @@ -1,12 +1,12 @@ %{ - "bandit": {:hex, :bandit, "1.10.1", "6b1f8609d947ae2a74da5bba8aee938c94348634e54e5625eef622ca0bbbb062", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b4c35f273030e44268ace53bf3d5991dfc385c77374244e2f960876547671aa"}, + "bandit": {:hex, :bandit, "1.10.2", "d15ea32eb853b5b42b965b24221eb045462b2ba9aff9a0bda71157c06338cbff", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "27b2a61b647914b1726c2ced3601473be5f7aa6bb468564a688646a689b3ee45"}, "bunch": {:hex, :bunch, "1.6.1", "5393d827a64d5f846092703441ea50e65bc09f37fd8e320878f13e63d410aec7", [:mix], [], "hexpm", "286cc3add551628b30605efbe2fca4e38cc1bea89bcd0a1a7226920b3364fe4a"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "coerce": {:hex, :coerce, "1.0.2", "5ef791040c92baaa5dd344887563faaeac6e6742573a167493294f8af3672bbe", [:mix], [], "hexpm", "0b3451c729571234fdac478636c298e71d1f2ce1243abed5fa43fa3181b980eb"}, "credo": {:hex, :credo, "1.7.15", "283da72eeb2fd3ccf7248f4941a0527efb97afa224bcdef30b4b580bc8258e1c", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "291e8645ea3fea7481829f1e1eb0881b8395db212821338e577a90bf225c5607"}, "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, "elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"}, - "ex_doc": {:hex, :ex_doc, "0.39.3", "519c6bc7e84a2918b737aec7ef48b96aa4698342927d080437f61395d361dcee", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "0590955cf7ad3b625780ee1c1ea627c28a78948c6c0a9b0322bd976a079996e1"}, + "ex_doc": {:hex, :ex_doc, "0.40.0", "2635974389b80fd3ca61b0f993d459dad05b4a8f9b069dcfbbc5f6a8a6aef60e", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "c040735250e2752b6e1102eeb4aa3f1dca74c316db873ae09f955d42136e7e5b"}, "ex_flv": {:hex, :ex_flv, "0.4.0", "9e43c833b5cbe3c6e21bb2651ae7650f3ec939eac8079f34efed8f813bf9133d", [:mix], [], "hexpm", "484f6990791e0c8862a88e4150f004deb067c7342e40b779c82d5c9a9c057969"}, "ex_m3u8": {:hex, :ex_m3u8, "0.15.4", "66f6ec7e4fb7372c48032db1c2d4a3e6c2bbbde2d1d9a1098986e3caa0ab7a55", [:mix], [{:nimble_parsec, "~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:typed_struct, "~> 0.3.0", [hex: :typed_struct, repo: "hexpm", optional: false]}], "hexpm", "ec03aa516919e0c8ec202da55f609b763bd7960195a3388900090fcad270c873"}, "ex_mp4": {:hex, :ex_mp4, "0.14.2", "c362b27c50fa8d5a16e4f5652963fcc47d5a61215eb729a0d6f8ec521575ed6d", [:mix], [{:media_codecs, "~> 0.10.0", [hex: :media_codecs, repo: "hexpm", optional: true]}, {:ratio, "~> 4.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:table_rex, "~> 4.0", [hex: :table_rex, repo: "hexpm", optional: true]}], "hexpm", "3712c62a93ddde83419bb22e382a145c6527c8b002d8a22348202828022e1041"}, @@ -25,7 +25,7 @@ "membrane_rtsp": {:hex, :membrane_rtsp, "0.11.0", "887b1c0cd4f40f6ce93880bfa1a1e8c9e250aabb24810a8fe2a7556bb54c29c4", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 0.17.0 or ~> 1.0", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:mockery, "~> 2.3", [hex: :mockery, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.4.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "69252d77ad3df48e6cb21fc16b0c5730607709714ad7849b7635813f9741ee2f"}, "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, "mockery": {:hex, :mockery, "2.5.0", "a87acd74fd733aa3b9cb5663d6f690178b056608f2652f18e4ec423ddd5496ed", [:mix], [], "hexpm", "52492b2eba61055df1c626e894663b624b5e6fdfaaaba1d9a8596236fbf4da69"}, - "mpeg_ts": {:hex, :mpeg_ts, "3.3.8", "3ef910d840cc2c7cb8998c5982b53d166ed207473c918cec3d4988ebf14fdd00", [:mix], [], "hexpm", "9e3ecbadcad9bfcae3c7be53e78b620068f361daac9114115c9490c79050aeab"}, + "mpeg_ts": {:hex, :mpeg_ts, "3.3.11", "77d69c5599fcd6eadef926b03cf6fe990dd76301ec41ce77de71bc84ad53412c", [:mix], [], "hexpm", "e1554e7b2ffe5692effca19173200fdee0959bd40d201ec920a950054c27cb76"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "numbers": {:hex, :numbers, "5.2.4", "f123d5bb7f6acc366f8f445e10a32bd403c8469bdbce8ce049e1f0972b607080", [:mix], [{:coerce, "~> 1.0", [hex: :coerce, repo: "hexpm", optional: false]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "eeccf5c61d5f4922198395bf87a465b6f980b8b862dd22d28198c5e6fab38582"}, @@ -34,7 +34,7 @@ "plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"}, "qex": {:hex, :qex, "0.5.1", "0d82c0f008551d24fffb99d97f8299afcb8ea9cf99582b770bd004ed5af63fd6", [:mix], [], "hexpm", "935a39fdaf2445834b95951456559e9dc2063d0a055742c558a99987b38d6bab"}, "ratio": {:hex, :ratio, "4.0.1", "3044166f2fc6890aa53d3aef0c336f84b2bebb889dc57d5f95cc540daa1912f8", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:numbers, "~> 5.2.0", [hex: :numbers, repo: "hexpm", optional: false]}], "hexpm", "c60cbb3ccdff9ffa56e7d6d1654b5c70d9f90f4d753ab3a43a6bf40855b881ce"}, - "rtsp": {:hex, :rtsp, "0.8.0", "1e70337387eaed5f6de67997010b690633c1df7a178acf144974908eaf8f742d", [:mix], [{:ex_mp4, "~> 0.14.0", [hex: :ex_mp4, repo: "hexpm", optional: true]}, {:ex_rtcp, "~> 0.4.0", [hex: :ex_rtcp, repo: "hexpm", optional: false]}, {:ex_rtp, "~> 0.4.0", [hex: :ex_rtp, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 1.0", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:media_codecs, "~> 0.10.0", [hex: :media_codecs, repo: "hexpm", optional: false]}, {:membrane_rtsp, "~> 0.11.0", [hex: :membrane_rtsp, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}], "hexpm", "808670602b19fa8a4568d8557bbede6baf8170ccd7303bddc0d581540700f62c"}, + "rtsp": {:hex, :rtsp, "0.8.1", "4bffebfcb0e1354283567178c040bbf40a85c4fbbde6d23addbbc7672cb3c700", [:mix], [{:ex_mp4, "~> 0.14.0", [hex: :ex_mp4, repo: "hexpm", optional: true]}, {:ex_rtcp, "~> 0.4.0", [hex: :ex_rtcp, repo: "hexpm", optional: false]}, {:ex_rtp, "~> 0.4.0", [hex: :ex_rtp, repo: "hexpm", optional: false]}, {:ex_sdp, "~> 1.0", [hex: :ex_sdp, repo: "hexpm", optional: false]}, {:media_codecs, "~> 0.10.0", [hex: :media_codecs, repo: "hexpm", optional: false]}, {:membrane_rtsp, "~> 0.11.0", [hex: :membrane_rtsp, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}], "hexpm", "b4af3c30b8f79dd642940452c6ad6727bfd1df492e5ddbc1eb705f25df6f4053"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "thousand_island": {:hex, :thousand_island, "1.4.3", "2158209580f633be38d43ec4e3ce0a01079592b9657afff9080d5d8ca149a3af", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6e4ce09b0fd761a58594d02814d40f77daff460c48a7354a15ab353bb998ea0b"}, "typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"}, diff --git a/test/shinkai/pipeline_test.exs b/test/shinkai/pipeline_test.exs index e6e3bca..6bcc383 100644 --- a/test/shinkai/pipeline_test.exs +++ b/test/shinkai/pipeline_test.exs @@ -31,7 +31,6 @@ defmodule Shinkai.PipelineTest do assert_receive {:hls, :done}, 5_000 hls_path = Path.join(Shinkai.Config.get_config(:hls)[:storage_dir], source.id) - audio? = not String.contains?(unquote(fixture), "opus") assert_hls(hls_path, audio?) @@ -79,60 +78,78 @@ defmodule Shinkai.PipelineTest do end end - describe "rtmp sink" do - test "Stream from rtsp", %{tmp_dir: _dir} do - server = start_rtsp_server() - source = %Source{id: UUID.uuid4(), type: :rtsp, uri: rtsp_uri(server, "test")} - - {:ok, rtmp_server} = ExRTMP.Server.start(port: 0, handler: Shinkai.Sources.RTMP.Handler) - start_source(source) - - # Wait for the RTMP sink to receive tracks - Process.sleep(150) + for fixture <- @fixtures do + describe "rtmp sink: #{fixture}" do + test "Stream from rtsp" do + server = start_rtsp_server() + source = %Source{id: UUID.uuid4(), type: :rtsp, uri: rtsp_uri(server, unquote(fixture))} - {:ok, pid} = ExRTMP.Client.start_link(uri: rtmp_uri(rtmp_server), stream_key: source.id) - assert :ok = ExRTMP.Client.connect(pid) - assert :ok = ExRTMP.Client.play(pid) + {:ok, rtmp_server} = ExRTMP.Server.start(port: 0, handler: Shinkai.Sources.RTMP.Handler) + start_source(source) - assert_rtmp_receive(pid) + # Wait for the RTMP sink to receive tracks + Process.sleep(150) - ExRTMP.Server.stop(rtmp_server) - end + {:ok, pid} = ExRTMP.Client.start_link(uri: rtmp_uri(rtmp_server), stream_key: source.id) + assert :ok = ExRTMP.Client.connect(pid) + assert :ok = ExRTMP.Client.play(pid) - test "Stream from rtmp" do - {:ok, rtmp_server} = - ExRTMP.Server.start( - port: 0, - handler: Shinkai.RTMP.Server.Handler, - handler_options: [fixture: "test/fixtures/big_buck_avc_aac.mp4"] - ) + assert_rtmp_receive(pid, unquote(fixture)) - id = UUID.uuid4() + ExRTMP.Server.stop(rtmp_server) + end - source = %Source{id: "live-#{id}", type: :rtmp, uri: rtmp_uri(rtmp_server, "live/#{id}")} + test "Stream from rtmp" do + {:ok, rtmp_server} = + ExRTMP.Server.start( + port: 0, + handler: Shinkai.RTMP.Server.Handler, + handler_options: [fixture: unquote(fixture)] + ) - _pid = start_supervised!({Shinkai.Pipeline, source}) + id = UUID.uuid4() - {:ok, pid} = ExRTMP.Client.start_link(uri: rtmp_uri(rtmp_server, "live"), stream_key: id) - assert :ok = ExRTMP.Client.connect(pid) - assert :ok = ExRTMP.Client.play(pid) + source = %Source{id: "live-#{id}", type: :rtmp, uri: rtmp_uri(rtmp_server, "live/#{id}")} + start_source(source) - assert_rtmp_receive(pid) + # _pid = start_supervised!({Shinkai.Pipeline, source}) - ExRTMP.Server.stop(rtmp_server) - end + {:ok, pid} = ExRTMP.Client.start_link(uri: rtmp_uri(rtmp_server, "live"), stream_key: id) + assert :ok = ExRTMP.Client.connect(pid) + assert :ok = ExRTMP.Client.play(pid) - defp assert_rtmp_receive(pid) do - assert_receive {:video, ^pid, {:codec, :h264, _dcr}}, 1000 - assert_receive {:audio, ^pid, {:codec, :aac, _}}, 1000 + assert_rtmp_receive(pid, unquote(fixture)) - for _i <- 1..20 do - assert_receive {:video, ^pid, {:sample, payload, _dts, _pts, keyframe?}}, 1000 - assert_receive {:audio, ^pid, {:sample, data, _dts}}, 1000 + ExRTMP.Server.stop(rtmp_server) + end - assert is_list(payload) - assert is_binary(data) - assert is_boolean(keyframe?) + defp assert_rtmp_receive(pid, fixture) do + {video_codec, audio_codec} = + case fixture do + "test/fixtures/big_buck_avc_aac.mp4" -> {:h264, :aac} + _ -> {:av1, nil} + end + + if video_codec do + assert_receive {:video, ^pid, {:codec, ^video_codec, _dcr}}, 1000 + end + + if audio_codec do + assert_receive {:audio, ^pid, {:codec, ^audio_codec, _}}, 1000 + end + + for _i <- 1..20 do + if video_codec do + assert_receive {:video, ^pid, {:sample, payload, _dts, _pts, keyframe?}}, 1000 + assert is_list(payload) or is_binary(payload) + assert is_boolean(keyframe?) + end + + if audio_codec do + assert_receive {:audio, ^pid, {:sample, data, _dts}}, 1000 + assert is_binary(data) + end + end end end end diff --git a/test/support/rtmp/mp4_to_flv.ex b/test/support/rtmp/mp4_to_flv.ex index 4ea96eb..b5bdb90 100644 --- a/test/support/rtmp/mp4_to_flv.ex +++ b/test/support/rtmp/mp4_to_flv.ex @@ -25,7 +25,7 @@ defmodule Shinkai.RTMP.Server.Mp4ToFlv do |> Stream.map(&Reader.read_sample(reader, &1)) |> Enum.each(fn sample -> if sample.track_id == video_track.id do - {dts, tag} = video_sample_tag(sample, video_track.timescale) + {dts, tag} = video_sample_tag(sample, video_track) ClientSession.send_video_data(rtmp_client, dts, tag) else {dts, tag} = audio_sample_tag(sample, audio_track.timescale) @@ -75,9 +75,24 @@ defmodule Shinkai.RTMP.Server.Mp4ToFlv do }) end - defp video_sample_tag(sample, timescale) do - dts = ExMP4.Helper.timescalify(sample.dts, timescale, :millisecond) - pts = ExMP4.Helper.timescalify(sample.pts, timescale, :millisecond) + defp video_sample_tag(sample, %{media: codec} = track) when codec in [:h265, :av1] do + dts = ExMP4.Helper.timescalify(sample.dts, track.timescale, :millisecond) + pts = ExMP4.Helper.timescalify(sample.pts, track.timescale, :millisecond) + + sample = + Tag.Serializer.serialize(%Tag.ExVideoData{ + codec_id: codec, + composition_time_offset: pts - dts, + packet_type: :coded_frames, + frame_type: if(sample.sync?, do: :keyframe, else: :interframe) + }) + + {dts, sample} + end + + defp video_sample_tag(sample, track) do + dts = ExMP4.Helper.timescalify(sample.dts, track.timescale, :millisecond) + pts = ExMP4.Helper.timescalify(sample.pts, track.timescale, :millisecond) sample = sample.payload From 088cd893aa70b408b03d8ea452fd0fc858ee014d Mon Sep 17 00:00:00 2001 From: Billal GHILAS Date: Fri, 23 Jan 2026 16:23:24 +0100 Subject: [PATCH 6/7] Fix tests again --- test/shinkai/pipeline_test.exs | 58 +++++++++++++++++----------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/test/shinkai/pipeline_test.exs b/test/shinkai/pipeline_test.exs index 6bcc383..a8a03b2 100644 --- a/test/shinkai/pipeline_test.exs +++ b/test/shinkai/pipeline_test.exs @@ -122,35 +122,6 @@ defmodule Shinkai.PipelineTest do ExRTMP.Server.stop(rtmp_server) end - - defp assert_rtmp_receive(pid, fixture) do - {video_codec, audio_codec} = - case fixture do - "test/fixtures/big_buck_avc_aac.mp4" -> {:h264, :aac} - _ -> {:av1, nil} - end - - if video_codec do - assert_receive {:video, ^pid, {:codec, ^video_codec, _dcr}}, 1000 - end - - if audio_codec do - assert_receive {:audio, ^pid, {:codec, ^audio_codec, _}}, 1000 - end - - for _i <- 1..20 do - if video_codec do - assert_receive {:video, ^pid, {:sample, payload, _dts, _pts, keyframe?}}, 1000 - assert is_list(payload) or is_binary(payload) - assert is_boolean(keyframe?) - end - - if audio_codec do - assert_receive {:audio, ^pid, {:sample, data, _dts}}, 1000 - assert is_binary(data) - end - end - end end end @@ -204,6 +175,35 @@ defmodule Shinkai.PipelineTest do assert_media_playlist(hls_path, "video", 2, 5) end + defp assert_rtmp_receive(pid, fixture) do + {video_codec, audio_codec} = + case fixture do + "test/fixtures/big_buck_avc_aac.mp4" -> {:h264, :aac} + _ -> {:av1, nil} + end + + if video_codec do + assert_receive {:video, ^pid, {:codec, ^video_codec, _dcr}}, 1000 + end + + if audio_codec do + assert_receive {:audio, ^pid, {:codec, ^audio_codec, _}}, 1000 + end + + for _i <- 1..20 do + if video_codec do + assert_receive {:video, ^pid, {:sample, payload, _dts, _pts, keyframe?}}, 1000 + assert is_list(payload) or is_binary(payload) + assert is_boolean(keyframe?) + end + + if audio_codec do + assert_receive {:audio, ^pid, {:sample, data, _dts}}, 1000 + assert is_binary(data) + end + end + end + defp rtmp_uri(server, path \\ "") do {:ok, port} = ExRTMP.Server.port(server) "rtmp://127.0.0.1:#{port}/#{path}" From 5f729ea5ce4eaf69ffbd110844da9bf07604b64c Mon Sep 17 00:00:00 2001 From: Billal GHILAS Date: Fri, 23 Jan 2026 16:29:42 +0100 Subject: [PATCH 7/7] Make credo happy --- lib/shinkai/sink/rtmp.ex | 21 +++++++++++++-------- test/shinkai/pipeline_test.exs | 7 ++++--- test/support/rtsp/publisher.ex | 7 ++++--- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/shinkai/sink/rtmp.ex b/lib/shinkai/sink/rtmp.ex index e628888..d56a9ed 100644 --- a/lib/shinkai/sink/rtmp.ex +++ b/lib/shinkai/sink/rtmp.ex @@ -85,14 +85,7 @@ defmodule Shinkai.Sink.RTMP do :ok track -> - tags = Enum.map(packets, &packet_to_tag(track, &1)) - - for {pid, _} <- entries, {timestamp, data} <- tags do - case track.type do - :video -> ClientSession.send_video_data(pid, timestamp, data) - :audio -> ClientSession.send_audio_data(pid, timestamp, data) - end - end + dispatch_packets(entries, packets, track) end end) @@ -112,6 +105,18 @@ defmodule Shinkai.Sink.RTMP do {:noreply, state} end + defp dispatch_packets(entries, packets, track) do + tags = Enum.map(packets, &packet_to_tag(track, &1)) + + for {pid, _} <- entries, {timestamp, data} <- tags do + # credo:disable-for-next-line + case track.type do + :video -> ClientSession.send_video_data(pid, timestamp, data) + :audio -> ClientSession.send_audio_data(pid, timestamp, data) + end + end + end + defp packet_to_tag(track, packet) do dts = div(packet.dts * @timescale, track.timescale) cts = div((packet.pts - packet.dts) * @timescale, track.timescale) diff --git a/test/shinkai/pipeline_test.exs b/test/shinkai/pipeline_test.exs index a8a03b2..51adb95 100644 --- a/test/shinkai/pipeline_test.exs +++ b/test/shinkai/pipeline_test.exs @@ -3,6 +3,7 @@ defmodule Shinkai.PipelineTest do alias ExM3U8.Tags alias RTSP.FileServer + alias Shinkai.RTSP.Publisher alias Shinkai.Sources.Source alias Shinkai.Utils @@ -41,8 +42,8 @@ defmodule Shinkai.PipelineTest do id = UUID.uuid4() Phoenix.PubSub.subscribe(Shinkai.PubSub, Utils.sink_topic(id)) - publisher = Shinkai.RTSP.Publisher.new("rtsp://localhost:8554/#{id}", unquote(fixture)) - Shinkai.RTSP.Publisher.publish(publisher) + Publisher.new("rtsp://localhost:8554/#{id}", unquote(fixture)) + |> Publisher.publish() assert_receive {:hls, :done}, 5_000 @@ -152,7 +153,7 @@ defmodule Shinkai.PipelineTest do items: items } = multivariabt_playlist - assert length(items) == [audio?, video?] |> Enum.filter(& &1) |> Enum.count() + assert length(items) == Enum.count([audio?, video?], & &1) if audio? do assert %{type: :audio, group_id: "audio"} = diff --git a/test/support/rtsp/publisher.ex b/test/support/rtsp/publisher.ex index c67cb06..8402fd4 100644 --- a/test/support/rtsp/publisher.ex +++ b/test/support/rtsp/publisher.ex @@ -2,6 +2,7 @@ defmodule Shinkai.RTSP.Publisher do @moduledoc false alias ExMP4.Reader + alias Membrane.RTSP, as: MRTSP alias RTSP.RTP.Encoder @spec new(String.t(), String.t()) :: map() @@ -15,7 +16,7 @@ defmodule Shinkai.RTSP.Publisher do tracks = Reader.tracks(state.reader) announce_tracks(state.rtsp, tracks) sockets = setup(state.rtsp, tracks) - {:ok, %{status: 200}} = Membrane.RTSP.record(state.rtsp) + {:ok, %{status: 200}} = MRTSP.record(state.rtsp) ctx = Map.new(tracks, fn track -> @@ -77,11 +78,11 @@ defmodule Shinkai.RTSP.Publisher do {:ok, port} = :inet.port(rtp_socket) {:ok, %{status: 200} = resp} = - Membrane.RTSP.setup(rtsp, "track=#{track.id}", [ + MRTSP.setup(rtsp, "track=#{track.id}", [ {"Transport", "RTP/AVP;unicast;client_port=#{port}-#{port + 1};mode=record"} ]) - {:ok, transport} = Membrane.RTSP.Response.get_header(resp, "Transport") + {:ok, transport} = MRTSP.Response.get_header(resp, "Transport") [_, rtp_port, _] = Regex.run(~r/server_port=(\d+)-(\d+)/, transport) :gen_udp.connect(rtp_socket, {127, 0, 0, 1}, String.to_integer(rtp_port))