From f72ae03f9b91ed8aa72f6b6e2201d95088e81a08 Mon Sep 17 00:00:00 2001 From: Mayel de Borniol <115318+mayel@users.noreply.github.com> Date: Fri, 6 Oct 2023 19:35:59 +0100 Subject: [PATCH] add PirateWeather data source (based on DarkSky API) (#24) * mv module * add PirateWeather data source (based on DarkSky) * switch to Jason + updates deps + fix warnings and format --- config/config.exs | 2 +- lib/forecastr/geocoder.ex | 2 +- lib/forecastr/owm/owm.ex | 2 +- lib/forecastr/pirate_weather.ex | 161 ++++++++++++++++++++ lib/forecastr/renderer/{ => giphy}/giphy.ex | 13 +- lib/forecastr/renderer/giphy/http.ex | 2 +- mix.exs | 2 +- mix.lock | 20 +-- 8 files changed, 186 insertions(+), 18 deletions(-) create mode 100644 lib/forecastr/pirate_weather.ex rename lib/forecastr/renderer/{ => giphy}/giphy.ex (80%) diff --git a/config/config.exs b/config/config.exs index 9001d10..7c84a36 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,4 +1,4 @@ -import Mix.Config +import Config config :forecastr, appid: System.get_env("FORECASTR_API_KEY"), diff --git a/lib/forecastr/geocoder.ex b/lib/forecastr/geocoder.ex index d8fcb6e..59fb090 100644 --- a/lib/forecastr/geocoder.ex +++ b/lib/forecastr/geocoder.ex @@ -15,7 +15,7 @@ defmodule Forecastr.Geocoder do end defp parse_request(%HTTPoison.Response{body: body}) do - Poison.decode!(body) + Jason.decode!(body) end defp geocode_with_osm(path, params) do diff --git a/lib/forecastr/owm/owm.ex b/lib/forecastr/owm/owm.ex index 50d1544..d2567f6 100644 --- a/lib/forecastr/owm/owm.ex +++ b/lib/forecastr/owm/owm.ex @@ -82,7 +82,7 @@ defmodule Forecastr.OWM do case Forecastr.OWM.HTTP.get(endpoint, [], params: params) do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> - {:ok, Poison.decode!(body)} + {:ok, Jason.decode!(body)} {:ok, %HTTPoison.Response{status_code: 404}} -> {:error, :not_found} diff --git a/lib/forecastr/pirate_weather.ex b/lib/forecastr/pirate_weather.ex new file mode 100644 index 0000000..a69e717 --- /dev/null +++ b/lib/forecastr/pirate_weather.ex @@ -0,0 +1,161 @@ +defmodule Forecastr.PirateWeather do + @moduledoc false + + alias Forecastr.Geocoder + + @type when_to_forecast :: :today | :next_days + @spec weather(when_to_forecast, String.t(), map()) :: {:ok, map()} | {:error, atom()} + def weather(when_to_forecast, query, opts) do + case api_endpoint(when_to_forecast) do + nil -> + {:error, :no_api_key} + + endpoint -> + params = convert_params(opts) + + %{ + "lat" => lat, + "lon" => lon, + "address" => %{ + "city" => city, + "country" => country + } + } = + query + |> Geocoder.geocode() + |> pick_location() + + with {:ok, forecast} <- fetch_weather_information(endpoint <> "/#{lat},#{lon}", params) do + {:ok, + forecast + |> add("name", city) + |> add("country", country) + |> add("when_to_forecast", Atom.to_string(when_to_forecast))} + end + end + end + + @spec normalize(map()) :: {:ok, map()} + @doc """ + Normalize for today's weather or for the next 3 days weather + """ + def normalize(%{ + "when_to_forecast" => "today", + "name" => name, + "country" => country, + "latitude" => lat, + "longitude" => lon, + "currently" => %{"temperature" => temp = temp_max = temp_min} = weather + }) do + normalized = + weather + |> extract_main_weather() + |> add("name", name) + |> add("country", country) + |> add("coordinates", %{"lat" => lat, "lon" => lon}) + |> add("temp", temp) + |> add("temp_max", temp_max) + |> add("temp_min", temp_min) + + {:ok, normalized} + end + + def normalize(%{ + "when_to_forecast" => "next_days", + "name" => name, + "country" => country, + "latitude" => lat, + "longitude" => lon, + "hourly" => %{"data" => forecast_list} + }) + when is_list(forecast_list) do + normalized = + Map.new() + |> add("name", name) + |> add("country", country) + |> add("coordinates", %{"lat" => lat, "lon" => lon}) + |> add("list", forecast_list |> Enum.map(&normalize_forecast_list/1)) + + {:ok, normalized} + end + + defp fetch_weather_information(endpoint, opts) do + case HTTPoison.get(endpoint, [], params: opts) do + {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> + {:ok, Jason.decode!(body)} + + {:ok, %HTTPoison.Response{status_code: 404}} -> + {:error, :not_found} + + {:ok, %HTTPoison.Response{status_code: 400}} -> + {:error, :not_found} + + {:ok, %HTTPoison.Response{status_code: 401}} -> + {:error, :api_key_invalid} + + error = {:error, _reason} -> + error + end + end + + defp extract_main_weather(weather) do + %{"summary" => main_weather_condition, "icon" => icon_name} = weather + %{"description" => main_weather_condition, "id" => icon_name} + end + + defp normalize_forecast_list(%{ + "summary" => main_weather_condition, + "icon" => icon, + "temperature" => temp = temp_max = temp_min, + "time" => time + }) do + date = time |> DateTime.from_unix!() |> DateTime.to_date() |> to_string() + time = time |> DateTime.from_unix!() |> DateTime.to_time() |> to_string() + + Map.new() + |> add("temp", temp) + |> add("temp_max", temp_max) + |> add("temp_min", temp_min) + |> add("dt_txt", "#{date} #{time}") + |> add("dt", time) + |> add("description", main_weather_condition) + |> add("id", icon) + end + + defp add(map, key, value) do + map + |> Map.put(key, value) + end + + @spec api_endpoint(when_to_forecast) :: String.t() + def api_endpoint(_) do + case Application.get_env(:forecastr, :appid) do + appid when is_binary(appid) and appid != "" -> + "https://api.pirateweather.net/forecast/#{appid}" + + _ -> + nil + end + end + + defp convert_params(%{units: :imperial} = params), do: Map.put(params, :units, "us") + defp convert_params(%{units: _} = params), do: Map.put(params, :units, "si") + defp convert_params(%{} = params), do: params + defp convert_params(params) when is_list(params), do: Map.new(params) |> convert_params() + + defp pick_location(%{"address" => %{"city" => _city}} = body), do: body + + defp pick_location(%{"address" => %{"town" => town}} = body), + do: put_in(body, ["address", "city"], town) + + defp pick_location(%{"address" => %{"village" => village}} = body), + do: put_in(body, ["address", "city"], village) + + defp pick_location(%{"address" => %{"province" => province}} = body), + do: put_in(body, ["address", "city"], province) + + defp pick_location(%{"address" => %{"suburb" => suburb}} = body), + do: put_in(body, ["address", "city"], suburb) + + defp pick_location({"address", address}), do: %{"address" => address} |> pick_location() +end diff --git a/lib/forecastr/renderer/giphy.ex b/lib/forecastr/renderer/giphy/giphy.ex similarity index 80% rename from lib/forecastr/renderer/giphy.ex rename to lib/forecastr/renderer/giphy/giphy.ex index 3aacdf3..4e73b4e 100644 --- a/lib/forecastr/renderer/giphy.ex +++ b/lib/forecastr/renderer/giphy/giphy.ex @@ -14,11 +14,18 @@ defmodule Forecastr.Renderer.Giphy do alias __MODULE__ @spec render(map(), units :: atom()) :: map() - def render(%{"description" => description} = map, units) do - Map.put(map, "giphy_pic", Enum.random(Giphy.HTTP.search(description))) + def render(%{"description" => description} = map, _units) do + Map.put( + map, + "giphy_pic", + case Giphy.HTTP.search(description) do + gifs when is_list(gifs) and gifs != [] -> Enum.random(gifs) + _ -> nil + end + ) end - def render(%{"list" => forecasts} = map, units) do + def render(%{"list" => forecasts} = map, _units) do %{map | "list" => giphy(forecasts)} end diff --git a/lib/forecastr/renderer/giphy/http.ex b/lib/forecastr/renderer/giphy/http.ex index de77d5b..d50bf13 100644 --- a/lib/forecastr/renderer/giphy/http.ex +++ b/lib/forecastr/renderer/giphy/http.ex @@ -17,7 +17,7 @@ defmodule Forecastr.Renderer.Giphy.HTTP do giphy_url |> HTTPoison.get!() |> Map.get(:body) - |> Poison.decode!() + |> Jason.decode!() |> extract_gif_urls() end diff --git a/mix.exs b/mix.exs index 962241b..679d9c5 100644 --- a/mix.exs +++ b/mix.exs @@ -32,7 +32,7 @@ defmodule Forecastr.MixProject do defp deps do [ {:httpoison, "~> 1.4"}, - {:poison, "~> 5.0"}, + {:jason, "~> 1.4"}, {:elbat, "~> 0.0.6"}, {:dialyxir, "~> 1.3.0", only: [:dev], runtime: false}, {:credo, "~> 1.5", only: [:dev, :test], runtime: false}, diff --git a/mix.lock b/mix.lock index fda9ca0..d714791 100644 --- a/mix.lock +++ b/mix.lock @@ -1,21 +1,21 @@ %{ "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, - "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, - "credo": {:hex, :credo, "1.7.0", "6119bee47272e85995598ee04f2ebbed3e947678dee048d10b5feca139435f75", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6839fcf63d1f0d1c0f450abc8564a57c43d644077ab96f2934563e68b8a769d7"}, + "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, + "credo": {:hex, :credo, "1.7.1", "6e26bbcc9e22eefbff7e43188e69924e78818e2fe6282487d0703652bc20fd62", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e9871c6095a4c0381c89b6aa98bc6260a8ba6addccf7f6a53da8849c748a58a2"}, "dialyxir": {:hex, :dialyxir, "1.3.0", "fd1672f0922b7648ff9ce7b1b26fcf0ef56dda964a459892ad15f6b4410b5284", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "00b2a4bcd6aa8db9dcb0b38c1225b7277dca9bc370b6438715667071a304696f"}, "earmark": {:hex, :earmark, "1.3.2", "b840562ea3d67795ffbb5bd88940b1bed0ed9fa32834915125ea7d02e35888a5", [:mix], [], "hexpm", "e3be2bc3ae67781db529b80aa7e7c49904a988596e2dbff897425b48b3581161"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.37", "2ad73550e27c8946648b06905a57e4d454e4d7229c2dafa72a0348c99d8be5f7", [:mix], [], "hexpm", "6b19783f2802f039806f375610faa22da130b8edc21209d0bff47918bb48360e"}, "elbat": {:hex, :elbat, "0.0.6", "35270ae629058435c0f705fc5b281662597fda0c1c0479080e35205d2758c6a5", [:mix], [], "hexpm", "74bbac013afe869123833273e5f26826fad453e17c09aeabcb7d8d0a74baf868"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.30.4", "e8395c8e3c007321abb30a334f9f7c0858d80949af298302daf77553468c0c39", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "9a19f0c50ffaa02435668f5242f2b2a61d46b541ebf326884505dfd3dd7af5e4"}, + "ex_doc": {:hex, :ex_doc, "0.30.6", "5f8b54854b240a2b55c9734c4b1d0dd7bdd41f71a095d42a70445c03cf05a281", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bd48f2ddacf4e482c727f9293d9498e0881597eae6ddc3d9562bd7923375109f"}, "exactor": {:hex, :exactor, "2.2.4", "5efb4ddeb2c48d9a1d7c9b465a6fffdd82300eb9618ece5d34c3334d5d7245b1", [:mix], [], "hexpm", "1222419f706e01bfa1095aec9acf6421367dcfab798a6f67c54cf784733cd6b5"}, - "excoveralls": {:hex, :excoveralls, "0.17.0", "279f124dba347903bb654bc40745c493ae265d45040001b4899ea1edf88078c7", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "08b638d114387a888f9cb8d65f2a0021ec04c3e447b793efa7c1e734aba93004"}, + "excoveralls": {:hex, :excoveralls, "0.17.1", "83fa7906ef23aa7fc8ad7ee469c357a63b1b3d55dd701ff5b9ce1f72442b2874", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "95bc6fda953e84c60f14da4a198880336205464e75383ec0f570180567985ae0"}, "exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "32e95820a97cffea67830e91514a2ad53b888850442d6d395f53a1ac60c82e07"}, - "exvcr": {:hex, :exvcr, "0.14.3", "e7d93b3b25919fbb653b06bc015cab99f658400eae96ed8e59758f1bb12ae167", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:finch, "~> 0.16", [hex: :finch, repo: "hexpm", optional: true]}, {:httpoison, "~> 1.0 or ~> 2.0", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.1", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "38fa7d918aeda0ecc8e70346225c1299d21d4c432061c832f23a421ac2ed791d"}, + "exvcr": {:hex, :exvcr, "0.14.4", "1aa5fe7d3f10b117251c158f8d28b39f7fc73d0a7628b2d0b75bf8cfb1111576", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:finch, "~> 0.16", [hex: :finch, repo: "hexpm", optional: true]}, {:httpoison, "~> 1.0 or ~> 2.0", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.1", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "4e600568c02ed29d46bc2e2c74927d172ba06658aa8b14705c0207363c44cc94"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, - "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"}, - "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "hackney": {:hex, :hackney, "1.19.1", "59de4716e985dd2b5cbd4954fa1ae187e2b610a9c4520ffcb0b1653c3d6e5559", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "8aa08234bdefc269995c63c2282cf3cd0e36febe3a6bfab11b610572fdd1cad0"}, + "httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm", "fc3499fed7a726995aa659143a248534adc754ebd16ccd437cd93b649a95091f"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, @@ -26,7 +26,7 @@ "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mogrify": {:hex, :mogrify, "0.9.3", "238c782f00271dace01369ad35ae2e9dd020feee3443b9299ea5ea6bed559841", [:mix], [], "hexpm", "0189b1e1de27455f2b9ae8cf88239cefd23d38de9276eb5add7159aea51731e6"}, "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, - "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, + "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},